diff --git a/Libraries/ART/ARTGroup.h b/Libraries/ART/ARTGroup.h index 15a8b643b..4d94a9acd 100644 --- a/Libraries/ART/ARTGroup.h +++ b/Libraries/ART/ARTGroup.h @@ -14,4 +14,6 @@ @interface ARTGroup : ARTNode +@property (nonatomic, assign) CGRect clipping; + @end diff --git a/Libraries/ART/ARTGroup.m b/Libraries/ART/ARTGroup.m index 9ecbf8ee8..672c3b6eb 100644 --- a/Libraries/ART/ARTGroup.m +++ b/Libraries/ART/ARTGroup.m @@ -13,7 +13,10 @@ - (void)renderLayerTo:(CGContextRef)context { -// TO-DO: Clipping rectangle + + if (!CGRectIsEmpty(self.clipping)) { + CGContextClipToRect(context, self.clipping); + } for (ARTNode *node in self.subviews) { [node renderTo:context]; diff --git a/Libraries/ART/ReactNativeART.js b/Libraries/ART/ReactNativeART.js index 9bf9bc0b6..1182276f7 100644 --- a/Libraries/ART/ReactNativeART.js +++ b/Libraries/ART/ReactNativeART.js @@ -227,13 +227,7 @@ var ClippingRectangle = React.createClass({ var y = extractNumber(props.y, 0); var w = extractNumber(props.width, 0); var h = extractNumber(props.height, 0); - var clipping = new Path() - .moveTo(x, y) - .line(w, 0) - .line(0, h) - .line(w, 0) - .close() - .toJSON(); + var clipping = [x, y, w, h]; // The current clipping API requires x and y to be ignored in the transform var propsExcludingXAndY = merge(props); delete propsExcludingXAndY.x; diff --git a/Libraries/ART/ViewManagers/ARTGroupManager.m b/Libraries/ART/ViewManagers/ARTGroupManager.m index b958d11f9..8b2776415 100644 --- a/Libraries/ART/ViewManagers/ARTGroupManager.m +++ b/Libraries/ART/ViewManagers/ARTGroupManager.m @@ -10,6 +10,7 @@ #import "ARTGroupManager.h" #import "ARTGroup.h" +#import "RCTConvert+ART.h" @implementation ARTGroupManager @@ -20,4 +21,6 @@ RCT_EXPORT_MODULE() return [ARTGroup new]; } +RCT_EXPORT_VIEW_PROPERTY(clipping, CGRect) + @end diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java index f01ca1ccf..2f83aeeb3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTGroupShadowNode.java @@ -9,14 +9,33 @@ package com.facebook.react.views.art; +import javax.annotation.Nullable; + import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.Region; + +import com.facebook.react.bridge.JSApplicationIllegalArgumentException; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.uimanager.annotations.ReactProp; /** * Shadow node for virtual ARTGroup view */ public class ARTGroupShadowNode extends ARTVirtualNode { + protected @Nullable RectF mClipping; + + @ReactProp(name = "clipping") + public void setClipping(@Nullable ReadableArray clippingDims) { + float[] clippingData = PropHelper.toFloatArray(clippingDims); + if (clippingData != null) { + mClipping = createClipping(clippingData); + markUpdated(); + } + } + @Override public boolean isVirtual() { return true; @@ -26,7 +45,16 @@ public class ARTGroupShadowNode extends ARTVirtualNode { opacity *= mOpacity; if (opacity > MIN_OPACITY_FOR_DRAW) { saveAndSetupCanvas(canvas); - // TODO(6352006): apply clipping (iOS doesn't do it yet, it seems to cause issues) + + if (mClipping != null) { + canvas.clipRect( + mClipping.left * mScale, + mClipping.top * mScale, + mClipping.right * mScale, + mClipping.bottom * mScale, + Region.Op.REPLACE); + } + for (int i = 0; i < getChildCount(); i++) { ARTVirtualNode child = (ARTVirtualNode) getChildAt(i); child.draw(canvas, paint, opacity); @@ -36,4 +64,21 @@ public class ARTGroupShadowNode extends ARTVirtualNode { restoreCanvas(canvas); } } + + /** + * Creates a {@link RectF} from an array of dimensions + * (e.g. [x, y, width, height]) + * + * @param data the array of dimensions + * @return the {@link RectF} that can used to clip the canvas + */ + private static RectF createClipping(float[] data) { + if (data.length != 4) { + throw new JSApplicationIllegalArgumentException( + "Clipping should be array of length 4 (e.g. [x, y, width, height])"); + } + RectF clippingRect = new RectF( + data[0], data[1], data[0] + data[2], data[1] + data[3]); + return clippingRect; + } }