From 4d5e3ce81e880a5920f8a3b9eb363b0a69cc6267 Mon Sep 17 00:00:00 2001 From: Adlai Holler Date: Mon, 1 May 2017 08:26:37 -0700 Subject: [PATCH] Tighten Rasterization API, Undeprecate It (#82) * Tamp down the rasterization API, and undeprecate it * Update license header * Update chornglorg * Address comments --- CHANGELOG.md | 5 +- Source/ASDisplayNode+Beta.h | 11 +- Source/ASDisplayNode.h | 2 - Source/ASDisplayNode.mm | 147 +++++++----------- Source/ASDisplayNodeExtras.mm | 2 +- Source/Details/_ASDisplayViewAccessiblity.mm | 4 +- Source/Private/ASDisplayNode+AsyncDisplay.mm | 4 +- .../Private/ASDisplayNode+FrameworkPrivate.h | 2 +- Source/Private/ASDisplayNode+UIViewBridge.mm | 4 +- Source/Private/ASDisplayNodeInternal.h | 7 +- Tests/ASDisplayNodeTests.mm | 52 +------ 11 files changed, 81 insertions(+), 159 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4d99448f..c4b306dff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ ## master * Add your own contributions to the next release on the line below this with your name. -- Add support for IGListKit post-removal-of-IGListSectionType, in preparation for IGListKit 3.0.0 release. (Adlai-Holler)[https://github.com/Adlai-Holler] (#49)[https://github.com/TextureGroup/Texture/pull/49] +- Add support for IGListKit post-removal-of-IGListSectionType, in preparation for IGListKit 3.0.0 release. [Adlai Holler](https://github.com/Adlai-Holler) [#49](https://github.com/TextureGroup/Texture/pull/49) - Fix `__has_include` check in ASLog.h [Philipp Smorygo](Philipp.Smorygo@jetbrains.com) - Fix potential deadlock in ASControlNode [Garrett Moon](https://github.com/garrettmoon) - [Yoga Beta] Improvements to the experimental support for Yoga layout [Scott Goodson](appleguy) -- Simplified & optimized hashing code. [Adlai Holler](https://github.com/Adlai-Holler) [#86](https://github.com/TextureGroup/Texture/pull/86) \ No newline at end of file +- Update the rasterization API and un-deprecate it. [Adlai Holler](https://github.com/Adlai-Holler)[#82](https://github.com/TextureGroup/Texture/pull/49) +- Simplified & optimized hashing code. [Adlai Holler](https://github.com/Adlai-Holler) [#86](https://github.com/TextureGroup/Texture/pull/86) diff --git a/Source/ASDisplayNode+Beta.h b/Source/ASDisplayNode+Beta.h index 61616066b..65d02790c 100644 --- a/Source/ASDisplayNode+Beta.h +++ b/Source/ASDisplayNode+Beta.h @@ -136,11 +136,11 @@ typedef struct { + (void)setRangeModeForMemoryWarnings:(ASLayoutRangeMode)rangeMode; /** - * @abstract Whether to draw all descendant nodes' layers/views into this node's layer/view's backing store. + * @abstract Whether to draw all descendent nodes' contents into this node's layer's backing store. * * @discussion - * When set to YES, causes all descendant nodes' layers/views to be drawn directly into this node's layer/view's backing - * store. Defaults to NO. + * When called, causes all descendent nodes' contents to be drawn directly into this node's layer's backing + * store. * * If a node's descendants are static (never animated or never change attributes after creation) then that node is a * good candidate for rasterization. Rasterizing descendants has two main benefits: @@ -154,8 +154,11 @@ typedef struct { * * Note: this has nothing to do with -[CALayer shouldRasterize], which doesn't work with ASDisplayNode's asynchronous * rendering model. + * + * Note: You cannot add subnodes whose layers/views are already loaded to a rasterized node. + * Note: You cannot call this method after the receiver's layer/view is loaded. */ -@property (nonatomic, assign) BOOL shouldRasterizeDescendants ASDISPLAYNODE_DEPRECATED_MSG("Deprecated in version 2.2"); +- (void)enableSubtreeRasterization; @end diff --git a/Source/ASDisplayNode.h b/Source/ASDisplayNode.h index 4c75d2336..424ad2401 100644 --- a/Source/ASDisplayNode.h +++ b/Source/ASDisplayNode.h @@ -185,8 +185,6 @@ extern NSInteger const ASDefaultDrawingPriority; * @param body The work to be performed when the node is loaded. * * @precondition The node is not already loaded. - * @note This will only be called the next time the node is loaded. If the node is later added to a subtree of a node - * that has `shouldRasterizeDescendants=YES`, and is unloaded, this block will not be called if it is loaded again. */ - (void)onDidLoad:(ASDisplayNodeDidLoadBlock)body; diff --git a/Source/ASDisplayNode.mm b/Source/ASDisplayNode.mm index 7dbb1df19..5eadb854c 100644 --- a/Source/ASDisplayNode.mm +++ b/Source/ASDisplayNode.mm @@ -541,28 +541,7 @@ + (NSValue * _Nonnull)_ivarsThatMayNeedMainDeallocation return result; } -#pragma mark - Loading / Unloading - -- (void)__unloadNode -{ - ASDisplayNodeAssertMainThread(); - ASDisplayNodeAssert([self isNodeLoaded], @"Implementation shouldn't call __unloadNode if not loaded: %@", self); - ASDisplayNodeAssert(checkFlag(Synchronous) == NO, @"Node created using -initWithViewBlock:/-initWithLayerBlock: cannot be unloaded. Node: %@", self); - ASDN::MutexLocker l(__instanceLock__); - - 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; -} +#pragma mark - Loading - (BOOL)_locked_shouldLoadViewOrLayer { @@ -1970,63 +1949,46 @@ - (void)setDisplaysAsynchronously:(BOOL)displaysAsynchronously self._locked_asyncLayer.displaysAsynchronously = displaysAsynchronously; } -- (BOOL)shouldRasterizeDescendants +- (BOOL)rasterizesSubtree { ASDN::MutexLocker l(__instanceLock__); - ASDisplayNodeAssert(!((_hierarchyState & ASHierarchyStateRasterized) && _flags.shouldRasterizeDescendants), - @"Subnode of a rasterized node should not have redundant shouldRasterizeDescendants enabled"); - return _flags.shouldRasterizeDescendants; + return _flags.rasterizesSubtree; } -- (void)setShouldRasterizeDescendants:(BOOL)shouldRasterize +- (void)enableSubtreeRasterization { - ASDisplayNodeAssertThreadAffinity(self); - BOOL rasterizedFromSelfOrAncestor = NO; - { - ASDN::MutexLocker l(__instanceLock__); - - if (_flags.shouldRasterizeDescendants == shouldRasterize) + ASDN::MutexLocker l(__instanceLock__); + // Already rasterized from self. + if (_flags.rasterizesSubtree) { + return; + } + + // If rasterized from above, bail. + if (ASHierarchyStateIncludesRasterized(_hierarchyState)) { + ASDisplayNodeFailAssert(@"Subnode of a rasterized node should not have redundant -enableSubtreeRasterization."); + return; + } + + // Ensure not loaded. + if ([self _locked_isNodeLoaded]) { + ASDisplayNodeFailAssert(@"Cannot call %@ on loaded node: %@", NSStringFromSelector(_cmd), self); + return; + } + + // Ensure no loaded subnodes + ASDisplayNode *loadedSubnode = ASDisplayNodeFindFirstSubnode(self, ^BOOL(ASDisplayNode * _Nonnull node) { + return node.nodeLoaded; + }); + if (loadedSubnode != nil) { + ASDisplayNodeFailAssert(@"Cannot call %@ on node %@ with loaded subnode %@", NSStringFromSelector(_cmd), self, loadedSubnode); return; - - _flags.shouldRasterizeDescendants = shouldRasterize; - rasterizedFromSelfOrAncestor = shouldRasterize || ASHierarchyStateIncludesRasterized(_hierarchyState); } - - if (self.isNodeLoaded) { - // Recursively tear down or build up subnodes. - // TODO: When disabling rasterization, preserve rasterized backing store as placeholderImage - // while the newly materialized subtree finishes rendering. Then destroy placeholderImage to save memory. - [self recursivelyClearContents]; - - ASDisplayNodePerformBlockOnEverySubnode(self, NO, ^(ASDisplayNode *node) { - if (rasterizedFromSelfOrAncestor) { - [node enterHierarchyState:ASHierarchyStateRasterized]; - if (node.isNodeLoaded) { - [node __unloadNode]; - } - } else { - [node exitHierarchyState:ASHierarchyStateRasterized]; - // We can avoid eagerly loading this node. We will load it on-demand as usual. - } - }); - if (!rasterizedFromSelfOrAncestor) { - // If we are not going to rasterize at all, go ahead and set up our view hierarchy. - [self _addSubnodeViewsAndLayers]; - } - - if (ASInterfaceStateIncludesVisible(self.interfaceState)) { - // TODO: Change this to recursivelyEnsureDisplay - but need a variant that does not skip - // nodes that have shouldBypassEnsureDisplay set (such as image nodes) so they are rasterized. - [self recursivelyDisplayImmediately]; - } - } else { - ASDisplayNodePerformBlockOnEverySubnode(self, NO, ^(ASDisplayNode *node) { - if (rasterizedFromSelfOrAncestor) { - [node enterHierarchyState:ASHierarchyStateRasterized]; - } else { - [node exitHierarchyState:ASHierarchyStateRasterized]; - } - }); + + _flags.rasterizesSubtree = YES; + + // Tell subnodes that now they're in a rasterized hierarchy (while holding lock!) + for (ASDisplayNode *subnode in _subnodes) { + [subnode enterHierarchyState:ASHierarchyStateRasterized]; } } @@ -2108,7 +2070,7 @@ - (BOOL)_implementsDisplay { ASDN::MutexLocker l(__instanceLock__); - return _flags.implementsDrawRect || _flags.implementsImageDisplay || _flags.shouldRasterizeDescendants || + return _flags.implementsDrawRect || _flags.implementsImageDisplay || _flags.rasterizesSubtree || _flags.implementsInstanceDrawRect || _flags.implementsInstanceImageDisplay; } @@ -2291,7 +2253,7 @@ static void _recursivelySetDisplaySuspended(ASDisplayNode *node, CALayer *layer, // Set the flag on the node. If this is a pure layer (no node) then this has no effect (plain layers don't support preventing/cancelling display). node.displaySuspended = flag; - if (layer && !node.shouldRasterizeDescendants) { + if (layer && !node.rasterizesSubtree) { // If there is a layer, recurse down the layer hierarchy to set the flag on descendants. This will cover both layer-based and node-based children. for (CALayer *sublayer in layer.sublayers) { _recursivelySetDisplaySuspended(nil, sublayer, flag); @@ -2620,8 +2582,8 @@ ASDISPLAYNODE_INLINE BOOL canUseViewAPI(ASDisplayNode *node, ASDisplayNode *subn } /// Returns if node is a member of a rasterized tree -ASDISPLAYNODE_INLINE BOOL nodeIsInRasterizedTree(ASDisplayNode *node) { - return (node.shouldRasterizeDescendants || (node.hierarchyState & ASHierarchyStateRasterized)); +ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) { + return (node.rasterizesSubtree || (node.hierarchyState & ASHierarchyStateRasterized)); } // NOTE: This method must be dealloc-safe (should not retain self). @@ -2658,8 +2620,8 @@ - (void)_setSupernode:(ASDisplayNode *)newSupernode : oldSupernode.hierarchyState); // Rasterized state - BOOL parentWasOrIsRasterized = (newSupernode ? newSupernode.shouldRasterizeDescendants - : oldSupernode.shouldRasterizeDescendants); + BOOL parentWasOrIsRasterized = (newSupernode ? newSupernode.rasterizesSubtree + : oldSupernode.rasterizesSubtree); if (parentWasOrIsRasterized) { stateToEnterOrExit |= ASHierarchyStateRasterized; } @@ -2745,6 +2707,12 @@ - (void)_insertSubnode:(ASDisplayNode *)subnode atSubnodeIndex:(NSInteger)subnod return; } + BOOL isRasterized = subtreeIsRasterized(self); + if (isRasterized && subnode.nodeLoaded) { + ASDisplayNodeFailAssert(@"Cannot add loaded node %@ to rasterized subtree of node %@", ASObjectDescriptionMakeTiny(subnode), ASObjectDescriptionMakeTiny(self)); + return; + } + __instanceLock__.lock(); NSUInteger subnodesCount = _subnodes.count; __instanceLock__.unlock(); @@ -2774,15 +2742,10 @@ - (void)_insertSubnode:(ASDisplayNode *)subnode atSubnodeIndex:(NSInteger)subnod // If we are a managed hierarchy, as in ASCellNode trees, it will also apply our .interfaceState. [subnode _setSupernode:self]; - // If this subnode will be rasterized, update its hierarchy state & enter hierarchy if needed - if (nodeIsInRasterizedTree(self)) { - ASDisplayNodePerformBlockOnEveryNodeBFS(subnode, ^(ASDisplayNode * _Nonnull node) { - [node enterHierarchyState:ASHierarchyStateRasterized]; - if (node.isNodeLoaded) { - [node __unloadNode]; - } - }); - if (self.isInHierarchy) { + // If this subnode will be rasterized, enter hierarchy if needed + // TODO: Move this into _setSupernode: ? + if (isRasterized) { + if (self.inHierarchy) { [subnode __enterHierarchy]; } } else if (self.nodeLoaded) { @@ -2911,7 +2874,7 @@ - (void)_replaceSubnode:(ASDisplayNode *)oldSubnode withSubnode:(ASDisplayNode * // Don't bother figuring out the sublayerIndex if in a rasterized subtree, because there are no layers in the // hierarchy and none of this could possibly work. - if (nodeIsInRasterizedTree(self) == NO) { + if (subtreeIsRasterized(self) == NO) { if (_layer) { sublayerIndex = [_layer.sublayers indexOfObjectIdenticalTo:oldSubnode.layer]; ASDisplayNodeAssert(sublayerIndex != NSNotFound, @"Somehow oldSubnode's supernode is self, yet we could not find it in our layers to replace"); @@ -2957,7 +2920,7 @@ - (void)_insertSubnode:(ASDisplayNode *)subnode belowSubnode:(ASDisplayNode *)be // Don't bother figuring out the sublayerIndex if in a rasterized subtree, because there are no layers in the // hierarchy and none of this could possibly work. - if (nodeIsInRasterizedTree(self) == NO) { + if (subtreeIsRasterized(self) == NO) { if (_layer) { belowSublayerIndex = [_layer.sublayers indexOfObjectIdenticalTo:below.layer]; ASDisplayNodeAssert(belowSublayerIndex != NSNotFound, @"Somehow below's supernode is self, yet we could not find it in our layers to reference"); @@ -3021,7 +2984,7 @@ - (void)_insertSubnode:(ASDisplayNode *)subnode aboveSubnode:(ASDisplayNode *)ab // Don't bother figuring out the sublayerIndex if in a rasterized subtree, because there are no layers in the // hierarchy and none of this could possibly work. - if (nodeIsInRasterizedTree(self) == NO) { + if (subtreeIsRasterized(self) == NO) { if (_layer) { aboveSublayerIndex = [_layer.sublayers indexOfObjectIdenticalTo:above.layer]; ASDisplayNodeAssert(aboveSublayerIndex != NSNotFound, @"Somehow above's supernode is self, yet we could not find it in our layers to replace"); @@ -3079,7 +3042,7 @@ - (void)_insertSubnode:(ASDisplayNode *)subnode atIndex:(NSInteger)idx // Don't bother figuring out the sublayerIndex if in a rasterized subtree, because there are no layers in the // hierarchy and none of this could possibly work. - if (nodeIsInRasterizedTree(self) == NO) { + if (subtreeIsRasterized(self) == NO) { // Account for potentially having other subviews if (_layer && idx == 0) { sublayerIndex = 0; @@ -3405,7 +3368,7 @@ - (void)setHierarchyState:(ASHierarchyState)newState // Entered rasterization state. if (newState & ASHierarchyStateRasterized) { - ASDisplayNodeAssert(checkFlag(Synchronous) == NO, @"Node created using -initWithViewBlock:/-initWithLayerBlock: cannot be added to subtree of node with shouldRasterizeDescendants=YES. Node: %@", self); + ASDisplayNodeAssert(checkFlag(Synchronous) == NO, @"Node created using -initWithViewBlock:/-initWithLayerBlock: cannot be added to subtree of node with subtree rasterization enabled. Node: %@", self); } // Entered or exited range managed state. diff --git a/Source/ASDisplayNodeExtras.mm b/Source/ASDisplayNodeExtras.mm index 4555da4eb..6c595f296 100644 --- a/Source/ASDisplayNodeExtras.mm +++ b/Source/ASDisplayNodeExtras.mm @@ -97,7 +97,7 @@ extern void ASDisplayNodePerformBlockOnEveryNode(CALayer * _Nullable layer, ASDi layer = node.layer; } - if (traverseSublayers && layer && node.shouldRasterizeDescendants == NO) { + if (traverseSublayers && layer && node.rasterizesSubtree == NO) { /// NOTE: The docs say `sublayers` returns a copy, but it does not. /// See: http://stackoverflow.com/questions/14854480/collection-calayerarray-0x1ed8faa0-was-mutated-while-being-enumerated for (CALayer *sublayer in [[layer sublayers] copy]) { diff --git a/Source/Details/_ASDisplayViewAccessiblity.mm b/Source/Details/_ASDisplayViewAccessiblity.mm index b559f8f75..e2f937403 100644 --- a/Source/Details/_ASDisplayViewAccessiblity.mm +++ b/Source/Details/_ASDisplayViewAccessiblity.mm @@ -91,7 +91,7 @@ static void CollectUIAccessibilityElementsForNode(ASDisplayNode *node, ASDisplay ASDisplayNodeCAssertNotNil(elements, @"Should pass in a NSMutableArray"); ASDisplayNodePerformBlockOnEveryNodeBFS(node, ^(ASDisplayNode * _Nonnull currentNode) { - // For every subnode that is layer backed or it's supernode has shouldRasterizeDescendants enabled + // For every subnode that is layer backed or it's supernode has subtree rasterization enabled // we have to create a UIAccessibilityElement as no view for this node exists if (currentNode != containerNode && currentNode.isAccessibilityElement) { UIAccessibilityElement *accessibilityElement = [ASAccessibilityElement accessibilityElementWithContainer:container node:currentNode containerNode:containerNode]; @@ -108,7 +108,7 @@ static void CollectAccessibilityElementsForView(_ASDisplayView *view, NSMutableA ASDisplayNode *node = view.asyncdisplaykit_node; // Handle rasterize case - if (node.shouldRasterizeDescendants) { + if (node.rasterizesSubtree) { CollectUIAccessibilityElementsForNode(node, node, view, elements); return; } diff --git a/Source/Private/ASDisplayNode+AsyncDisplay.mm b/Source/Private/ASDisplayNode+AsyncDisplay.mm index ca535e46b..e34357f0a 100644 --- a/Source/Private/ASDisplayNode+AsyncDisplay.mm +++ b/Source/Private/ASDisplayNode+AsyncDisplay.mm @@ -77,7 +77,7 @@ - (void)_recursivelyRasterizeSelfAndSublayersWithIsCancelledBlock:(asdisplaynode CGRect frame; // If this is the root container node, use a frame with a zero origin to draw into. If not, calculate the correct frame using the node's position, transform and anchorPoint. - if (self.shouldRasterizeDescendants) { + if (self.rasterizesSubtree) { frame = CGRectMake(0.0f, 0.0f, bounds.size.width, bounds.size.height); } else { CGPoint position = self.position; @@ -169,7 +169,7 @@ - (asyncdisplaykit_async_transaction_operation_block_t)_displayBlockWithAsynchro // We always create a graphics context, unless a -display method is used, OR if we are a subnode drawing into a rasterized parent. BOOL shouldCreateGraphicsContext = (flags.implementsInstanceImageDisplay == NO && flags.implementsImageDisplay == NO && rasterizing == NO); - BOOL shouldBeginRasterizing = (rasterizing == NO && flags.shouldRasterizeDescendants); + BOOL shouldBeginRasterizing = (rasterizing == NO && flags.rasterizesSubtree); BOOL usesInstanceMethodDisplay = (flags.implementsInstanceDrawRect || flags.implementsInstanceImageDisplay); BOOL usesImageDisplay = (flags.implementsImageDisplay || flags.implementsInstanceImageDisplay); BOOL usesDrawRect = (flags.implementsDrawRect || flags.implementsInstanceDrawRect); diff --git a/Source/Private/ASDisplayNode+FrameworkPrivate.h b/Source/Private/ASDisplayNode+FrameworkPrivate.h index d55bb0eb6..d845a56b8 100644 --- a/Source/Private/ASDisplayNode+FrameworkPrivate.h +++ b/Source/Private/ASDisplayNode+FrameworkPrivate.h @@ -43,7 +43,7 @@ typedef NS_OPTIONS(NSUInteger, ASHierarchyState) { /** The node may or may not have a supernode, but no supernode has a special hierarchy-influencing option enabled. */ ASHierarchyStateNormal = 0, - /** The node has a supernode with .shouldRasterizeDescendants = YES. + /** The node has a supernode with .rasterizesSubtree = YES. Note: the root node of the rasterized subtree (the one with the property set on it) will NOT have this state set. */ ASHierarchyStateRasterized = 1 << 0, /** The node or one of its supernodes is managed by a class like ASRangeController. Most commonly, these nodes are diff --git a/Source/Private/ASDisplayNode+UIViewBridge.mm b/Source/Private/ASDisplayNode+UIViewBridge.mm index fc4b3c4ea..3c84d577b 100644 --- a/Source/Private/ASDisplayNode+UIViewBridge.mm +++ b/Source/Private/ASDisplayNode+UIViewBridge.mm @@ -319,12 +319,12 @@ - (void)setNeedsDisplay ASPerformBlockOnMainThread(^{ // The below operation must be performed on the main thread to ensure against an extremely rare deadlock, where a parent node // begins materializing the view / layer hierarchy (locking itself or a descendant) while this node walks up - // the tree and requires locking that node to access .shouldRasterizeDescendants. + // the tree and requires locking that node to access .rasterizesSubtree. // For this reason, this method should be avoided when possible. Use _hierarchyState & ASHierarchyStateRasterized. ASDisplayNodeAssertMainThread(); ASDisplayNode *rasterizedContainerNode = self.supernode; while (rasterizedContainerNode) { - if (rasterizedContainerNode.shouldRasterizeDescendants) { + if (rasterizedContainerNode.rasterizesSubtree) { break; } rasterizedContainerNode = rasterizedContainerNode.supernode; diff --git a/Source/Private/ASDisplayNodeInternal.h b/Source/Private/ASDisplayNodeInternal.h index 2535c9c86..7590d9511 100644 --- a/Source/Private/ASDisplayNodeInternal.h +++ b/Source/Private/ASDisplayNodeInternal.h @@ -88,7 +88,7 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo unsigned viewEverHadAGestureRecognizerAttached:1; unsigned layerBacked:1; unsigned displaysAsynchronously:1; - unsigned shouldRasterizeDescendants:1; + unsigned rasterizesSubtree:1; unsigned shouldBypassEnsureDisplay:1; unsigned displaySuspended:1; unsigned shouldAnimateSizeChanges:1; @@ -297,10 +297,9 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo - (ASPrimitiveTraitCollection)primitiveTraitCollection; /** - * This is a non-deprecated internal declaration of the property. Public declaration - * is in ASDisplayNode+Beta.h + * Whether this node rasterizes its descendants. See -enableSubtreeRasterization. */ -@property (nonatomic, assign) BOOL shouldRasterizeDescendants; +@property (atomic, readonly) BOOL rasterizesSubtree; - (void)nodeViewDidAddGestureRecognizer; diff --git a/Tests/ASDisplayNodeTests.mm b/Tests/ASDisplayNodeTests.mm index e9acff54e..c4f9dca69 100644 --- a/Tests/ASDisplayNodeTests.mm +++ b/Tests/ASDisplayNodeTests.mm @@ -1,5 +1,5 @@ // -// ASDisplayNodeTests.m +// ASDisplayNodeTests.mm // Texture // // Copyright (c) 2014-present, Facebook, Inc. All rights reserved. @@ -1977,7 +1977,7 @@ - (void)testThatNodeGetsRenderedIfItGoesFromZeroSizeToRealSizeButOnlyOnce - (void)testThatRasterizedNodesGetInterfaceStateUpdatesWhenContainerEntersHierarchy { ASDisplayNode *supernode = [[ASDisplayNode alloc] init]; - supernode.shouldRasterizeDescendants = YES; + [supernode enableSubtreeRasterization]; ASDisplayNode *subnode = [[ASDisplayNode alloc] init]; ASSetDebugNames(supernode, subnode); UIWindow *window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; @@ -1995,7 +1995,7 @@ - (void)testThatRasterizedNodesGetInterfaceStateUpdatesWhenContainerEntersHierar - (void)testThatRasterizedNodesGetInterfaceStateUpdatesWhenAddedToContainerThatIsInHierarchy { ASDisplayNode *supernode = [[ASDisplayNode alloc] init]; - supernode.shouldRasterizeDescendants = YES; + [supernode enableSubtreeRasterization]; ASDisplayNode *subnode = [[ASDisplayNode alloc] init]; ASSetDebugNames(supernode, subnode); @@ -2010,52 +2010,10 @@ - (void)testThatRasterizedNodesGetInterfaceStateUpdatesWhenAddedToContainerThatI XCTAssertFalse(subnode.isVisible); } -- (void)testThatLoadedNodeGetsUnloadedIfSubtreeBecomesRasterized -{ - ASDisplayNode *supernode = [[ASDisplayNode alloc] init]; - [supernode view]; - ASDisplayNode *subnode = [[ASDisplayNode alloc] init]; - ASSetDebugNames(supernode, subnode); - [supernode addSubnode:subnode]; - XCTAssertTrue(subnode.nodeLoaded); - supernode.shouldRasterizeDescendants = YES; - XCTAssertFalse(subnode.nodeLoaded); -} - -- (void)testThatLoadedNodeGetsUnloadedIfAddedToRasterizedSubtree -{ - ASDisplayNode *supernode = [[ASDisplayNode alloc] init]; - supernode.shouldRasterizeDescendants = YES; - ASDisplayNode *subnode = [[ASDisplayNode alloc] init]; - ASSetDebugNames(supernode, subnode); - [subnode view]; - XCTAssertTrue(subnode.nodeLoaded); - [supernode addSubnode:subnode]; - XCTAssertFalse(subnode.nodeLoaded); - XCTAssertTrue(ASHierarchyStateIncludesRasterized(subnode.hierarchyState)); -} - -- (void)testThatClearingRasterizationBitMidwayDownTheTreeWorksRight -{ - ASDisplayNode *topNode = [[ASDisplayNode alloc] init]; - topNode.shouldRasterizeDescendants = YES; - ASDisplayNode *middleNode = [[ASDisplayNode alloc] init]; - middleNode.shouldRasterizeDescendants = YES; - ASDisplayNode *bottomNode = [[ASDisplayNode alloc] init]; - ASSetDebugNames(topNode, middleNode, bottomNode); - [middleNode addSubnode:bottomNode]; - [topNode addSubnode:middleNode]; - XCTAssertTrue(ASHierarchyStateIncludesRasterized(bottomNode.hierarchyState)); - XCTAssertTrue(ASHierarchyStateIncludesRasterized(middleNode.hierarchyState)); - middleNode.shouldRasterizeDescendants = NO; - XCTAssertTrue(ASHierarchyStateIncludesRasterized(bottomNode.hierarchyState)); - XCTAssertTrue(ASHierarchyStateIncludesRasterized(middleNode.hierarchyState)); -} - - (void)testThatRasterizingWrapperNodesIsNotAllowed { ASDisplayNode *rasterizedSupernode = [[ASDisplayNode alloc] init]; - rasterizedSupernode.shouldRasterizeDescendants = YES; + [rasterizedSupernode enableSubtreeRasterization]; ASDisplayNode *subnode = [[ASDisplayNode alloc] initWithViewBlock:^UIView * _Nonnull{ return [[UIView alloc] init]; }]; @@ -2110,7 +2068,7 @@ - (void)testThatSubnodeGetsInterfaceStateSetIfRasterized { ASTestDisplayNode *node = [[ASTestDisplayNode alloc] init]; node.debugName = @"Node"; - node.shouldRasterizeDescendants = YES; + [node enableSubtreeRasterization]; ASTestDisplayNode *subnode = [[ASTestDisplayNode alloc] init]; subnode.debugName = @"Subnode";