diff --git a/Source/ASDisplayNode.h b/Source/ASDisplayNode.h
index ce54e0a51..161146a4d 100644
--- a/Source/ASDisplayNode.h
+++ b/Source/ASDisplayNode.h
@@ -666,6 +666,14 @@ AS_EXTERN NSInteger const ASDefaultDrawingPriority;
*/
@property CGFloat cornerRadius; // default=0.0
+/** @abstract Which corners to mask when rounding corners.
+ *
+ * @note This option cannot be changed when using iOS < 11
+ * and using ASCornerRoundingTypeDefaultSlowCALayer. Use a different corner rounding type to implement not-all-corners
+ * rounding in prior versions of iOS.
+ */
+@property CACornerMask maskedCorners; // default=all corners.
+
@property BOOL clipsToBounds; // default==NO
@property (getter=isHidden) BOOL hidden; // default==NO
@property (getter=isOpaque) BOOL opaque; // default==YES
diff --git a/Source/ASDisplayNode.mm b/Source/ASDisplayNode.mm
index 7bc5716de..83e333a01 100644
--- a/Source/ASDisplayNode.mm
+++ b/Source/ASDisplayNode.mm
@@ -324,6 +324,7 @@ - (void)_initializeInstance
_contentsScaleForDisplay = ASScreenScale();
_drawingPriority = ASDefaultTransactionPriority;
+ _maskedCorners = kASCACornerAllCorners;
_primitiveTraitCollection = ASPrimitiveTraitCollectionMakeDefault();
@@ -1526,17 +1527,17 @@ - (void)recursivelySetNeedsDisplayAtScale:(CGFloat)contentsScale
- (void)_layoutClipCornersIfNeeded
{
ASDisplayNodeAssertMainThread();
- if (_clipCornerLayers[0] == nil) {
+ if (_clipCornerLayers[0] == nil && _clipCornerLayers[1] == nil && _clipCornerLayers[2] == nil &&
+ _clipCornerLayers[3] == nil) {
return;
}
-
+
CGSize boundsSize = self.bounds.size;
for (int idx = 0; idx < NUM_CLIP_CORNER_LAYERS; idx++) {
BOOL isTop = (idx == 0 || idx == 1);
- BOOL isRight = (idx == 1 || idx == 2);
+ BOOL isRight = (idx == 1 || idx == 3);
if (_clipCornerLayers[idx]) {
- // Note the Core Animation coordinates are reversed for y; 0 is at the bottom.
- _clipCornerLayers[idx].position = CGPointMake(isRight ? boundsSize.width : 0.0, isTop ? boundsSize.height : 0.0);
+ _clipCornerLayers[idx].position = CGPointMake(isRight ? boundsSize.width : 0.0, isTop ? 0.0 : boundsSize.height);
[_layer addSublayer:_clipCornerLayers[idx]];
}
}
@@ -1546,78 +1547,87 @@ - (void)_updateClipCornerLayerContentsWithRadius:(CGFloat)radius backgroundColor
{
ASPerformBlockOnMainThread(^{
for (int idx = 0; idx < NUM_CLIP_CORNER_LAYERS; idx++) {
- // Layers are, in order: Top Left, Top Right, Bottom Right, Bottom Left.
+ // Skip corners that aren't clipped (we have already set up & torn down layers based on maskedCorners.)
+ if (_clipCornerLayers[idx] == nil) {
+ continue;
+ }
+
+ // Layers are, in order: Top Left, Top Right, Bottom Left, Bottom Right, which mirrors CACornerMask.
// anchorPoint is Bottom Left at 0,0 and Top Right at 1,1.
BOOL isTop = (idx == 0 || idx == 1);
- BOOL isRight = (idx == 1 || idx == 2);
-
+ BOOL isRight = (idx == 1 || idx == 3);
+
CGSize size = CGSizeMake(radius + 1, radius + 1);
ASGraphicsBeginImageContextWithOptions(size, NO, self.contentsScaleForDisplay);
-
+
CGContextRef ctx = UIGraphicsGetCurrentContext();
if (isRight == YES) {
CGContextTranslateCTM(ctx, -radius + 1, 0);
}
- if (isTop == YES) {
+ if (isTop == NO) {
CGContextTranslateCTM(ctx, 0, -radius + 1);
}
+
UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, radius * 2, radius * 2) cornerRadius:radius];
[roundedRect setUsesEvenOddFillRule:YES];
[roundedRect appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(-1, -1, radius * 2 + 1, radius * 2 + 1)]];
[backgroundColor setFill];
[roundedRect fill];
-
+
// No lock needed, as _clipCornerLayers is only modified on the main thread.
- CALayer *clipCornerLayer = _clipCornerLayers[idx];
+ unowned CALayer *clipCornerLayer = _clipCornerLayers[idx];
clipCornerLayer.contents = (id)(ASGraphicsGetImageAndEndCurrentContext().CGImage);
clipCornerLayer.bounds = CGRectMake(0.0, 0.0, size.width, size.height);
- clipCornerLayer.anchorPoint = CGPointMake(isRight ? 1.0 : 0.0, isTop ? 1.0 : 0.0);
+ clipCornerLayer.anchorPoint = CGPointMake(isRight ? 1.0 : 0.0, isTop ? 0.0 : 1.0);
}
[self _layoutClipCornersIfNeeded];
});
}
-- (void)_setClipCornerLayersVisible:(BOOL)visible
+- (void)_setClipCornerLayersVisible:(CACornerMask)visibleCornerLayers
{
ASPerformBlockOnMainThread(^{
ASDisplayNodeAssertMainThread();
- if (visible) {
- for (int idx = 0; idx < NUM_CLIP_CORNER_LAYERS; idx++) {
- if (_clipCornerLayers[idx] == nil) {
- static ASDisplayNodeCornerLayerDelegate *clipCornerLayers;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- clipCornerLayers = [[ASDisplayNodeCornerLayerDelegate alloc] init];
- });
- _clipCornerLayers[idx] = [[CALayer alloc] init];
- _clipCornerLayers[idx].zPosition = 99999;
- _clipCornerLayers[idx].delegate = clipCornerLayers;
- }
- }
- [self _updateClipCornerLayerContentsWithRadius:_cornerRadius backgroundColor:self.backgroundColor];
- } else {
- for (int idx = 0; idx < NUM_CLIP_CORNER_LAYERS; idx++) {
+ for (int idx = 0; idx < NUM_CLIP_CORNER_LAYERS; idx++) {
+ BOOL visible = (0 != (visibleCornerLayers & (1 << idx)));
+ if (visible == (_clipCornerLayers[idx] != nil)) {
+ continue;
+ } else if (visible) {
+ static ASDisplayNodeCornerLayerDelegate *clipCornerLayers;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ clipCornerLayers = [[ASDisplayNodeCornerLayerDelegate alloc] init];
+ });
+ _clipCornerLayers[idx] = [[CALayer alloc] init];
+ _clipCornerLayers[idx].zPosition = 99999;
+ _clipCornerLayers[idx].delegate = clipCornerLayers;
+ } else {
[_clipCornerLayers[idx] removeFromSuperlayer];
_clipCornerLayers[idx] = nil;
}
}
+ [self _updateClipCornerLayerContentsWithRadius:_cornerRadius backgroundColor:self.backgroundColor];
});
}
-- (void)updateCornerRoundingWithType:(ASCornerRoundingType)newRoundingType cornerRadius:(CGFloat)newCornerRadius
+- (void)updateCornerRoundingWithType:(ASCornerRoundingType)newRoundingType
+ cornerRadius:(CGFloat)newCornerRadius
+ maskedCorners:(CACornerMask)newMaskedCorners
{
__instanceLock__.lock();
CGFloat oldCornerRadius = _cornerRadius;
ASCornerRoundingType oldRoundingType = _cornerRoundingType;
+ CACornerMask oldMaskedCorners = _maskedCorners;
_cornerRadius = newCornerRadius;
_cornerRoundingType = newRoundingType;
+ _maskedCorners = newMaskedCorners;
__instanceLock__.unlock();
-
+
ASPerformBlockOnMainThread(^{
ASDisplayNodeAssertMainThread();
- if (oldRoundingType != newRoundingType || oldCornerRadius != newCornerRadius) {
+ if (oldRoundingType != newRoundingType || oldCornerRadius != newCornerRadius || oldMaskedCorners != newMaskedCorners) {
if (oldRoundingType == ASCornerRoundingTypeDefaultSlowCALayer) {
if (newRoundingType == ASCornerRoundingTypePrecomposited) {
self.layerCornerRadius = 0.0;
@@ -1629,14 +1639,16 @@ - (void)updateCornerRoundingWithType:(ASCornerRoundingType)newRoundingType corne
}
else if (newRoundingType == ASCornerRoundingTypeClipping) {
self.layerCornerRadius = 0.0;
- [self _setClipCornerLayersVisible:YES];
+ [self _setClipCornerLayersVisible:newMaskedCorners];
} else if (newRoundingType == ASCornerRoundingTypeDefaultSlowCALayer) {
self.layerCornerRadius = newCornerRadius;
+ self.layerMaskedCorners = newMaskedCorners;
}
}
else if (oldRoundingType == ASCornerRoundingTypePrecomposited) {
if (newRoundingType == ASCornerRoundingTypeDefaultSlowCALayer) {
self.layerCornerRadius = newCornerRadius;
+ self.layerMaskedCorners = newMaskedCorners;
[self setNeedsDisplay];
}
else if (newRoundingType == ASCornerRoundingTypePrecomposited) {
@@ -1645,22 +1657,23 @@ - (void)updateCornerRoundingWithType:(ASCornerRoundingType)newRoundingType corne
[self setNeedsDisplay];
}
else if (newRoundingType == ASCornerRoundingTypeClipping) {
- [self _setClipCornerLayersVisible:YES];
+ [self _setClipCornerLayersVisible:newMaskedCorners];
[self setNeedsDisplay];
}
}
else if (oldRoundingType == ASCornerRoundingTypeClipping) {
if (newRoundingType == ASCornerRoundingTypeDefaultSlowCALayer) {
self.layerCornerRadius = newCornerRadius;
- [self _setClipCornerLayersVisible:NO];
+ [self _setClipCornerLayersVisible:kNilOptions];
}
else if (newRoundingType == ASCornerRoundingTypePrecomposited) {
- [self _setClipCornerLayersVisible:NO];
+ [self _setClipCornerLayersVisible:kNilOptions];
[self displayImmediately];
}
else if (newRoundingType == ASCornerRoundingTypeClipping) {
- // Clip corners already exist, but the radius has changed.
- [self _updateClipCornerLayerContentsWithRadius:newCornerRadius backgroundColor:self.backgroundColor];
+ // Clip corners already exist, but the radius and/or maskedCorners have changed.
+ // This method will add & remove them, and subsequently redraw them.
+ [self _setClipCornerLayersVisible:newMaskedCorners];
}
}
}
diff --git a/Source/Details/UIView+ASConvenience.h b/Source/Details/UIView+ASConvenience.h
index 8c4b2f55c..19fd57695 100644
--- a/Source/Details/UIView+ASConvenience.h
+++ b/Source/Details/UIView+ASConvenience.h
@@ -22,6 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic) CGFloat zPosition;
@property (nonatomic) CGPoint anchorPoint;
@property (nonatomic) CGFloat cornerRadius;
+@property (nonatomic) CACornerMask maskedCorners API_AVAILABLE(ios(11), tvos(11));
@property (nullable, nonatomic) id contents;
@property (nonatomic, copy) NSString *contentsGravity;
@property (nonatomic) CGRect contentsRect;
diff --git a/Source/Private/ASDisplayNode+AsyncDisplay.mm b/Source/Private/ASDisplayNode+AsyncDisplay.mm
index 31662bd70..68bf4107a 100644
--- a/Source/Private/ASDisplayNode+AsyncDisplay.mm
+++ b/Source/Private/ASDisplayNode+AsyncDisplay.mm
@@ -287,13 +287,15 @@ - (void)__willDisplayNodeContentWithRenderingContext:(CGContextRef)context drawP
ASCornerRoundingType cornerRoundingType = _cornerRoundingType;
CGFloat cornerRadius = _cornerRadius;
ASDisplayNodeContextModifier willDisplayNodeContentWithRenderingContext = _willDisplayNodeContentWithRenderingContext;
+ CACornerMask maskedCorners = _maskedCorners;
__instanceLock__.unlock();
if (cornerRoundingType == ASCornerRoundingTypePrecomposited && cornerRadius > 0.0) {
ASDisplayNodeAssert(context == UIGraphicsGetCurrentContext(), @"context is expected to be pushed on UIGraphics stack %@", self);
// TODO: This clip path should be removed if we are rasterizing.
CGRect boundingBox = CGContextGetClipBoundingBox(context);
- [[UIBezierPath bezierPathWithRoundedRect:boundingBox cornerRadius:cornerRadius] addClip];
+ CGSize radii = CGSizeMake(cornerRadius, cornerRadius);
+ [[UIBezierPath bezierPathWithRoundedRect:boundingBox byRoundingCorners:maskedCorners cornerRadii:radii] addClip];
}
if (willDisplayNodeContentWithRenderingContext) {
@@ -313,6 +315,7 @@ - (void)__didDisplayNodeContentWithRenderingContext:(CGContextRef)context image:
CGFloat cornerRadius = _cornerRadius;
CGFloat contentsScale = _contentsScaleForDisplay;
ASDisplayNodeContextModifier didDisplayNodeContentWithRenderingContext = _didDisplayNodeContentWithRenderingContext;
+ CACornerMask maskedCorners = _maskedCorners;
__instanceLock__.unlock();
if (context != NULL) {
@@ -338,7 +341,10 @@ - (void)__didDisplayNodeContentWithRenderingContext:(CGContextRef)context image:
ASDisplayNodeAssert(UIGraphicsGetCurrentContext(), @"context is expected to be pushed on UIGraphics stack %@", self);
UIBezierPath *roundedHole = [UIBezierPath bezierPathWithRect:bounds];
- [roundedHole appendPath:[UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:cornerRadius * contentsScale]];
+ CGSize radii = CGSizeMake(cornerRadius * contentsScale, cornerRadius * contentsScale);
+ [roundedHole appendPath:[UIBezierPath bezierPathWithRoundedRect:bounds
+ byRoundingCorners:maskedCorners
+ cornerRadii:radii]];
roundedHole.usesEvenOddFillRule = YES;
UIBezierPath *roundedPath = nil;
diff --git a/Source/Private/ASDisplayNode+UIViewBridge.mm b/Source/Private/ASDisplayNode+UIViewBridge.mm
index 4f7e93140..45828d7bc 100644
--- a/Source/Private/ASDisplayNode+UIViewBridge.mm
+++ b/Source/Private/ASDisplayNode+UIViewBridge.mm
@@ -181,7 +181,9 @@ - (CGFloat)cornerRadius
- (void)setCornerRadius:(CGFloat)newCornerRadius
{
- [self updateCornerRoundingWithType:self.cornerRoundingType cornerRadius:newCornerRadius];
+ [self updateCornerRoundingWithType:self.cornerRoundingType
+ cornerRadius:newCornerRadius
+ maskedCorners:self.maskedCorners];
}
- (ASCornerRoundingType)cornerRoundingType
@@ -192,7 +194,20 @@ - (ASCornerRoundingType)cornerRoundingType
- (void)setCornerRoundingType:(ASCornerRoundingType)newRoundingType
{
- [self updateCornerRoundingWithType:newRoundingType cornerRadius:self.cornerRadius];
+ [self updateCornerRoundingWithType:newRoundingType cornerRadius:self.cornerRadius maskedCorners:self.maskedCorners];
+}
+
+- (CACornerMask)maskedCorners
+{
+ AS::MutexLocker l(__instanceLock__);
+ return _maskedCorners;
+}
+
+- (void)setMaskedCorners:(CACornerMask)newMaskedCorners
+{
+ [self updateCornerRoundingWithType:self.cornerRoundingType
+ cornerRadius:self.cornerRadius
+ maskedCorners:newMaskedCorners];
}
- (NSString *)contentsGravity
@@ -983,6 +998,27 @@ - (void)setLayerCornerRadius:(CGFloat)newLayerCornerRadius
_setToLayer(cornerRadius, newLayerCornerRadius);
}
+- (CACornerMask)layerMaskedCorners
+{
+ _bridge_prologue_read;
+ if (AS_AVAILABLE_IOS_TVOS(11, 11)) {
+ return _getFromLayer(maskedCorners);
+ } else {
+ return kASCACornerAllCorners;
+ }
+}
+
+- (void)setLayerMaskedCorners:(CACornerMask)newLayerMaskedCorners
+{
+ _bridge_prologue_write;
+ if (AS_AVAILABLE_IOS_TVOS(11, 11)) {
+ _setToLayer(maskedCorners, newLayerMaskedCorners);
+ } else {
+ ASDisplayNodeAssert(newLayerMaskedCorners == kASCACornerAllCorners,
+ @"Cannot change maskedCorners property in iOS < 11 while using DefaultSlowCALayer rounding.");
+ }
+}
+
- (BOOL)_locked_insetsLayoutMarginsFromSafeArea
{
ASAssertLocked(__instanceLock__);
diff --git a/Source/Private/ASDisplayNodeInternal.h b/Source/Private/ASDisplayNodeInternal.h
index b20470c6c..879639f16 100644
--- a/Source/Private/ASDisplayNodeInternal.h
+++ b/Source/Private/ASDisplayNodeInternal.h
@@ -73,6 +73,8 @@ AS_EXTERN NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimest
#define VISIBILITY_NOTIFICATIONS_DISABLED_BITS 4
#define TIME_DISPLAYNODE_OPS 0 // If you're using this information frequently, try: (DEBUG || PROFILE)
+static constexpr CACornerMask kASCACornerAllCorners =
+ kCALayerMinXMinYCorner | kCALayerMaxXMinYCorner | kCALayerMinXMaxYCorner | kCALayerMaxXMaxYCorner;
#define NUM_CLIP_CORNER_LAYERS 4
@@ -216,6 +218,7 @@ AS_EXTERN NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimest
CGFloat _cornerRadius;
ASCornerRoundingType _cornerRoundingType;
CALayer *_clipCornerLayers[NUM_CLIP_CORNER_LAYERS];
+ CACornerMask _maskedCorners;
ASDisplayNodeContextModifier _willDisplayNodeContentWithRenderingContext;
ASDisplayNodeContextModifier _didDisplayNodeContentWithRenderingContext;
@@ -336,8 +339,10 @@ AS_EXTERN NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimest
/// Display the node's view/layer immediately on the current thread, bypassing the background thread rendering. Will be deprecated.
- (void)displayImmediately;
-/// Refreshes any precomposited or drawn clip corners, setting up state as required to transition radius or rounding type.
-- (void)updateCornerRoundingWithType:(ASCornerRoundingType)newRoundingType cornerRadius:(CGFloat)newCornerRadius;
+/// Refreshes any precomposited or drawn clip corners, setting up state as required to transition corner config.
+- (void)updateCornerRoundingWithType:(ASCornerRoundingType)newRoundingType
+ cornerRadius:(CGFloat)newCornerRadius
+ maskedCorners:(CACornerMask)newMaskedCorners;
/// Alternative initialiser for backing with a custom view class. Supports asynchronous display with _ASDisplayView subclasses.
- (instancetype)initWithViewClass:(Class)viewClass;
@@ -397,6 +402,9 @@ AS_EXTERN NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimest
@property (nonatomic) CGFloat layerCornerRadius;
+/// NOTE: Changing this to non-default under iOS < 11 will make an assertion (for the end user to see.)
+@property (nonatomic) CACornerMask layerMaskedCorners;
+
- (BOOL)_locked_insetsLayoutMarginsFromSafeArea;
@end
diff --git a/Source/Private/_ASPendingState.mm b/Source/Private/_ASPendingState.mm
index 5dca0ce5c..422ee6239 100644
--- a/Source/Private/_ASPendingState.mm
+++ b/Source/Private/_ASPendingState.mm
@@ -87,6 +87,7 @@
int setPreservesSuperviewLayoutMargins:1;
int setInsetsLayoutMarginsFromSafeArea:1;
int setActions:1;
+ int setMaskedCorners : 1;
} ASPendingStateFlags;
@@ -215,6 +216,7 @@ ASDISPLAYNODE_INLINE void ASPendingStateApplyMetricsToLayer(_ASPendingState *sta
@synthesize preservesSuperviewLayoutMargins=preservesSuperviewLayoutMargins;
@synthesize insetsLayoutMarginsFromSafeArea=insetsLayoutMarginsFromSafeArea;
@synthesize actions=actions;
+@synthesize maskedCorners = maskedCorners;
static CGColorRef blackColorRef = NULL;
static UIColor *defaultTintColor = nil;
@@ -416,6 +418,12 @@ - (void)setCornerRadius:(CGFloat)newCornerRadius
_flags.setCornerRadius = YES;
}
+- (void)setMaskedCorners:(CACornerMask)newMaskedCorners
+{
+ maskedCorners = newMaskedCorners;
+ _flags.setMaskedCorners = YES;
+}
+
- (void)setContentMode:(UIViewContentMode)newContentMode
{
contentMode = newContentMode;
@@ -890,6 +898,12 @@ - (void)applyToLayer:(CALayer *)layer
if (flags.setCornerRadius)
layer.cornerRadius = cornerRadius;
+ if (AS_AVAILABLE_IOS_TVOS(11, 11)) {
+ if (flags.setMaskedCorners) {
+ layer.maskedCorners = maskedCorners;
+ }
+ }
+
if (flags.setContentMode)
layer.contentsGravity = ASDisplayNodeCAContentsGravityFromUIContentMode(contentMode);
diff --git a/Tests/ASDisplayNodeSnapshotTests.mm b/Tests/ASDisplayNodeSnapshotTests.mm
index 489727e3b..ae1bce744 100644
--- a/Tests/ASDisplayNodeSnapshotTests.mm
+++ b/Tests/ASDisplayNodeSnapshotTests.mm
@@ -8,6 +8,7 @@
#import "ASSnapshotTestCase.h"
#import
+#import
@interface ASDisplayNodeSnapshotTests : ASSnapshotTestCase
@@ -33,4 +34,46 @@ - (void)testBasicHierarchySnapshotTesting
ASSnapshotVerifyNode(node, nil);
}
+NS_INLINE UIImage *BlueImageMake(CGRect bounds)
+{
+ UIGraphicsBeginImageContextWithOptions(bounds.size, YES, 0);
+ [[UIColor blueColor] setFill];
+ UIRectFill(bounds);
+ UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+ return image;
+}
+
+- (void)testPrecompositedCornerRounding
+{
+ for (CACornerMask c = 1; c <= kASCACornerAllCorners; c |= (c << 1)) {
+ auto node = [[ASImageNode alloc] init];
+ auto bounds = CGRectMake(0, 0, 100, 100);
+ node.image = BlueImageMake(bounds);
+ node.frame = bounds;
+ node.cornerRoundingType = ASCornerRoundingTypePrecomposited;
+ node.backgroundColor = UIColor.greenColor;
+ node.maskedCorners = c;
+ node.cornerRadius = 15;
+ ASSnapshotVerifyNode(node, ([NSString stringWithFormat:@"%d", (int)c]));
+ }
+}
+
+- (void)testClippingCornerRounding
+{
+ for (CACornerMask c = 1; c <= kASCACornerAllCorners; c |= (c << 1)) {
+ auto node = [[ASImageNode alloc] init];
+ auto bounds = CGRectMake(0, 0, 100, 100);
+ node.image = BlueImageMake(bounds);
+ node.frame = bounds;
+ node.cornerRoundingType = ASCornerRoundingTypeClipping;
+ node.backgroundColor = UIColor.greenColor;
+ node.maskedCorners = c;
+ node.cornerRadius = 15;
+ // A layout pass is required, because that's where we lay out the clip layers.
+ [node.layer layoutIfNeeded];
+ ASSnapshotVerifyNode(node, ([NSString stringWithFormat:@"%d", (int)c]));
+ }
+}
+
@end
diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding@2x.png
new file mode 100644
index 000000000..aa72ff691
Binary files /dev/null and b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding@2x.png differ
diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15@2x.png
new file mode 100644
index 000000000..187993d04
Binary files /dev/null and b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_15@2x.png differ
diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1@2x.png
new file mode 100644
index 000000000..aa72ff691
Binary files /dev/null and b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_1@2x.png differ
diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3@2x.png
new file mode 100644
index 000000000..17604b6ac
Binary files /dev/null and b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_3@2x.png differ
diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7@2x.png
new file mode 100644
index 000000000..45d842d09
Binary files /dev/null and b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testClippingCornerRounding_7@2x.png differ
diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding@2x.png
new file mode 100644
index 000000000..0b4a6b425
Binary files /dev/null and b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding@2x.png differ
diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_15@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_15@2x.png
new file mode 100644
index 000000000..ba850b21e
Binary files /dev/null and b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_15@2x.png differ
diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_1@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_1@2x.png
new file mode 100644
index 000000000..0b4a6b425
Binary files /dev/null and b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_1@2x.png differ
diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_3@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_3@2x.png
new file mode 100644
index 000000000..4282e29d3
Binary files /dev/null and b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_3@2x.png differ
diff --git a/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_7@2x.png b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_7@2x.png
new file mode 100644
index 000000000..46ae9327a
Binary files /dev/null and b/Tests/ReferenceImages_iOS_10/ASDisplayNodeSnapshotTests/testPrecompositedCornerRounding_7@2x.png differ