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