Refactor DrawView to avoid extra allocates.

Summary: Previously, the first time we collected a draw view, we would make a clone, even though the draw view had never been mutated.  This refactors draw view to avoid this extra allocate.

Reviewed By: ahmedre

Differential Revision: D3719056
This commit is contained in:
Seth Kirby 2016-08-15 18:56:36 -07:00 коммит произвёл Ahmed El-Helw
Родитель cc216b5ec3
Коммит b2f41e2921
3 изменённых файлов: 70 добавлений и 42 удалений

Просмотреть файл

@ -42,7 +42,7 @@ import android.graphics.Color;
&& mClipRight == clipRight && mClipBottom == clipBottom; && mClipRight == clipRight && mClipBottom == clipBottom;
} }
public final void setClipBounds( protected final void setClipBounds(
float clipLeft, float clipLeft,
float clipTop, float clipTop,
float clipRight, float clipRight,
@ -185,6 +185,13 @@ import android.graphics.Color;
return mFrozen; return mFrozen;
} }
/**
* Mark this object as frozen, indicating that it should not be mutated.
*/
public final void freeze() {
mFrozen = true;
}
/** /**
* Left position of this DrawCommand relative to the hosting View. * Left position of this DrawCommand relative to the hosting View.
*/ */
@ -226,7 +233,7 @@ import android.graphics.Color;
/** /**
* Updates boundaries of this DrawCommand. * Updates boundaries of this DrawCommand.
*/ */
private void setBounds(float left, float top, float right, float bottom) { protected final void setBounds(float left, float top, float right, float bottom) {
mLeft = left; mLeft = left;
mTop = top; mTop = top;
mRight = right; mRight = right;
@ -238,7 +245,7 @@ import android.graphics.Color;
/** /**
* Returns true if boundaries match and don't need to be updated. False otherwise. * Returns true if boundaries match and don't need to be updated. False otherwise.
*/ */
private boolean boundsMatch(float left, float top, float right, float bottom) { protected final boolean boundsMatch(float left, float top, float right, float bottom) {
return mLeft == left && mTop == top && mRight == right && mBottom == bottom; return mLeft == left && mTop == top && mRight == right && mBottom == bottom;
} }
} }

Просмотреть файл

@ -72,48 +72,53 @@ import android.graphics.RectF;
float clipRight, float clipRight,
float clipBottom, float clipBottom,
float clipRadius) { float clipRadius) {
DrawView drawView = (DrawView) if (!isFrozen()) {
updateBoundsAndFreeze( // We haven't collected this draw view yet, so we can just set everything.
left, setBounds(left, top, right, bottom);
top, setClipBounds(clipLeft, clipTop, clipRight, clipBottom);
right, setClipRadius(clipRadius);
bottom, setLogicalBounds(logicalLeft, logicalTop, logicalRight, logicalBottom);
clipLeft, freeze();
clipTop, return this;
clipRight,
clipBottom);
boolean clipRadiusChanged = Math.abs(mClipRadius - clipRadius) > 0.001f;
boolean logicalBoundsChanged =
!logicalBoundsMatch(logicalLeft, logicalTop, logicalRight, logicalBottom);
if (drawView == this && (clipRadiusChanged || logicalBoundsChanged)) {
// everything matches except the clip radius, so we clone the old one so that we can update
// the clip radius in the block below.
try {
drawView = (DrawView) clone();
} catch (CloneNotSupportedException e) {
// This should not happen since AbstractDrawCommand implements Cloneable
throw new RuntimeException(e);
}
} }
if (drawView != this) { boolean boundsMatch = boundsMatch(left, top, right, bottom);
drawView.mClipRadius = clipRadius; boolean clipBoundsMatch = clipBoundsMatch(clipLeft, clipTop, clipRight, clipBottom);
if (clipRadius > MINIMUM_ROUNDED_CLIPPING_VALUE) { boolean clipRadiusMatch = mClipRadius == clipRadius;
// update the path that we'll clip based on boolean logicalBoundsMatch =
drawView.updateClipPath(); logicalBoundsMatch(logicalLeft, logicalTop, logicalRight, logicalBottom);
} else {
drawView.mPath = null;
}
if (logicalBoundsChanged) { // See if we can reuse the draw view.
drawView.setLogicalBounds(logicalLeft, logicalTop, logicalRight, logicalBottom); if (boundsMatch && clipBoundsMatch && clipRadiusMatch && logicalBoundsMatch) {
} return this;
// It is very important that we unset this, as our spec is that newly created DrawViews are
// handled differently by the FlatViewGroup. This is needed because updateBoundsAndFreeze
// uses .clone(), so we maintain the previous state.
drawView.mWasMounted = false;
} }
DrawView drawView = (DrawView) mutableCopy();
if (!boundsMatch) {
drawView.setBounds(left, top, right, bottom);
}
if (!clipBoundsMatch) {
drawView.setClipBounds(clipLeft, clipTop, clipRight, clipBottom);
}
if (!logicalBoundsMatch) {
drawView.setLogicalBounds(logicalLeft, logicalTop, logicalRight, logicalBottom);
}
if (!clipRadiusMatch || !boundsMatch) {
// If the bounds change, we need to update the clip path.
drawView.setClipRadius(clipRadius);
}
// It is very important that we unset this, as our spec is that newly created DrawViews
// are handled differently by the FlatViewGroup. This is needed because clone() maintains
// the previous state.
drawView.mWasMounted = false;
drawView.freeze();
return drawView; return drawView;
} }
@ -143,6 +148,22 @@ import android.graphics.RectF;
} }
} }
/**
* Set the clip radius. Should only be called when the clip radius is first set or when it
* changes, in order to avoid extra work.
*
* @param clipRadius The new clip radius.
*/
void setClipRadius(float clipRadius) {
mClipRadius = clipRadius;
if (clipRadius > MINIMUM_ROUNDED_CLIPPING_VALUE) {
// update the path that we'll clip based on
updateClipPath();
} else {
mPath = null;
}
}
/** /**
* Update the path with which we'll clip this view * Update the path with which we'll clip this view
*/ */

Просмотреть файл

@ -503,7 +503,7 @@ import com.facebook.react.views.view.ReactClippingViewGroupHelper;
float clipRight, float clipRight,
float clipBottom) { float clipBottom) {
Assertions.assumeNotNull(mDrawView); Assertions.assumeNotNull(mDrawView);
if (mDrawView.reactTag == 0) { if (mDrawView == EMPTY_DRAW_VIEW) {
// This is the first time we have collected this DrawView, but we have to create a new // This is the first time we have collected this DrawView, but we have to create a new
// DrawView anyway, as reactTag is final, and our DrawView instance is the static copy. // DrawView anyway, as reactTag is final, and our DrawView instance is the static copy.
mDrawView = new DrawView(getReactTag()); mDrawView = new DrawView(getReactTag());