Small changes required by the coming layout debugger (#337)

* Small changes required by the layout debugger
- `ASDisplayNode` can be told to not flatten its layout immediately but later on. The unflattened layout is also stored in a separate property. It's needed for inspecting not only display nodes but also layout specs used to compute a layout tree.
- `ASLayout` can be told to always retain its sublayout elements. This is needed especially for layout specs since they are usually not retained after an ASLayout was computed.

* Update CHANGELOG

* Address comments
This commit is contained in:
Huy Nguyen 2017-06-08 10:47:50 -07:00 committed by GitHub
parent 13c467b2f4
commit 05e9bdd092
8 changed files with 87 additions and 5 deletions

View File

@ -34,4 +34,5 @@
- [Fix] Fix a major regression in our image node contents caching. [Adlai Holler](https://github.com/Adlai-Holler) [#287](https://github.com/TextureGroup/Texture/pull/287) - [Fix] Fix a major regression in our image node contents caching. [Adlai Holler](https://github.com/Adlai-Holler) [#287](https://github.com/TextureGroup/Texture/pull/287)
- [Fix] Fixed a bug where ASVideoNodeDelegate error reporting callback would crash an app because of not responding to selector. [Sergey Petrachkov](https://github.com/Petrachkov) [#291](https://github.com/TextureGroup/Texture/issues/291) - [Fix] Fixed a bug where ASVideoNodeDelegate error reporting callback would crash an app because of not responding to selector. [Sergey Petrachkov](https://github.com/Petrachkov) [#291](https://github.com/TextureGroup/Texture/issues/291)
- [IGListKit] Add IGListKit headers to public section of Xcode project [Michael Schneider](https://github.com/maicki)[#286](https://github.com/TextureGroup/Texture/pull/286) - [IGListKit] Add IGListKit headers to public section of Xcode project [Michael Schneider](https://github.com/maicki)[#286](https://github.com/TextureGroup/Texture/pull/286)
- [Layout] Ensure -layout and -layoutDidFinish are called only if a node is loaded. [Huy Nguyen](https://github.com/nguyenhuy) [#285](https://github.com/TextureGroup/Texture/pull/285) - [Layout] Ensure -layout and -layoutDidFinish are called only if a node is loaded. [Huy Nguyen](https://github.com/nguyenhuy) [#285](https://github.com/TextureGroup/Texture/pull/285)
- [Layout Debugger] Small changes needed for the coming layout debugger [Huy Nguyen](https://github.com/nguyenhuy) [#337](https://github.com/TextureGroup/Texture/pull/337)

View File

@ -911,6 +911,12 @@ ASPrimitiveTraitCollectionDeprecatedImplementation
ASDisplayNodeAssertTrue(displayNodeLayout->layout.size.width >= 0.0); ASDisplayNodeAssertTrue(displayNodeLayout->layout.size.width >= 0.0);
ASDisplayNodeAssertTrue(displayNodeLayout->layout.size.height >= 0.0); ASDisplayNodeAssertTrue(displayNodeLayout->layout.size.height >= 0.0);
// Flatten the layout if it wasn't done before (@see -calculateLayoutThatFits:).
if ([ASDisplayNode shouldStoreUnflattenedLayouts]) {
_unflattenedLayout = displayNodeLayout->layout;
displayNodeLayout->layout = [_unflattenedLayout filteredNodeLayoutTree];
}
_calculatedDisplayNodeLayout = displayNodeLayout; _calculatedDisplayNodeLayout = displayNodeLayout;
} }

View File

@ -553,6 +553,30 @@ extern NSInteger const ASDefaultDrawingPriority;
*/ */
@interface ASDisplayNode (Debugging) <ASDebugNameProvider> @interface ASDisplayNode (Debugging) <ASDebugNameProvider>
/**
* Set to YES to tell all ASDisplayNode instances to store their unflattened layouts.
*
* The layout can be accessed via `-unflattenedCalculatedLayout`.
*
* Flattened layouts use less memory and are faster to lookup. On the other hand, unflattened layouts are useful for debugging
* because they preserve original information.
*/
+ (void)setShouldStoreUnflattenedLayouts:(BOOL)shouldStore;
/**
* Whether or not ASDisplayNode instances should store their unflattened layouts.
*
* The layout can be accessed via `-unflattenedCalculatedLayout`.
*
* Flattened layouts use less memory and are faster to lookup. On the other hand, unflattened layouts are useful for debugging
* because they preserve original information.
*
* Defaults to NO.
*/
+ (BOOL)shouldStoreUnflattenedLayouts;
@property (nonatomic, strong, readonly, nullable) ASLayout *unflattenedCalculatedLayout;
/** /**
* @abstract Return a description of the node hierarchy. * @abstract Return a description of the node hierarchy.
* *

View File

@ -82,6 +82,7 @@ NSInteger const ASDefaultDrawingPriority = ASDefaultTransactionPriority;
@synthesize threadSafeBounds = _threadSafeBounds; @synthesize threadSafeBounds = _threadSafeBounds;
static BOOL suppressesInvalidCollectionUpdateExceptions = NO; static BOOL suppressesInvalidCollectionUpdateExceptions = NO;
static std::atomic_bool storesUnflattenedLayouts = ATOMIC_VAR_INIT(NO);
+ (BOOL)suppressesInvalidCollectionUpdateExceptions + (BOOL)suppressesInvalidCollectionUpdateExceptions
{ {
@ -887,6 +888,8 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
if (_pendingDisplayNodeLayout != nullptr) { if (_pendingDisplayNodeLayout != nullptr) {
_pendingDisplayNodeLayout->invalidate(); _pendingDisplayNodeLayout->invalidate();
} }
_unflattenedLayout = nil;
#if YOGA_TREE_CONTIGUOUS #if YOGA_TREE_CONTIGUOUS
[self invalidateCalculatedYogaLayout]; [self invalidateCalculatedYogaLayout];
@ -1013,7 +1016,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
// Manually propagate the trait collection here so that any layoutSpec children of layoutSpec will get a traitCollection // Manually propagate the trait collection here so that any layoutSpec children of layoutSpec will get a traitCollection
{ {
ASDN::SumScopeTimer t(_layoutSpecTotalTime, measureLayoutSpec); ASDN::SumScopeTimer t(_layoutSpecTotalTime, measureLayoutSpec);
ASTraitCollectionPropagateDown(layoutElement, self.primitiveTraitCollection); ASTraitCollectionPropagateDown(layoutElement, self.primitiveTraitCollection);
} }
@ -1038,7 +1040,13 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
} }
ASDisplayNodeLogEvent(self, @"computedLayout: %@", layout); ASDisplayNodeLogEvent(self, @"computedLayout: %@", layout);
return [layout filteredNodeLayoutTree]; // Return the (original) unflattened layout if it needs to be stored. The layout will be flattened later on (@see _locked_setCalculatedDisplayNodeLayout:).
// Otherwise, flatten it right away.
if (! [ASDisplayNode shouldStoreUnflattenedLayouts]) {
layout = [layout filteredNodeLayoutTree];
}
return layout;
} }
- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
@ -3286,6 +3294,22 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) {
@implementation ASDisplayNode (Debugging) @implementation ASDisplayNode (Debugging)
+ (void)setShouldStoreUnflattenedLayouts:(BOOL)shouldStore
{
storesUnflattenedLayouts.store(shouldStore);
}
+ (BOOL)shouldStoreUnflattenedLayouts
{
return storesUnflattenedLayouts.load();
}
- (ASLayout *)unflattenedCalculatedLayout
{
ASDN::MutexLocker l(__instanceLock__);
return _unflattenedLayout;
}
- (NSString *)displayNodeRecursiveDescription - (NSString *)displayNodeRecursiveDescription
{ {
return [self _recursiveDescriptionHelperWithIndent:@""]; return [self _recursiveDescriptionHelperWithIndent:@""];

View File

@ -98,7 +98,7 @@ extern ASDisplayNode * _Nullable ASLayerToDisplayNode(CALayer * _Nullable layer)
extern ASDisplayNode * _Nullable ASViewToDisplayNode(UIView * _Nullable view) AS_WARN_UNUSED_RESULT; extern ASDisplayNode * _Nullable ASViewToDisplayNode(UIView * _Nullable view) AS_WARN_UNUSED_RESULT;
/** /**
Given a node, returns the root of the node heirarchy (where supernode == nil) Given a node, returns the root of the node hierarchy (where supernode == nil)
*/ */
extern ASDisplayNode *ASDisplayNodeUltimateParentOfNode(ASDisplayNode *node) AS_WARN_UNUSED_RESULT; extern ASDisplayNode *ASDisplayNodeUltimateParentOfNode(ASDisplayNode *node) AS_WARN_UNUSED_RESULT;

View File

@ -176,6 +176,18 @@ ASDISPLAYNODE_EXTERN_C_END
@interface ASLayout (Debugging) @interface ASLayout (Debugging)
/**
* Set to YES to tell all ASLayout instances to retain their sublayout elements. Defaults to NO.
* Can be overridden at instance level.
*/
+ (void)setShouldRetainSublayoutLayoutElements:(BOOL)shouldRetain;
/**
* Whether or not ASLayout instances should retain their sublayout elements.
* Can be overridden at instance level.
*/
+ (BOOL)shouldRetainSublayoutLayoutElements;
/** /**
* Recrusively output the description of the layout tree. * Recrusively output the description of the layout tree.
*/ */

View File

@ -76,6 +76,18 @@ static inline NSString * descriptionIndents(NSUInteger indents)
@dynamic frame, type; @dynamic frame, type;
static std::atomic_bool static_retainsSublayoutLayoutElements = ATOMIC_VAR_INIT(NO);
+ (void)setShouldRetainSublayoutLayoutElements:(BOOL)shouldRetain
{
static_retainsSublayoutLayoutElements.store(shouldRetain);
}
+ (BOOL)shouldRetainSublayoutLayoutElements
{
return static_retainsSublayoutLayoutElements.load();
}
- (instancetype)initWithLayoutElement:(id<ASLayoutElement>)layoutElement - (instancetype)initWithLayoutElement:(id<ASLayoutElement>)layoutElement
size:(CGSize)size size:(CGSize)size
position:(CGPoint)position position:(CGPoint)position
@ -118,7 +130,7 @@ static inline NSString * descriptionIndents(NSUInteger indents)
} }
_flattened = NO; _flattened = NO;
_retainSublayoutLayoutElements = NO; self.retainSublayoutLayoutElements = [ASLayout shouldRetainSublayoutLayoutElements];
} }
return self; return self;

View File

@ -211,6 +211,9 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
NSString *_debugName; NSString *_debugName;
#pragma mark - ASDisplayNode (Debugging)
ASLayout *_unflattenedLayout;
#if TIME_DISPLAYNODE_OPS #if TIME_DISPLAYNODE_OPS
@public @public
NSTimeInterval _debugTimeToCreateView; NSTimeInterval _debugTimeToCreateView;