Avoid using path for normal border cases
Reviewed By: ahmedre Differential Revision: D5111224 fbshipit-source-id: c188f83339ed011272f80b4fac35f47f8d72d30b
This commit is contained in:
parent
2143df8cb6
commit
5db26380dd
|
@ -34,6 +34,11 @@ import com.facebook.react.uimanager.Spacing;
|
|||
private static final int BORDER_BOTTOM_COLOR_SET = 1 << 4;
|
||||
private static final int BORDER_PATH_EFFECT_DIRTY = 1 << 5;
|
||||
|
||||
// ~0 == 0xFFFFFFFF, all bits set to 1.
|
||||
private static final int ALL_BITS_SET = ~0;
|
||||
// 0 == 0x00000000, all bits set to 0.
|
||||
private static final int ALL_BITS_UNSET = 0;
|
||||
|
||||
private float mBorderLeftWidth;
|
||||
private float mBorderTopWidth;
|
||||
private float mBorderRightWidth;
|
||||
|
@ -212,14 +217,32 @@ import com.facebook.react.uimanager.Spacing;
|
|||
}
|
||||
|
||||
/**
|
||||
* @return true when border colors differs where two border sides meet (e.g. right and top border
|
||||
* colors differ)
|
||||
* Quickly determine if all the set border colors are equal. Bitwise AND all the set colors
|
||||
* together, then OR them all together. If the AND and the OR are the same, then the colors
|
||||
* are compatible, so return this color.
|
||||
*
|
||||
* Used to avoid expensive path creation and expensive calls to canvas.drawPath
|
||||
*
|
||||
* @return A compatible border color, or zero if the border colors are not compatible.
|
||||
*/
|
||||
private boolean isBorderColorDifferentAtIntersectionPoints() {
|
||||
return isFlagSet(BORDER_TOP_COLOR_SET) ||
|
||||
isFlagSet(BORDER_BOTTOM_COLOR_SET) ||
|
||||
isFlagSet(BORDER_LEFT_COLOR_SET) ||
|
||||
isFlagSet(BORDER_RIGHT_COLOR_SET);
|
||||
private static int fastBorderCompatibleColorOrZero(
|
||||
float borderLeft,
|
||||
float borderTop,
|
||||
float borderRight,
|
||||
float borderBottom,
|
||||
int colorLeft,
|
||||
int colorTop,
|
||||
int colorRight,
|
||||
int colorBottom) {
|
||||
int andSmear = (borderLeft > 0 ? colorLeft : ALL_BITS_SET) &
|
||||
(borderTop > 0 ? colorTop : ALL_BITS_SET) &
|
||||
(borderRight > 0 ? colorRight : ALL_BITS_SET) &
|
||||
(borderBottom > 0 ? colorBottom : ALL_BITS_SET);
|
||||
int orSmear = (borderLeft > 0 ? colorLeft : ALL_BITS_UNSET) |
|
||||
(borderTop > 0 ? colorTop : ALL_BITS_UNSET) |
|
||||
(borderRight > 0 ? colorRight : ALL_BITS_UNSET) |
|
||||
(borderBottom > 0 ? colorBottom : ALL_BITS_UNSET);
|
||||
return andSmear == orSmear ? andSmear : 0;
|
||||
}
|
||||
|
||||
private void drawRectangularBorders(Canvas canvas) {
|
||||
|
@ -246,23 +269,63 @@ import com.facebook.react.uimanager.Spacing;
|
|||
float rightInset = right - borderRight;
|
||||
int rightColor = resolveBorderColor(BORDER_RIGHT_COLOR_SET, mBorderRightColor, defaultColor);
|
||||
|
||||
boolean isDrawPathRequired = isBorderColorDifferentAtIntersectionPoints();
|
||||
if (isDrawPathRequired && mPathForBorder == null) {
|
||||
mPathForBorder = new Path();
|
||||
}
|
||||
// Check for fast path to border drawing.
|
||||
int fastBorderColor = fastBorderCompatibleColorOrZero(
|
||||
borderLeft,
|
||||
borderTop,
|
||||
borderRight,
|
||||
borderBottom,
|
||||
leftColor,
|
||||
topColor,
|
||||
rightColor,
|
||||
bottomColor);
|
||||
if (fastBorderColor != 0) {
|
||||
// Fast border color draw.
|
||||
if (Color.alpha(fastBorderColor) != 0) {
|
||||
// Border color is not transparent.
|
||||
|
||||
// Draw center. The border might be opaque, so we need to draw this.
|
||||
if (Color.alpha(mBackgroundColor) != 0) {
|
||||
PAINT.setColor(mBackgroundColor);
|
||||
canvas.drawRect(left, top, right, bottom, PAINT);
|
||||
}
|
||||
// Draw center.
|
||||
if (Color.alpha(mBackgroundColor) != 0) {
|
||||
PAINT.setColor(mBackgroundColor);
|
||||
if (Color.alpha(fastBorderColor) == 255) {
|
||||
// The border will draw over the edges, so only draw the inset background.
|
||||
canvas.drawRect(leftInset, topInset, rightInset, bottomInset, PAINT);
|
||||
} else {
|
||||
// The border is opaque, so we have to draw the entire background color.
|
||||
canvas.drawRect(left, top, right, bottom, PAINT);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw top.
|
||||
if (borderTop != 0 && Color.alpha(topColor) != 0) {
|
||||
PAINT.setColor(topColor);
|
||||
PAINT.setColor(fastBorderColor);
|
||||
if (borderLeft > 0) {
|
||||
canvas.drawRect(left, top, leftInset, bottom - borderBottom, PAINT);
|
||||
}
|
||||
if (borderTop > 0) {
|
||||
canvas.drawRect(left + borderLeft, top, right, topInset, PAINT);
|
||||
}
|
||||
if (borderRight > 0) {
|
||||
canvas.drawRect(rightInset, top + borderTop, right, bottom, PAINT);
|
||||
}
|
||||
if (borderBottom > 0) {
|
||||
canvas.drawRect(left, bottomInset, right - borderRight, bottom, PAINT);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (mPathForBorder == null) {
|
||||
mPathForBorder = new Path();
|
||||
}
|
||||
|
||||
if (isDrawPathRequired) {
|
||||
// Draw center. Any of the borders might be opaque or transparent, so we need to draw this.
|
||||
if (Color.alpha(mBackgroundColor) != 0) {
|
||||
PAINT.setColor(mBackgroundColor);
|
||||
canvas.drawRect(left, top, right, bottom, PAINT);
|
||||
}
|
||||
|
||||
// Draw top.
|
||||
if (borderTop != 0 && Color.alpha(topColor) != 0) {
|
||||
PAINT.setColor(topColor);
|
||||
updatePathForTopBorder(
|
||||
mPathForBorder,
|
||||
top,
|
||||
topInset,
|
||||
left,
|
||||
|
@ -270,17 +333,13 @@ import com.facebook.react.uimanager.Spacing;
|
|||
right,
|
||||
rightInset);
|
||||
canvas.drawPath(mPathForBorder, PAINT);
|
||||
} else {
|
||||
canvas.drawRect(left, top, right, topInset, PAINT);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw bottom.
|
||||
if (borderBottom != 0 && Color.alpha(bottomColor) != 0) {
|
||||
PAINT.setColor(bottomColor);
|
||||
|
||||
if (isDrawPathRequired) {
|
||||
// Draw bottom.
|
||||
if (borderBottom != 0 && Color.alpha(bottomColor) != 0) {
|
||||
PAINT.setColor(bottomColor);
|
||||
updatePathForBottomBorder(
|
||||
mPathForBorder,
|
||||
bottom,
|
||||
bottomInset,
|
||||
left,
|
||||
|
@ -288,17 +347,13 @@ import com.facebook.react.uimanager.Spacing;
|
|||
right,
|
||||
rightInset);
|
||||
canvas.drawPath(mPathForBorder, PAINT);
|
||||
} else {
|
||||
canvas.drawRect(left, bottomInset, right, bottom, PAINT);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw left.
|
||||
if (borderLeft != 0 && Color.alpha(leftColor) != 0) {
|
||||
PAINT.setColor(leftColor);
|
||||
|
||||
if (isDrawPathRequired) {
|
||||
// Draw left.
|
||||
if (borderLeft != 0 && Color.alpha(leftColor) != 0) {
|
||||
PAINT.setColor(leftColor);
|
||||
updatePathForLeftBorder(
|
||||
mPathForBorder,
|
||||
top,
|
||||
topInset,
|
||||
bottom,
|
||||
|
@ -306,17 +361,13 @@ import com.facebook.react.uimanager.Spacing;
|
|||
left,
|
||||
leftInset);
|
||||
canvas.drawPath(mPathForBorder, PAINT);
|
||||
} else {
|
||||
canvas.drawRect(left, topInset, leftInset, bottomInset, PAINT);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw right.
|
||||
if (borderRight != 0 && Color.alpha(rightColor) != 0) {
|
||||
PAINT.setColor(rightColor);
|
||||
|
||||
if (isDrawPathRequired) {
|
||||
// Draw right.
|
||||
if (borderRight != 0 && Color.alpha(rightColor) != 0) {
|
||||
PAINT.setColor(rightColor);
|
||||
updatePathForRightBorder(
|
||||
mPathForBorder,
|
||||
top,
|
||||
topInset,
|
||||
bottom,
|
||||
|
@ -324,82 +375,72 @@ import com.facebook.react.uimanager.Spacing;
|
|||
right,
|
||||
rightInset);
|
||||
canvas.drawPath(mPathForBorder, PAINT);
|
||||
} else {
|
||||
canvas.drawRect(rightInset, topInset, right, bottomInset, PAINT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePathForTopBorder(
|
||||
private static void updatePathForTopBorder(
|
||||
Path path,
|
||||
float top,
|
||||
float topInset,
|
||||
float left,
|
||||
float leftInset,
|
||||
float right,
|
||||
float rightInset) {
|
||||
if (mPathForBorder == null) {
|
||||
mPathForBorder = new Path();
|
||||
}
|
||||
mPathForBorder.reset();
|
||||
mPathForBorder.moveTo(left, top);
|
||||
mPathForBorder.lineTo(leftInset, topInset);
|
||||
mPathForBorder.lineTo(rightInset, topInset);
|
||||
mPathForBorder.lineTo(right, top);
|
||||
mPathForBorder.lineTo(left, top);
|
||||
path.reset();
|
||||
path.moveTo(left, top);
|
||||
path.lineTo(leftInset, topInset);
|
||||
path.lineTo(rightInset, topInset);
|
||||
path.lineTo(right, top);
|
||||
path.lineTo(left, top);
|
||||
}
|
||||
|
||||
private void updatePathForBottomBorder(
|
||||
private static void updatePathForBottomBorder(
|
||||
Path path,
|
||||
float bottom,
|
||||
float bottomInset,
|
||||
float left,
|
||||
float leftInset,
|
||||
float right,
|
||||
float rightInset) {
|
||||
if (mPathForBorder == null) {
|
||||
mPathForBorder = new Path();
|
||||
}
|
||||
mPathForBorder.reset();
|
||||
mPathForBorder.moveTo(left, bottom);
|
||||
mPathForBorder.lineTo(right, bottom);
|
||||
mPathForBorder.lineTo(rightInset, bottomInset);
|
||||
mPathForBorder.lineTo(leftInset, bottomInset);
|
||||
mPathForBorder.lineTo(left, bottom);
|
||||
path.reset();
|
||||
path.moveTo(left, bottom);
|
||||
path.lineTo(right, bottom);
|
||||
path.lineTo(rightInset, bottomInset);
|
||||
path.lineTo(leftInset, bottomInset);
|
||||
path.lineTo(left, bottom);
|
||||
}
|
||||
|
||||
private void updatePathForLeftBorder(
|
||||
private static void updatePathForLeftBorder(
|
||||
Path path,
|
||||
float top,
|
||||
float topInset,
|
||||
float bottom,
|
||||
float bottomInset,
|
||||
float left,
|
||||
float leftInset) {
|
||||
if (mPathForBorder == null) {
|
||||
mPathForBorder = new Path();
|
||||
}
|
||||
mPathForBorder.reset();
|
||||
mPathForBorder.moveTo(left, top);
|
||||
mPathForBorder.lineTo(leftInset, topInset);
|
||||
mPathForBorder.lineTo(leftInset, bottomInset);
|
||||
mPathForBorder.lineTo(left, bottom);
|
||||
mPathForBorder.lineTo(left, top);
|
||||
path.reset();
|
||||
path.moveTo(left, top);
|
||||
path.lineTo(leftInset, topInset);
|
||||
path.lineTo(leftInset, bottomInset);
|
||||
path.lineTo(left, bottom);
|
||||
path.lineTo(left, top);
|
||||
}
|
||||
|
||||
private void updatePathForRightBorder(
|
||||
private static void updatePathForRightBorder(
|
||||
Path path,
|
||||
float top,
|
||||
float topInset,
|
||||
float bottom,
|
||||
float bottomInset,
|
||||
float right,
|
||||
float rightInset) {
|
||||
if (mPathForBorder == null) {
|
||||
mPathForBorder = new Path();
|
||||
}
|
||||
mPathForBorder.reset();
|
||||
mPathForBorder.moveTo(right, top);
|
||||
mPathForBorder.lineTo(right, bottom);
|
||||
mPathForBorder.lineTo(rightInset, bottomInset);
|
||||
mPathForBorder.lineTo(rightInset, topInset);
|
||||
mPathForBorder.lineTo(right, top);
|
||||
path.reset();
|
||||
path.moveTo(right, top);
|
||||
path.lineTo(right, bottom);
|
||||
path.lineTo(rightInset, bottomInset);
|
||||
path.lineTo(rightInset, topInset);
|
||||
path.lineTo(right, top);
|
||||
}
|
||||
|
||||
private int resolveBorderColor(int flag, int color, int defaultColor) {
|
||||
|
|
Loading…
Reference in New Issue