From 4e757f0969ff057207edca8ce5e9835508e0657a Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Wed, 30 Mar 2016 22:02:17 -0700 Subject: [PATCH] General improvements - Refactor naming of ASEnvironmentCollection to ASEnvironmentState - Remove struct pointers - Move ASEnvironmentStatePropagation to a enum class - Move merge functions to pure functions - Move ASLayoutOptionsForwarding and ASLayoutableExtensibility into ASLayoutSpec and ASDisplayNode - Remove ASLayoutableSetValuesForLayoutable and move into explicit classes (ASDisplayNode, ASTextNode) --- AsyncDisplayKit/ASDisplayNode.mm | 62 ++---- AsyncDisplayKit/ASTextNode.mm | 6 + AsyncDisplayKit/Details/ASEnvironment.h | 22 +- AsyncDisplayKit/Details/ASEnvironment.m | 4 +- AsyncDisplayKit/Layout/ASLayoutSpec.h | 2 + AsyncDisplayKit/Layout/ASLayoutSpec.mm | 56 ++--- AsyncDisplayKit/Layout/ASLayoutable.mm | 180 ---------------- AsyncDisplayKit/Layout/ASLayoutablePrivate.h | 200 +++++++++++++++++- AsyncDisplayKit/Layout/ASStackLayoutSpec.mm | 4 +- AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm | 4 +- .../Private/ASDisplayNodeInternal.h | 2 +- .../Private/ASEnvironmentInternal.h | 18 +- .../Private/ASEnvironmentInternal.mm | 30 +-- 13 files changed, 281 insertions(+), 309 deletions(-) diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index d6fc281d17..3bfe80760c 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -253,8 +253,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) _displaySentinel = [[ASSentinel alloc] init]; _preferredFrameSize = CGSizeZero; - _environmentCollection = ASEnvironmentCollectionCreate(); - ASLayoutableSetValuesForLayoutable(self); + _environmentState = ASEnvironmentStateCreate(); } - (id)init @@ -1703,6 +1702,10 @@ static NSInteger incrementIfFound(NSInteger i) { [self exitHierarchyState:stateToEnterOrExit]; } } + + if ([newSupernode supportsUpwardPropagation]) { + ASEnvironmentStatePropagateUp(newSupernode, self.environmentState.layoutOptionsState); + } } // Track that a node will be displayed as part of the current node hierarchy. @@ -1857,8 +1860,8 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) ASDN::MutexLocker l(_propertyLock); if (_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) { ASLayoutSpec *layoutSpec = [self layoutSpecThatFits:constrainedSize]; - layoutSpec.isMutable = NO; layoutSpec.parent = self; + layoutSpec.isMutable = NO; ASLayout *layout = [layoutSpec measureWithSizeRange:constrainedSize]; // Make sure layoutableObject of the root layout is `self`, so that the flattened layout will be structurally correct. if (layout.layoutableObject != self) { @@ -1922,6 +1925,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock) ASDN::MutexLocker l(_propertyLock); if (! CGSizeEqualToSize(_preferredFrameSize, preferredFrameSize)) { _preferredFrameSize = preferredFrameSize; + self.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(_preferredFrameSize), ASRelativeSizeMakeWithCGSize(_preferredFrameSize)); [self invalidateCalculatedLayout]; } } @@ -2672,9 +2676,14 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; #pragma mark - ASEnvironment -- (ASEnvironmentCollection *)environmentCollection +- (ASEnvironmentState)environmentState { - return &_environmentCollection; + return _environmentState; +} + +- (void)setEnvironmentState:(ASEnvironmentState)environmentState +{ + _environmentState = environmentState; } - (ASDisplayNode *)parent @@ -2682,53 +2691,18 @@ static const char *ASDisplayNodeDrawingPriorityKey = "ASDrawingPriority"; return self.supernode; } -- (void)setParent:(ASDisplayNode *)parent -{ - [self __setSupernode:parent]; -} - - (NSArray *)children { return self.subnodes; } -- (BOOL)supportsMultipleChildren +- (BOOL)supportsUpwardPropagation { - return NO; + return YES; } - -#pragma mark - ASLayoutableExtensibility - -- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx -{ - _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value); -} - -- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx -{ - return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx); -} - -- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx -{ - _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value); -} - -- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx -{ - return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx); -} - -- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx -{ - _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value); -} - -- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx -{ - return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx); -} +ASEnvironmentLayoutOptionsForwarding +ASEnvironmentLayoutExtensibilityForwarding #if TARGET_OS_TV diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index 8c59739588..504b3fae98 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -364,6 +364,12 @@ static NSArray *DefaultLinkAttributeNames = @[ NSLinkAttributeName ]; } _attributedString = ASCleanseAttributedStringOfCoreTextAttributes(attributedString); + + if (_attributedString.length > 0) { + CGFloat screenScale = ASScreenScale(); + self.ascender = round([[_attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; + self.descender = round([[_attributedString attribute:NSFontAttributeName atIndex:_attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; + } // Sync the truncation string with attributes from the updated _attributedString // Without this, the size calculation of the text with truncation applied will diff --git a/AsyncDisplayKit/Details/ASEnvironment.h b/AsyncDisplayKit/Details/ASEnvironment.h index 7f1f0f8863..43e21bda09 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.h +++ b/AsyncDisplayKit/Details/ASEnvironment.h @@ -62,13 +62,13 @@ typedef struct ASEnvironmentHierarchyState { extern ASEnvironmentHierarchyState ASEnvironmentHierarchyStateCreate(); -#pragma mark - ASEnvironmentCollection +#pragma mark - ASEnvironmentState -typedef struct ASEnvironmentCollection { +typedef struct ASEnvironmentState { struct ASEnvironmentHierarchyState hierarchyState; struct ASEnvironmentLayoutOptionsState layoutOptionsState; -} ASEnvironmentCollection; -extern ASEnvironmentCollection ASEnvironmentCollectionCreate(); +} ASEnvironmentState; +extern ASEnvironmentState ASEnvironmentStateCreate(); ASDISPLAYNODE_EXTERN_C_END @@ -77,26 +77,22 @@ ASDISPLAYNODE_EXTERN_C_END /** * ASEnvironment allows objects that conform to the ASEnvironment protocol to be able to propagate specific States - * defined in an ASEnvironmentCollection up and down the ASEnvironment tree. To be able to define how merges of + * defined in an ASEnvironmentState up and down the ASEnvironment tree. To be able to define how merges of * States should happen, specific merge functions can be provided */ @protocol ASEnvironment /// The environment collection of an object which class conforms to the ASEnvironment protocol -- (ASEnvironmentCollection *)environmentCollection; +- (ASEnvironmentState)environmentState; +- (void)setEnvironmentState:(ASEnvironmentState)environmentState; /// Returns the parent of an object which class conforms to the ASEnvironment protocol -- (id)parent; - -/// Set the parent of an object which class conforms to the ASEnvironment protocol -- (void)setParent:(id)parent; +- (id _Nullable)parent; /// Returns all children of an object which class conforms to the ASEnvironment protocol - (NSArray> *)children; -// TODO: ASEnvironment: Find a better name. As in ASDisplayNode this returns NO which in theory is wrong as as -// it supports multiple subnodes -- (BOOL)supportsMultipleChildren; +- (BOOL)supportsUpwardPropagation; @end diff --git a/AsyncDisplayKit/Details/ASEnvironment.m b/AsyncDisplayKit/Details/ASEnvironment.m index e08795a7b3..5cbe4d95c1 100644 --- a/AsyncDisplayKit/Details/ASEnvironment.m +++ b/AsyncDisplayKit/Details/ASEnvironment.m @@ -32,9 +32,9 @@ ASEnvironmentHierarchyState ASEnvironmentHierarchyStateCreate() }; } -ASEnvironmentCollection ASEnvironmentCollectionCreate() +ASEnvironmentState ASEnvironmentStateCreate() { - return (ASEnvironmentCollection) { + return (ASEnvironmentState) { .hierarchyState = ASEnvironmentHierarchyStateCreate(), .layoutOptionsState = ASEnvironmentLayoutOptionsStateCreate() }; diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.h b/AsyncDisplayKit/Layout/ASLayoutSpec.h index 991c4224a7..dcb9b33246 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.h +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.h @@ -25,6 +25,8 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init; +@property (nullable, nonatomic, weak) id parent; + /** * Adds a child to this layout spec using a default identifier. * diff --git a/AsyncDisplayKit/Layout/ASLayoutSpec.mm b/AsyncDisplayKit/Layout/ASLayoutSpec.mm index 77abc59671..7c7598b90a 100644 --- a/AsyncDisplayKit/Layout/ASLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASLayoutSpec.mm @@ -25,9 +25,9 @@ static NSString * const kDefaultChildKey = @"kDefaultChildKey"; static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; @interface ASLayoutSpec() { - ASEnvironmentCollection _environmentCollection; + ASEnvironmentState _environmentState; + ASDN::RecursiveMutex _propertyLock; } -@property (nonatomic, weak) id parent; @property (nonatomic, strong) NSMutableDictionary *layoutChildren; @end @@ -44,8 +44,7 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; return nil; } _isMutable = YES; - _environmentCollection = ASEnvironmentCollectionCreate(); - ASLayoutableSetValuesForLayoutable(self); + _environmentState = ASEnvironmentStateCreate(); return self; } @@ -83,7 +82,9 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; id finalLayoutable = [child finalLayoutable]; if (finalLayoutable != child) { // Copy layout options - finalLayoutable.environmentCollection->layoutOptionsState = child.environmentCollection->layoutOptionsState; + ASEnvironmentState environmentState = finalLayoutable.environmentState; + environmentState.layoutOptionsState = child.environmentState.layoutOptionsState; + finalLayoutable.environmentState = environmentState; return finalLayoutable; } } @@ -102,8 +103,8 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; { _parent = parent; - if (![parent supportsMultipleChildren]) { - ASEnvironmentStatePropagateUp(parent, self.environmentCollection->layoutOptionsState); + if ([parent supportsUpwardPropagation]) { + ASEnvironmentStatePropagateUp(parent, _environmentState.layoutOptionsState); } } @@ -148,48 +149,23 @@ static NSString * const kDefaultChildrenKey = @"kDefaultChildrenKey"; #pragma mark - ASEnvironment -- (ASEnvironmentCollection *)environmentCollection +- (ASEnvironmentState)environmentState { - return &_environmentCollection; + return _environmentState; } -- (BOOL)supportsMultipleChildren +- (void)setEnvironmentState:(ASEnvironmentState)environmentState { - return NO; + _environmentState = environmentState; } - -#pragma mark - ASLayoutableExtensibility - -- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx +- (BOOL)supportsUpwardPropagation { - _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value); + return YES; } -- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx -{ - return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx); -} - -- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx -{ - _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value); -} - -- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx -{ - return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx); -} - -- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx -{ - _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value); -} - -- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx -{ - return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx); -} +ASEnvironmentLayoutOptionsForwarding +ASEnvironmentLayoutExtensibilityForwarding @end diff --git a/AsyncDisplayKit/Layout/ASLayoutable.mm b/AsyncDisplayKit/Layout/ASLayoutable.mm index c38586ff5a..23fd59e9ff 100644 --- a/AsyncDisplayKit/Layout/ASLayoutable.mm +++ b/AsyncDisplayKit/Layout/ASLayoutable.mm @@ -81,183 +81,3 @@ void ASLayoutableClearCurrentContext() ASDN::StaticMutexLocker l(_layoutableContextLock); layoutableContextMap.erase(key); } - -/** - * Given an id, set up layout options that are intrinsically defined by the layoutable. - * - * While this could be done in the layoutable object itself, moving the logic into this helper function - * allows a custom spec to set up defaults without needing to alter the layoutable itself. For example, - * image you were creating a custom baseline spec that needed ascender/descender. To assign values automatically - * when a text node's attribute string is set, you would need to subclass ASTextNode and assign the values in the - * override of setAttributeString. However, assigning the defaults via this function allows you to create a - * custom spec without the need to create a subclass of ASTextNode. - * - * @param layoutable The layoutable object to inspect for default intrinsic layout option values - */ -void ASLayoutableSetValuesForLayoutable(id layoutable) -{ - //ASDN::MutexLocker l(_propertyLock); - if ([layoutable isKindOfClass:[ASDisplayNode class]]) { - ASDisplayNode *displayNode = (ASDisplayNode *)layoutable; - displayNode.sizeRange = ASRelativeSizeRangeMake(ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize), ASRelativeSizeMakeWithCGSize(displayNode.preferredFrameSize)); - - if ([layoutable isKindOfClass:[ASTextNode class]]) { - ASTextNode *textNode = (ASTextNode *)layoutable; - NSAttributedString *attributedString = textNode.attributedString; - if (attributedString.length > 0) { - CGFloat screenScale = ASScreenScale(); - textNode.ascender = round([[attributedString attribute:NSFontAttributeName atIndex:0 effectiveRange:NULL] ascender] * screenScale)/screenScale; - textNode.descender = round([[attributedString attribute:NSFontAttributeName atIndex:attributedString.length - 1 effectiveRange:NULL] descender] * screenScale)/screenScale; - } - } - - } -} - - -#pragma mark - ASLayoutOptionsForwarding - -/** - * Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties - * in ASLayoutable that are used when a node or spec is used in a layout spec. - * These properties are provided for convenience, as they are forwards to the node or spec's - * properties. Instead of duplicating the property forwarding in both classes, we - * create a define that allows us to easily implement the forwards in one place. - * - * If you create a custom layout spec, we recommend this stragety if you decide to extend - * ASDisplayNode and ASLayoutSpec to provide convenience properties for any options that your - * layoutSpec may require. - */ - -#define ASEnvironmentLayoutOptionsForwarding \ -- (ASEnvironmentLayoutOptionsState *)layoutOptionsState\ -{\ - return &(self.environmentCollection->layoutOptionsState);\ -}\ -- (void)propagateUpLayoutOptionsState\ -{\ - id parent = [self parent];\ - if (![parent supportsMultipleChildren]) {\ - ASEnvironmentStatePropagateUp(parent, self.environmentCollection->layoutOptionsState);\ - }\ -}\ -\ -- (CGFloat)spacingAfter\ -{\ - return self.layoutOptionsState->spacingAfter;\ -}\ -\ -- (void)setSpacingAfter:(CGFloat)spacingAfter\ -{\ - self.layoutOptionsState->spacingAfter = spacingAfter;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (CGFloat)spacingBefore\ -{\ - return self.layoutOptionsState->spacingBefore;\ -}\ -\ -- (void)setSpacingBefore:(CGFloat)spacingBefore\ -{\ - self.layoutOptionsState->spacingBefore = spacingBefore;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (BOOL)flexGrow\ -{\ - return self.layoutOptionsState->flexGrow;\ -}\ -\ -- (void)setFlexGrow:(BOOL)flexGrow\ -{\ - self.layoutOptionsState->flexGrow = flexGrow;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (BOOL)flexShrink\ -{\ - return self.layoutOptionsState->flexShrink;\ -}\ -\ -- (void)setFlexShrink:(BOOL)flexShrink\ -{\ - self.layoutOptionsState->flexShrink = flexShrink;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (ASRelativeDimension)flexBasis\ -{\ - return self.layoutOptionsState->flexBasis;\ -}\ -\ -- (void)setFlexBasis:(ASRelativeDimension)flexBasis\ -{\ - self.layoutOptionsState->flexBasis = flexBasis;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (ASStackLayoutAlignSelf)alignSelf\ -{\ - return self.layoutOptionsState->alignSelf;\ -}\ -\ -- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf\ -{\ - self.layoutOptionsState->alignSelf = alignSelf;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (CGFloat)ascender\ -{\ - return self.layoutOptionsState->ascender;\ -}\ -\ -- (void)setAscender:(CGFloat)ascender\ -{\ - self.layoutOptionsState->ascender = ascender;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (CGFloat)descender\ -{\ - return self.layoutOptionsState->descender;\ -}\ -\ -- (void)setDescender:(CGFloat)descender\ -{\ - self.layoutOptionsState->descender = descender;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (ASRelativeSizeRange)sizeRange\ -{\ - return self.layoutOptionsState->sizeRange;\ -}\ -\ -- (void)setSizeRange:(ASRelativeSizeRange)sizeRange\ -{\ - self.layoutOptionsState->sizeRange = sizeRange;\ - [self propagateUpLayoutOptionsState];\ -}\ -\ -- (CGPoint)layoutPosition\ -{\ - return self.layoutOptionsState->layoutPosition;\ -}\ -\ -- (void)setLayoutPosition:(CGPoint)layoutPosition\ -{\ - self.layoutOptionsState->layoutPosition = layoutPosition;\ - [self propagateUpLayoutOptionsState];\ -}\ - - -@implementation ASDisplayNode(ASLayoutOptionsForwarding) -ASEnvironmentLayoutOptionsForwarding -@end - -@implementation ASLayoutSpec(ASLayoutOptionsForwarding) -ASEnvironmentLayoutOptionsForwarding -@end - diff --git a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h index e4aa37e8db..d18d0b7419 100644 --- a/AsyncDisplayKit/Layout/ASLayoutablePrivate.h +++ b/AsyncDisplayKit/Layout/ASLayoutablePrivate.h @@ -34,8 +34,6 @@ extern struct ASLayoutableContext ASLayoutableGetCurrentContext(); extern void ASLayoutableClearCurrentContext(); -extern void ASLayoutableSetValuesForLayoutable(id layoutable); - /** * The base protocol for ASLayoutable. Generally the methods/properties in this class do not need to be * called by the end user and are only called internally. However, there may be a case where the methods are useful. @@ -62,3 +60,201 @@ extern void ASLayoutableSetValuesForLayoutable(id layoutable); @property (nonatomic, assign) BOOL isFinalLayoutable; @end + + +#pragma mark - ASLayoutOptionsForwarding + +/** + * Both an ASDisplayNode and an ASLayoutSpec conform to ASLayoutable. There are several properties + * in ASLayoutable that are used when a node or spec is used in a layout spec. + * These properties are provided for convenience, as they are forwards to the node or spec's + * properties. Instead of duplicating the property forwarding in both classes, we + * create a define that allows us to easily implement the forwards in one place. + * + * If you create a custom layout spec, we recommend this stragety if you decide to extend + * ASDisplayNode and ASLayoutSpec to provide convenience properties for any options that your + * layoutSpec may require. + */ + +#define ASEnvironmentLayoutOptionsForwarding \ +- (void)propagateUpLayoutOptionsState\ +{\ + id parent = [self parent];\ + if ([parent supportsUpwardPropagation]) {\ + ASEnvironmentStatePropagateUp(parent, _environmentState.layoutOptionsState);\ + }\ +}\ +\ +- (CGFloat)spacingAfter\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.spacingAfter;\ +}\ +\ +- (void)setSpacingAfter:(CGFloat)spacingAfter\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.spacingAfter = spacingAfter;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (CGFloat)spacingBefore\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.spacingBefore;\ +}\ +\ +- (void)setSpacingBefore:(CGFloat)spacingBefore\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.spacingBefore = spacingBefore;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (BOOL)flexGrow\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.flexGrow;\ +}\ +\ +- (void)setFlexGrow:(BOOL)flexGrow\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.flexGrow = flexGrow;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (BOOL)flexShrink\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.flexShrink;\ +}\ +\ +- (void)setFlexShrink:(BOOL)flexShrink\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.flexShrink = flexShrink;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (ASRelativeDimension)flexBasis\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.flexBasis;\ +}\ +\ +- (void)setFlexBasis:(ASRelativeDimension)flexBasis\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.flexBasis = flexBasis;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (ASStackLayoutAlignSelf)alignSelf\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.alignSelf;\ +}\ +\ +- (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.alignSelf = alignSelf;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (CGFloat)ascender\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.ascender;\ +}\ +\ +- (void)setAscender:(CGFloat)ascender\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.ascender = ascender;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (CGFloat)descender\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.descender;\ +}\ +\ +- (void)setDescender:(CGFloat)descender\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.descender = descender;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (ASRelativeSizeRange)sizeRange\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.sizeRange;\ +}\ +\ +- (void)setSizeRange:(ASRelativeSizeRange)sizeRange\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.sizeRange = sizeRange;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ +\ +- (CGPoint)layoutPosition\ +{\ + ASDN::MutexLocker l(_propertyLock);\ + return _environmentState.layoutOptionsState.layoutPosition;\ +}\ +\ +- (void)setLayoutPosition:(CGPoint)layoutPosition\ +{\ + _propertyLock.lock();\ + _environmentState.layoutOptionsState.layoutPosition = layoutPosition;\ + [self propagateUpLayoutOptionsState];\ + _propertyLock.unlock();\ +}\ + + +#pragma mark - ASLayoutableExtensibility + +#define ASEnvironmentLayoutExtensibilityForwarding \ +- (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx\ +{\ + _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(self, idx, value);\ +}\ +\ +- (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx\ +{\ + return _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(self, idx);\ +}\ +\ +- (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx\ +{\ + _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(self, idx, value);\ +}\ +\ +- (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx\ +{\ + return _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(self, idx);\ +}\ +\ +- (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx\ +{\ + _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(self, idx, value);\ +}\ +\ +- (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx\ +{\ + return _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(self, idx);\ +}\ diff --git a/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm index 6af951ec86..26b6d449c7 100644 --- a/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStackLayoutSpec.mm @@ -200,9 +200,9 @@ @implementation ASStackLayoutSpec (ASEnvironment) -- (BOOL)supportsMultipleChildren +- (BOOL)supportsUpwardPropagation { - return YES; + return NO; } @end diff --git a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm index 388b06aa02..a727376a57 100644 --- a/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm +++ b/AsyncDisplayKit/Layout/ASStaticLayoutSpec.mm @@ -87,9 +87,9 @@ @implementation ASStaticLayoutSpec (ASEnvironment) -- (BOOL)supportsMultipleChildren +- (BOOL)supportsUpwardPropagation { - return YES; + return NO; } @end diff --git a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h index f632f64ae0..e8930b9865 100644 --- a/AsyncDisplayKit/Private/ASDisplayNodeInternal.h +++ b/AsyncDisplayKit/Private/ASDisplayNodeInternal.h @@ -97,7 +97,7 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo // This is the desired contentsScale, not the scale at which the layer's contents should be displayed CGFloat _contentsScaleForDisplay; - ASEnvironmentCollection _environmentCollection; + ASEnvironmentState _environmentState; ASLayout *_layout; ASSizeRange _constrainedSize; diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.h b/AsyncDisplayKit/Private/ASEnvironmentInternal.h index 877508330a..9cf9a11e55 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.h +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.h @@ -12,7 +12,7 @@ #pragma once -enum ASEnvironmentStatePropagation { DOWN, UP }; +enum class ASEnvironmentStatePropagation { DOWN, UP }; #pragma mark - Set and get extensible values for layout options @@ -36,34 +36,34 @@ void ASEnvironmentPerformBlockOnObjectAndParents(id object, void( #pragma mark - Merging static const struct ASEnvironmentLayoutOptionsState ASEnvironmentDefaultLayoutOptionsState = {}; -void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentLayoutOptionsState& state, ASEnvironmentStatePropagation propagation); +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentLayoutOptionsState state, ASEnvironmentStatePropagation propagation); static const struct ASEnvironmentHierarchyState ASEnvironmentDefaultHierarchyState = {}; -void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentHierarchyState& state, ASEnvironmentStatePropagation propagation); +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentHierarchyState state, ASEnvironmentStatePropagation propagation); #pragma mark - Propagation template -void ASEnvironmentStatePropagateDown(id object, ASEnvironmentStateType& state) { +void ASEnvironmentStatePropagateDown(id object, ASEnvironmentStateType state) { ASEnvironmentPerformBlockOnObjectAndChildren(object, ^(id node) { - ASEnvironmentMergeObjectAndState(object, state, DOWN); + object.environmentState = ASEnvironmentMergeObjectAndState(object.environmentState, state, ASEnvironmentStatePropagation::DOWN); }); } template -void ASEnvironmentStatePropagateUp(id object, ASEnvironmentStateType& state) { +void ASEnvironmentStatePropagateUp(id object, ASEnvironmentStateType state) { ASEnvironmentPerformBlockOnObjectAndParents(object, ^(id node) { - ASEnvironmentMergeObjectAndState(object, state, UP); + object.environmentState = ASEnvironmentMergeObjectAndState(object.environmentState, state, ASEnvironmentStatePropagation::UP); }); } template void ASEnvironmentStateApply(id object, ASEnvironmentStateType& state, ASEnvironmentStatePropagation propagate) { - if (propagate == DOWN) { + if (propagate == ASEnvironmentStatePropagation::DOWN) { ASEnvironmentStatePropagateUp(object, state); - } else if (propagate == UP) { + } else if (propagate == ASEnvironmentStatePropagation::UP) { ASEnvironmentStatePropagateDown(object, state); } } diff --git a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm index 2ab5ed21a0..4bec0df268 100644 --- a/AsyncDisplayKit/Private/ASEnvironmentInternal.mm +++ b/AsyncDisplayKit/Private/ASEnvironmentInternal.mm @@ -52,65 +52,66 @@ void _ASEnvironmentLayoutOptionsExtensionSetBoolAtIndex(id object { NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Setting index outside of max bool extensions space"); - ASEnvironmentStateExtensions extension = object.environmentCollection->layoutOptionsState._extensions; + ASEnvironmentStateExtensions extension = object.environmentState.layoutOptionsState._extensions; extension.boolExtensions[idx] = value; - object.environmentCollection->layoutOptionsState._extensions = extension; + object.environmentState.layoutOptionsState._extensions = extension; } BOOL _ASEnvironmentLayoutOptionsExtensionGetBoolAtIndex(id object, int idx) { NSCAssert(idx < kMaxEnvironmentStateBoolExtensions, @"Accessing index outside of max bool extensions space"); - return object.environmentCollection->layoutOptionsState._extensions.boolExtensions[idx]; + return object.environmentState.layoutOptionsState._extensions.boolExtensions[idx]; } void _ASEnvironmentLayoutOptionsExtensionSetIntegerAtIndex(id object, int idx, NSInteger value) { NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Setting index outside of max integer extensions space"); - ASEnvironmentStateExtensions extension = object.environmentCollection->layoutOptionsState._extensions; + ASEnvironmentStateExtensions extension = object.environmentState.layoutOptionsState._extensions; extension.integerExtensions[idx] = value; - object.environmentCollection->layoutOptionsState._extensions = extension; + object.environmentState.layoutOptionsState._extensions = extension; } NSInteger _ASEnvironmentLayoutOptionsExtensionGetIntegerAtIndex(id object, int idx) { NSCAssert(idx < kMaxEnvironmentStateIntegerExtensions, @"Accessing index outside of max integer extensions space"); - return object.environmentCollection->layoutOptionsState._extensions.integerExtensions[idx]; + return object.environmentState.layoutOptionsState._extensions.integerExtensions[idx]; } void _ASEnvironmentLayoutOptionsExtensionSetEdgeInsetsAtIndex(id object, int idx, UIEdgeInsets value) { NSCAssert(idx < kMaxEnvironmentStateEdgeInsetExtensions, @"Setting index outside of max edge insets extensions space"); - ASEnvironmentStateExtensions extension = object.environmentCollection->layoutOptionsState._extensions; + ASEnvironmentStateExtensions extension = object.environmentState.layoutOptionsState._extensions; extension.edgeInsetsExtensions[idx] = value; - object.environmentCollection->layoutOptionsState._extensions = extension; + object.environmentState.layoutOptionsState._extensions = extension; } UIEdgeInsets _ASEnvironmentLayoutOptionsExtensionGetEdgeInsetsAtIndex(id object, int idx) { NSCAssert(idx < kMaxEnvironmentStateEdgeInsetExtensions, @"Accessing index outside of max edge insets extensions space"); - return object.environmentCollection->layoutOptionsState._extensions.edgeInsetsExtensions[idx]; + return object.environmentState.layoutOptionsState._extensions.edgeInsetsExtensions[idx]; } #pragma mark - Merging functions for states -void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentHierarchyState& state, ASEnvironmentStatePropagation propagation) { +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentHierarchyState state, ASEnvironmentStatePropagation propagation) { // Merge object and hierarchy state LOG(@"Merge object and state: %@ - ASEnvironmentHierarchyState", object); + return environmentState; } -void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentLayoutOptionsState& state, ASEnvironmentStatePropagation propagation) { +ASEnvironmentState ASEnvironmentMergeObjectAndState(ASEnvironmentState environmentState, ASEnvironmentLayoutOptionsState state, ASEnvironmentStatePropagation propagation) { // Merge object and layout options state LOG(@"Merge object and state: %@ - ASEnvironmentLayoutOptionsState", object); // Support propagate up - if (propagation == UP) { + if (propagation == ASEnvironmentStatePropagation::UP) { // Object is the parent and the state is the state of the child const ASEnvironmentLayoutOptionsState defaultState = ASEnvironmentDefaultLayoutOptionsState; - ASEnvironmentLayoutOptionsState parentState = object.environmentCollection->layoutOptionsState; + ASEnvironmentLayoutOptionsState parentState = environmentState.layoutOptionsState; // For every field check if the parent value is equal to the default than propegate up the child value to // the parent @@ -143,7 +144,8 @@ void ASEnvironmentMergeObjectAndState(id object, ASEnvironmentLay parentState.layoutPosition = defaultState.layoutPosition; } - object.environmentCollection->layoutOptionsState = parentState; + environmentState.layoutOptionsState = parentState; } + return environmentState; }