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_BOTTOM_COLOR_SET = 1 << 4;
|
||||||
private static final int BORDER_PATH_EFFECT_DIRTY = 1 << 5;
|
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 mBorderLeftWidth;
|
||||||
private float mBorderTopWidth;
|
private float mBorderTopWidth;
|
||||||
private float mBorderRightWidth;
|
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
|
* Quickly determine if all the set border colors are equal. Bitwise AND all the set colors
|
||||||
* colors differ)
|
* 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() {
|
private static int fastBorderCompatibleColorOrZero(
|
||||||
return isFlagSet(BORDER_TOP_COLOR_SET) ||
|
float borderLeft,
|
||||||
isFlagSet(BORDER_BOTTOM_COLOR_SET) ||
|
float borderTop,
|
||||||
isFlagSet(BORDER_LEFT_COLOR_SET) ||
|
float borderRight,
|
||||||
isFlagSet(BORDER_RIGHT_COLOR_SET);
|
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) {
|
private void drawRectangularBorders(Canvas canvas) {
|
||||||
|
@ -246,23 +269,63 @@ import com.facebook.react.uimanager.Spacing;
|
||||||
float rightInset = right - borderRight;
|
float rightInset = right - borderRight;
|
||||||
int rightColor = resolveBorderColor(BORDER_RIGHT_COLOR_SET, mBorderRightColor, defaultColor);
|
int rightColor = resolveBorderColor(BORDER_RIGHT_COLOR_SET, mBorderRightColor, defaultColor);
|
||||||
|
|
||||||
boolean isDrawPathRequired = isBorderColorDifferentAtIntersectionPoints();
|
// Check for fast path to border drawing.
|
||||||
if (isDrawPathRequired && mPathForBorder == null) {
|
int fastBorderColor = fastBorderCompatibleColorOrZero(
|
||||||
mPathForBorder = new Path();
|
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.
|
// Draw center.
|
||||||
if (Color.alpha(mBackgroundColor) != 0) {
|
if (Color.alpha(mBackgroundColor) != 0) {
|
||||||
PAINT.setColor(mBackgroundColor);
|
PAINT.setColor(mBackgroundColor);
|
||||||
canvas.drawRect(left, top, right, bottom, PAINT);
|
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.
|
PAINT.setColor(fastBorderColor);
|
||||||
if (borderTop != 0 && Color.alpha(topColor) != 0) {
|
if (borderLeft > 0) {
|
||||||
PAINT.setColor(topColor);
|
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(
|
updatePathForTopBorder(
|
||||||
|
mPathForBorder,
|
||||||
top,
|
top,
|
||||||
topInset,
|
topInset,
|
||||||
left,
|
left,
|
||||||
|
@ -270,17 +333,13 @@ import com.facebook.react.uimanager.Spacing;
|
||||||
right,
|
right,
|
||||||
rightInset);
|
rightInset);
|
||||||
canvas.drawPath(mPathForBorder, PAINT);
|
canvas.drawPath(mPathForBorder, PAINT);
|
||||||
} else {
|
|
||||||
canvas.drawRect(left, top, right, topInset, PAINT);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Draw bottom.
|
// Draw bottom.
|
||||||
if (borderBottom != 0 && Color.alpha(bottomColor) != 0) {
|
if (borderBottom != 0 && Color.alpha(bottomColor) != 0) {
|
||||||
PAINT.setColor(bottomColor);
|
PAINT.setColor(bottomColor);
|
||||||
|
|
||||||
if (isDrawPathRequired) {
|
|
||||||
updatePathForBottomBorder(
|
updatePathForBottomBorder(
|
||||||
|
mPathForBorder,
|
||||||
bottom,
|
bottom,
|
||||||
bottomInset,
|
bottomInset,
|
||||||
left,
|
left,
|
||||||
|
@ -288,17 +347,13 @@ import com.facebook.react.uimanager.Spacing;
|
||||||
right,
|
right,
|
||||||
rightInset);
|
rightInset);
|
||||||
canvas.drawPath(mPathForBorder, PAINT);
|
canvas.drawPath(mPathForBorder, PAINT);
|
||||||
} else {
|
|
||||||
canvas.drawRect(left, bottomInset, right, bottom, PAINT);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Draw left.
|
// Draw left.
|
||||||
if (borderLeft != 0 && Color.alpha(leftColor) != 0) {
|
if (borderLeft != 0 && Color.alpha(leftColor) != 0) {
|
||||||
PAINT.setColor(leftColor);
|
PAINT.setColor(leftColor);
|
||||||
|
|
||||||
if (isDrawPathRequired) {
|
|
||||||
updatePathForLeftBorder(
|
updatePathForLeftBorder(
|
||||||
|
mPathForBorder,
|
||||||
top,
|
top,
|
||||||
topInset,
|
topInset,
|
||||||
bottom,
|
bottom,
|
||||||
|
@ -306,17 +361,13 @@ import com.facebook.react.uimanager.Spacing;
|
||||||
left,
|
left,
|
||||||
leftInset);
|
leftInset);
|
||||||
canvas.drawPath(mPathForBorder, PAINT);
|
canvas.drawPath(mPathForBorder, PAINT);
|
||||||
} else {
|
|
||||||
canvas.drawRect(left, topInset, leftInset, bottomInset, PAINT);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Draw right.
|
// Draw right.
|
||||||
if (borderRight != 0 && Color.alpha(rightColor) != 0) {
|
if (borderRight != 0 && Color.alpha(rightColor) != 0) {
|
||||||
PAINT.setColor(rightColor);
|
PAINT.setColor(rightColor);
|
||||||
|
|
||||||
if (isDrawPathRequired) {
|
|
||||||
updatePathForRightBorder(
|
updatePathForRightBorder(
|
||||||
|
mPathForBorder,
|
||||||
top,
|
top,
|
||||||
topInset,
|
topInset,
|
||||||
bottom,
|
bottom,
|
||||||
|
@ -324,82 +375,72 @@ import com.facebook.react.uimanager.Spacing;
|
||||||
right,
|
right,
|
||||||
rightInset);
|
rightInset);
|
||||||
canvas.drawPath(mPathForBorder, PAINT);
|
canvas.drawPath(mPathForBorder, PAINT);
|
||||||
} else {
|
|
||||||
canvas.drawRect(rightInset, topInset, right, bottomInset, PAINT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePathForTopBorder(
|
private static void updatePathForTopBorder(
|
||||||
|
Path path,
|
||||||
float top,
|
float top,
|
||||||
float topInset,
|
float topInset,
|
||||||
float left,
|
float left,
|
||||||
float leftInset,
|
float leftInset,
|
||||||
float right,
|
float right,
|
||||||
float rightInset) {
|
float rightInset) {
|
||||||
if (mPathForBorder == null) {
|
path.reset();
|
||||||
mPathForBorder = new Path();
|
path.moveTo(left, top);
|
||||||
}
|
path.lineTo(leftInset, topInset);
|
||||||
mPathForBorder.reset();
|
path.lineTo(rightInset, topInset);
|
||||||
mPathForBorder.moveTo(left, top);
|
path.lineTo(right, top);
|
||||||
mPathForBorder.lineTo(leftInset, topInset);
|
path.lineTo(left, top);
|
||||||
mPathForBorder.lineTo(rightInset, topInset);
|
|
||||||
mPathForBorder.lineTo(right, top);
|
|
||||||
mPathForBorder.lineTo(left, top);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePathForBottomBorder(
|
private static void updatePathForBottomBorder(
|
||||||
|
Path path,
|
||||||
float bottom,
|
float bottom,
|
||||||
float bottomInset,
|
float bottomInset,
|
||||||
float left,
|
float left,
|
||||||
float leftInset,
|
float leftInset,
|
||||||
float right,
|
float right,
|
||||||
float rightInset) {
|
float rightInset) {
|
||||||
if (mPathForBorder == null) {
|
path.reset();
|
||||||
mPathForBorder = new Path();
|
path.moveTo(left, bottom);
|
||||||
}
|
path.lineTo(right, bottom);
|
||||||
mPathForBorder.reset();
|
path.lineTo(rightInset, bottomInset);
|
||||||
mPathForBorder.moveTo(left, bottom);
|
path.lineTo(leftInset, bottomInset);
|
||||||
mPathForBorder.lineTo(right, bottom);
|
path.lineTo(left, bottom);
|
||||||
mPathForBorder.lineTo(rightInset, bottomInset);
|
|
||||||
mPathForBorder.lineTo(leftInset, bottomInset);
|
|
||||||
mPathForBorder.lineTo(left, bottom);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePathForLeftBorder(
|
private static void updatePathForLeftBorder(
|
||||||
|
Path path,
|
||||||
float top,
|
float top,
|
||||||
float topInset,
|
float topInset,
|
||||||
float bottom,
|
float bottom,
|
||||||
float bottomInset,
|
float bottomInset,
|
||||||
float left,
|
float left,
|
||||||
float leftInset) {
|
float leftInset) {
|
||||||
if (mPathForBorder == null) {
|
path.reset();
|
||||||
mPathForBorder = new Path();
|
path.moveTo(left, top);
|
||||||
}
|
path.lineTo(leftInset, topInset);
|
||||||
mPathForBorder.reset();
|
path.lineTo(leftInset, bottomInset);
|
||||||
mPathForBorder.moveTo(left, top);
|
path.lineTo(left, bottom);
|
||||||
mPathForBorder.lineTo(leftInset, topInset);
|
path.lineTo(left, top);
|
||||||
mPathForBorder.lineTo(leftInset, bottomInset);
|
|
||||||
mPathForBorder.lineTo(left, bottom);
|
|
||||||
mPathForBorder.lineTo(left, top);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePathForRightBorder(
|
private static void updatePathForRightBorder(
|
||||||
|
Path path,
|
||||||
float top,
|
float top,
|
||||||
float topInset,
|
float topInset,
|
||||||
float bottom,
|
float bottom,
|
||||||
float bottomInset,
|
float bottomInset,
|
||||||
float right,
|
float right,
|
||||||
float rightInset) {
|
float rightInset) {
|
||||||
if (mPathForBorder == null) {
|
path.reset();
|
||||||
mPathForBorder = new Path();
|
path.moveTo(right, top);
|
||||||
}
|
path.lineTo(right, bottom);
|
||||||
mPathForBorder.reset();
|
path.lineTo(rightInset, bottomInset);
|
||||||
mPathForBorder.moveTo(right, top);
|
path.lineTo(rightInset, topInset);
|
||||||
mPathForBorder.lineTo(right, bottom);
|
path.lineTo(right, top);
|
||||||
mPathForBorder.lineTo(rightInset, bottomInset);
|
|
||||||
mPathForBorder.lineTo(rightInset, topInset);
|
|
||||||
mPathForBorder.lineTo(right, top);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int resolveBorderColor(int flag, int color, int defaultColor) {
|
private int resolveBorderColor(int flag, int color, int defaultColor) {
|
||||||
|
|
Loading…
Reference in New Issue