From 8a70c8d416a73ea4c49543ab3933e828c1d67ea4 Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Mon, 5 Oct 2015 13:50:43 -0700 Subject: [PATCH 1/2] Adds support for disabling and re-enabling should rasterize. --- AsyncDisplayKit/ASDisplayNode.mm | 60 ++++++- AsyncDisplayKit/Private/_ASPendingState.h | 3 + AsyncDisplayKit/Private/_ASPendingState.m | 208 ++++++++++++++++++++++ 3 files changed, 268 insertions(+), 3 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index f8b5aef2ec..6201fb75ef 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -331,6 +331,40 @@ - (void)dealloc #pragma mark - Core +- (void)__tearDown:(BOOL)tearDown subnodesOfNode:(ASDisplayNode *)node +{ + for (ASDisplayNode *subnode in node.subnodes) { + if (tearDown) { + [subnode __unloadNode]; + } else { + [subnode __loadNode]; + } + } +} + +- (void)__unloadNode +{ + ASDisplayNodeAssertThreadAffinity(self); + ASDN::MutexLocker l(_propertyLock); + + if (_flags.layerBacked) + _pendingViewState = [_ASPendingState pendingViewStateFromLayer:_layer]; + else + _pendingViewState = [_ASPendingState pendingViewStateFromView:_view]; + + [_view removeFromSuperview]; + _view = nil; + if (_flags.layerBacked) + _layer.delegate = nil; + [_layer removeFromSuperlayer]; + _layer = nil; +} + +- (void)__loadNode +{ + [self layer]; +} + - (ASDisplayNode *)__rasterizedContainerNode { ASDisplayNode *node = self.supernode; @@ -340,7 +374,7 @@ - (ASDisplayNode *)__rasterizedContainerNode } node = node.supernode; } - + return nil; } @@ -619,11 +653,22 @@ - (void)setShouldRasterizeDescendants:(BOOL)flag { ASDisplayNodeAssertThreadAffinity(self); ASDN::MutexLocker l(_propertyLock); - + if (_flags.shouldRasterizeDescendants == flag) return; - + _flags.shouldRasterizeDescendants = flag; + + if (self.isNodeLoaded) { + //recursively tear down or build up subnodes + [self recursivelyClearContents]; + [self __tearDown:flag subnodesOfNode:self]; + if (flag == NO) { + [self _addSubnodeViewsAndLayers]; + } + + [self recursivelyDisplayImmediately]; + } } - (CGFloat)contentsScaleForDisplay @@ -653,6 +698,15 @@ - (void)displayImmediately [[self asyncLayer] displayImmediately]; } +- (void)recursivelyDisplayImmediately +{ + ASDN::MutexLocker l(_propertyLock); + for (ASDisplayNode *child in _subnodes) { + [child recursivelyDisplayImmediately]; + } + [self displayImmediately]; +} + - (void)__setNeedsLayout { ASDisplayNodeAssertThreadAffinity(self); diff --git a/AsyncDisplayKit/Private/_ASPendingState.h b/AsyncDisplayKit/Private/_ASPendingState.h index 904730b93d..4dd1146d24 100644 --- a/AsyncDisplayKit/Private/_ASPendingState.h +++ b/AsyncDisplayKit/Private/_ASPendingState.h @@ -27,4 +27,7 @@ - (void)applyToView:(UIView *)view; - (void)applyToLayer:(CALayer *)layer; ++ (_ASPendingState *)pendingViewStateFromLayer:(CALayer *)layer; ++ (_ASPendingState *)pendingViewStateFromView:(UIView *)view; + @end diff --git a/AsyncDisplayKit/Private/_ASPendingState.m b/AsyncDisplayKit/Private/_ASPendingState.m index b92f97d802..f8c2426971 100644 --- a/AsyncDisplayKit/Private/_ASPendingState.m +++ b/AsyncDisplayKit/Private/_ASPendingState.m @@ -796,4 +796,212 @@ - (void)applyToView:(UIView *)view view.accessibilityIdentifier = accessibilityIdentifier; } ++ (_ASPendingState *)pendingViewStateFromLayer:(CALayer *)layer +{ + _ASPendingState *pendingState = [[_ASPendingState alloc] init]; + + pendingState.anchorPoint = layer.anchorPoint; + (pendingState->_flags).setAnchorPoint = YES; + + pendingState.position = layer.position; + (pendingState->_flags).setPosition = YES; + + pendingState.zPosition = layer.zPosition; + (pendingState->_flags).setZPosition = YES; + + pendingState.bounds = layer.bounds; + (pendingState->_flags).setBounds = YES; + + pendingState.contentsScale = layer.contentsScale; + (pendingState->_flags).setContentsScale = YES; + + pendingState.transform = layer.transform; + (pendingState->_flags).setTransform = YES; + + pendingState.sublayerTransform = layer.sublayerTransform; + (pendingState->_flags).setSublayerTransform = YES; + + pendingState.contents = layer.contents; + (pendingState->_flags).setContents = YES; + + pendingState.clipsToBounds = layer.masksToBounds; + (pendingState->_flags).setClipsToBounds = YES; + + pendingState.backgroundColor = layer.backgroundColor; + (pendingState->_flags).setBackgroundColor = YES; + + pendingState.opaque = layer.opaque; + (pendingState->_flags).setOpaque = YES; + + pendingState.hidden = layer.hidden; + (pendingState->_flags).setHidden = YES; + + pendingState.alpha = layer.opacity; + (pendingState->_flags).setAlpha = YES; + + pendingState.cornerRadius = layer.cornerRadius; + (pendingState->_flags).setCornerRadius = YES; + + pendingState.contentMode = ASDisplayNodeUIContentModeFromCAContentsGravity(layer.contentsGravity); + (pendingState->_flags).setContentMode = YES; + + pendingState.shadowColor = layer.shadowColor; + (pendingState->_flags).setShadowColor = YES; + + pendingState.shadowOpacity = layer.shadowOpacity; + (pendingState->_flags).setShadowOpacity = YES; + + pendingState.shadowOffset = layer.shadowOffset; + (pendingState->_flags).setShadowOffset = YES; + + pendingState.shadowRadius = layer.shadowRadius; + (pendingState->_flags).setShadowRadius = YES; + + pendingState.borderWidth = layer.borderWidth; + (pendingState->_flags).setBorderWidth = YES; + + pendingState.borderColor = layer.borderColor; + (pendingState->_flags).setBorderColor = YES; + + pendingState.needsDisplayOnBoundsChange = layer.needsDisplayOnBoundsChange; + (pendingState->_flags).setNeedsDisplayOnBoundsChange = YES; + + pendingState.allowsEdgeAntialiasing = layer.allowsEdgeAntialiasing; + (pendingState->_flags).setAllowsEdgeAntialiasing = YES; + + pendingState.edgeAntialiasingMask = layer.edgeAntialiasingMask; + (pendingState->_flags).setEdgeAntialiasingMask = YES; + + return pendingState; +} + ++ (_ASPendingState *)pendingViewStateFromView:(UIView *)view +{ + _ASPendingState *pendingState = [[_ASPendingState alloc] init]; + + CALayer *layer = view.layer; + + pendingState.anchorPoint = layer.anchorPoint; + (pendingState->_flags).setAnchorPoint = YES; + + pendingState.position = layer.position; + (pendingState->_flags).setPosition = YES; + + pendingState.zPosition = layer.zPosition; + (pendingState->_flags).setZPosition = YES; + + pendingState.bounds = view.bounds; + (pendingState->_flags).setBounds = YES; + + pendingState.contentsScale = layer.contentsScale; + (pendingState->_flags).setContentsScale = YES; + + pendingState.transform = layer.transform; + (pendingState->_flags).setTransform = YES; + + pendingState.sublayerTransform = layer.sublayerTransform; + (pendingState->_flags).setSublayerTransform = YES; + + pendingState.contents = layer.contents; + (pendingState->_flags).setContents = YES; + + pendingState.clipsToBounds = view.clipsToBounds; + (pendingState->_flags).setClipsToBounds = YES; + + pendingState.backgroundColor = layer.backgroundColor; + (pendingState->_flags).setBackgroundColor = YES; + + pendingState.tintColor = view.tintColor; + (pendingState->_flags).setTintColor = YES; + + pendingState.opaque = layer.opaque; + (pendingState->_flags).setOpaque = YES; + + pendingState.hidden = view.hidden; + (pendingState->_flags).setHidden = YES; + + pendingState.alpha = view.alpha; + (pendingState->_flags).setAlpha = YES; + + pendingState.cornerRadius = layer.cornerRadius; + (pendingState->_flags).setCornerRadius = YES; + + pendingState.contentMode = view.contentMode; + (pendingState->_flags).setContentMode = YES; + + pendingState.userInteractionEnabled = view.userInteractionEnabled; + (pendingState->_flags).setUserInteractionEnabled = YES; + + pendingState.exclusiveTouch = view.exclusiveTouch; + (pendingState->_flags).setExclusiveTouch = YES; + + pendingState.shadowColor = layer.shadowColor; + (pendingState->_flags).setShadowColor = YES; + + pendingState.shadowOpacity = layer.shadowOpacity; + (pendingState->_flags).setShadowOpacity = YES; + + pendingState.shadowOffset = layer.shadowOffset; + (pendingState->_flags).setShadowOffset = YES; + + pendingState.shadowRadius = layer.shadowRadius; + (pendingState->_flags).setShadowRadius = YES; + + pendingState.borderWidth = layer.borderWidth; + (pendingState->_flags).setBorderWidth = YES; + + pendingState.borderColor = layer.borderColor; + (pendingState->_flags).setBorderColor = YES; + + pendingState.autoresizingMask = view.autoresizingMask; + (pendingState->_flags).setAutoresizingMask = YES; + + pendingState.autoresizesSubviews = view.autoresizesSubviews; + (pendingState->_flags).setAutoresizesSubviews = YES; + + pendingState.needsDisplayOnBoundsChange = layer.needsDisplayOnBoundsChange; + (pendingState->_flags).setNeedsDisplayOnBoundsChange = YES; + + pendingState.allowsEdgeAntialiasing = layer.allowsEdgeAntialiasing; + (pendingState->_flags).setAllowsEdgeAntialiasing = YES; + + pendingState.edgeAntialiasingMask = layer.edgeAntialiasingMask; + (pendingState->_flags).setEdgeAntialiasingMask = YES; + + pendingState.isAccessibilityElement = view.isAccessibilityElement; + (pendingState->_flags).setIsAccessibilityElement = YES; + + pendingState.accessibilityLabel = view.accessibilityLabel; + (pendingState->_flags).setAccessibilityLabel = YES; + + pendingState.accessibilityHint = view.accessibilityHint; + (pendingState->_flags).setAccessibilityHint = YES; + + pendingState.accessibilityValue = view.accessibilityValue; + (pendingState->_flags).setAccessibilityValue = YES; + + pendingState.accessibilityTraits = view.accessibilityTraits; + (pendingState->_flags).setAccessibilityTraits = YES; + + pendingState.accessibilityFrame = view.accessibilityFrame; + (pendingState->_flags).setAccessibilityFrame = YES; + + pendingState.accessibilityLanguage = view.accessibilityLanguage; + (pendingState->_flags).setAccessibilityLanguage = YES; + + pendingState.accessibilityElementsHidden = view.accessibilityElementsHidden; + (pendingState->_flags).setAccessibilityElementsHidden = YES; + + pendingState.accessibilityViewIsModal = view.accessibilityViewIsModal; + (pendingState->_flags).setAccessibilityViewIsModal = YES; + + pendingState.shouldGroupAccessibilityChildren = view.shouldGroupAccessibilityChildren; + (pendingState->_flags).setShouldGroupAccessibilityChildren = YES; + + pendingState.accessibilityIdentifier = view.accessibilityIdentifier; + (pendingState->_flags).setAccessibilityIdentifier = YES; + + return pendingState; +} + @end From 1a8f66919b91e6892ed446276e601ce9efac08e7 Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Tue, 6 Oct 2015 11:35:43 -0700 Subject: [PATCH 2/2] Add tests for enabling / disabling shouldRasterize --- AsyncDisplayKitTests/ASSnapshotTestCase.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/AsyncDisplayKitTests/ASSnapshotTestCase.h b/AsyncDisplayKitTests/ASSnapshotTestCase.h index 054560152c..dae712c29b 100644 --- a/AsyncDisplayKitTests/ASSnapshotTestCase.h +++ b/AsyncDisplayKitTests/ASSnapshotTestCase.h @@ -14,6 +14,12 @@ { \ [ASSnapshotTestCase hackilySynchronouslyRecursivelyRenderNode:node__]; \ FBSnapshotVerifyLayer(node__.layer, identifier__); \ + [node__ setShouldRasterizeDescendants:YES]; \ + [ASSnapshotTestCase hackilySynchronouslyRecursivelyRenderNode:node__]; \ + FBSnapshotVerifyLayer(node__.layer, identifier__); \ + [node__ setShouldRasterizeDescendants:NO]; \ + [ASSnapshotTestCase hackilySynchronouslyRecursivelyRenderNode:node__]; \ + FBSnapshotVerifyLayer(node__.layer, identifier__); \ } @interface ASSnapshotTestCase : FBSnapshotTestCase