mirror of
https://github.com/status-im/react-native.git
synced 2025-02-27 00:20:31 +00:00
Fix border-rendering in APIs < 18
Summary: `Canvas.clipPath` isn't supported with hardware acceleration in APIs below 18. The rounded border rendering logic for Android relies on this method. Therefore, rounded borders do not render correctly on such devices. **Screenshot of Nexus 5 running API 17 (Before these changes):** https://pxl.cl/9rsf **The fix**: If the API version is less than 18 and we're rendering rounded borders, I disable hardware acceleration. Otherwise, I enable it. I'm going to check to see if this has perf regressions by running a CT-Scan. With this change, rounded borders render correctly on Android devices running versions of Android between Honeycomb to JellyBean MR2. **Screenshot of Nexus 5 running API 17 (After these changes):** https://pxl.cl/9rrk Reviewed By: xiphirx Differential Revision: D6153087 fbshipit-source-id: 16e35be096051ac817c8b8bcdd132ecff3b4b167
This commit is contained in:
parent
60828566a7
commit
5aa1fb3ff3
@ -129,16 +129,29 @@ public class ReactViewBackgroundDrawable extends Drawable {
|
|||||||
@Override
|
@Override
|
||||||
public void draw(Canvas canvas) {
|
public void draw(Canvas canvas) {
|
||||||
updatePathEffect();
|
updatePathEffect();
|
||||||
boolean roundedBorders = mBorderCornerRadii != null ||
|
if (!hasRoundedBorders()) {
|
||||||
(!YogaConstants.isUndefined(mBorderRadius) && mBorderRadius > 0);
|
|
||||||
|
|
||||||
if (!roundedBorders) {
|
|
||||||
drawRectangularBackgroundWithBorders(canvas);
|
drawRectangularBackgroundWithBorders(canvas);
|
||||||
} else {
|
} else {
|
||||||
drawRoundedBackgroundWithBorders(canvas);
|
drawRoundedBackgroundWithBorders(canvas);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasRoundedBorders() {
|
||||||
|
if (!YogaConstants.isUndefined(mBorderRadius) && mBorderRadius > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBorderCornerRadii != null) {
|
||||||
|
for (final float borderRadii : mBorderCornerRadii) {
|
||||||
|
if (!YogaConstants.isUndefined(borderRadii) && borderRadii > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onBoundsChange(Rect bounds) {
|
protected void onBoundsChange(Rect bounds) {
|
||||||
super.onBoundsChange(bounds);
|
super.onBoundsChange(bounds);
|
||||||
@ -620,23 +633,29 @@ public class ReactViewBackgroundDrawable extends Drawable {
|
|||||||
* border of V will render inside O.
|
* border of V will render inside O.
|
||||||
*
|
*
|
||||||
* <p>Let BorderWidth = (borderTop, borderLeft, borderBottom, borderRight).
|
* <p>Let BorderWidth = (borderTop, borderLeft, borderBottom, borderRight).
|
||||||
|
*
|
||||||
* <p>Let I (for inner) = O - BorderWidth.
|
* <p>Let I (for inner) = O - BorderWidth.
|
||||||
*
|
*
|
||||||
* <p>Then, remembering that O and I are rectangles and that I is inside O, O - I gives us the
|
* <p>Then, remembering that O and I are rectangles and that I is inside O, O - I gives us the
|
||||||
* border of V. Therefore, we can use canvas.clipPath to draw V's border.
|
* border of V. Therefore, we can use canvas.clipPath to draw V's border.
|
||||||
*
|
*
|
||||||
* <p>canvas.clipPath(O, Region.OP.INTERSECT);
|
* <p>canvas.clipPath(O, Region.OP.INTERSECT);
|
||||||
|
*
|
||||||
* <p>canvas.clipPath(I, Region.OP.DIFFERENCE);
|
* <p>canvas.clipPath(I, Region.OP.DIFFERENCE);
|
||||||
|
*
|
||||||
* <p>canvas.drawRect(O, paint);
|
* <p>canvas.drawRect(O, paint);
|
||||||
*
|
*
|
||||||
* <p>This lets us draw non-rounded single-color borders.
|
* <p>This lets us draw non-rounded single-color borders.
|
||||||
*
|
*
|
||||||
* <p>To extend this algorithm to rounded single-color borders, we:
|
* <p>To extend this algorithm to rounded single-color borders, we:
|
||||||
|
*
|
||||||
* <p>1. Curve the corners of O by the (border radii of V) using Path#addRoundRect.
|
* <p>1. Curve the corners of O by the (border radii of V) using Path#addRoundRect.
|
||||||
|
*
|
||||||
* <p>2. Curve the corners of I by (border radii of V - border widths of V) using
|
* <p>2. Curve the corners of I by (border radii of V - border widths of V) using
|
||||||
* Path#addRoundRect.
|
* Path#addRoundRect.
|
||||||
*
|
*
|
||||||
* <p>Let O' = curve(O, border radii of V).
|
* <p>Let O' = curve(O, border radii of V).
|
||||||
|
*
|
||||||
* <p>Let I' = curve(I, border radii of V - border widths of V)
|
* <p>Let I' = curve(I, border radii of V - border widths of V)
|
||||||
*
|
*
|
||||||
* <p>The rationale behind this decision is the (first sentence of the) following section in the
|
* <p>The rationale behind this decision is the (first sentence of the) following section in the
|
||||||
@ -647,7 +666,9 @@ public class ReactViewBackgroundDrawable extends Drawable {
|
|||||||
* render curved single-color borders:
|
* render curved single-color borders:
|
||||||
*
|
*
|
||||||
* <p>canvas.clipPath(O, Region.OP.INTERSECT);
|
* <p>canvas.clipPath(O, Region.OP.INTERSECT);
|
||||||
|
*
|
||||||
* <p>canvas.clipPath(I, Region.OP.DIFFERENCE);
|
* <p>canvas.clipPath(I, Region.OP.DIFFERENCE);
|
||||||
|
*
|
||||||
* <p>canvas.drawRect(O, paint);
|
* <p>canvas.drawRect(O, paint);
|
||||||
*
|
*
|
||||||
* <p>To extend this algorithm to rendering multi-colored rounded borders, we render each side
|
* <p>To extend this algorithm to rendering multi-colored rounded borders, we render each side
|
||||||
@ -655,8 +676,11 @@ public class ReactViewBackgroundDrawable extends Drawable {
|
|||||||
* border radii are 0. Then, the four quadrilaterals would be:
|
* border radii are 0. Then, the four quadrilaterals would be:
|
||||||
*
|
*
|
||||||
* <p>Left: (O.left, O.top), (I.left, I.top), (I.left, I.bottom), (O.left, O.bottom)
|
* <p>Left: (O.left, O.top), (I.left, I.top), (I.left, I.bottom), (O.left, O.bottom)
|
||||||
|
*
|
||||||
* <p>Top: (O.left, O.top), (I.left, I.top), (I.right, I.top), (O.right, O.top)
|
* <p>Top: (O.left, O.top), (I.left, I.top), (I.right, I.top), (O.right, O.top)
|
||||||
|
*
|
||||||
* <p>Right: (O.right, O.top), (I.right, I.top), (I.right, I.bottom), (O.right, O.bottom)
|
* <p>Right: (O.right, O.top), (I.right, I.top), (I.right, I.bottom), (O.right, O.bottom)
|
||||||
|
*
|
||||||
* <p>Bottom: (O.right, O.bottom), (I.right, I.bottom), (I.left, I.bottom), (O.left, O.bottom)
|
* <p>Bottom: (O.right, O.bottom), (I.right, I.bottom), (I.left, I.bottom), (O.left, O.bottom)
|
||||||
*
|
*
|
||||||
* <p>Now, lets consider what happens when we render a rounded border (radii != 0). For the sake
|
* <p>Now, lets consider what happens when we render a rounded border (radii != 0). For the sake
|
||||||
|
@ -233,7 +233,20 @@ public class ReactViewGroup extends ViewGroup implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setBorderRadius(float borderRadius, int position) {
|
public void setBorderRadius(float borderRadius, int position) {
|
||||||
getOrCreateReactViewBackground().setRadius(borderRadius, position);
|
ReactViewBackgroundDrawable backgroundDrawable = getOrCreateReactViewBackground();
|
||||||
|
backgroundDrawable.setRadius(borderRadius, position);
|
||||||
|
|
||||||
|
if (Build.VERSION_CODES.HONEYCOMB < Build.VERSION.SDK_INT
|
||||||
|
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||||
|
final int UPDATED_LAYER_TYPE =
|
||||||
|
backgroundDrawable.hasRoundedBorders()
|
||||||
|
? View.LAYER_TYPE_SOFTWARE
|
||||||
|
: View.LAYER_TYPE_HARDWARE;
|
||||||
|
|
||||||
|
if (UPDATED_LAYER_TYPE != getLayerType()) {
|
||||||
|
setLayerType(UPDATED_LAYER_TYPE, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBorderStyle(@Nullable String style) {
|
public void setBorderStyle(@Nullable String style) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user