// // ASLayoutElement.mm // Texture // // Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. // Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved. // Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 // #import #import #import #import #import #import #import #import #include using AS::MutexLocker; #if YOGA #import YOGA_HEADER_PATH #import #endif #pragma mark - ASLayoutElementContext @implementation ASLayoutElementContext - (instancetype)init { if (self = [super init]) { _transitionID = ASLayoutElementContextDefaultTransitionID; } return self; } @end CGFloat const ASLayoutElementParentDimensionUndefined = NAN; CGSize const ASLayoutElementParentSizeUndefined = {ASLayoutElementParentDimensionUndefined, ASLayoutElementParentDimensionUndefined}; int32_t const ASLayoutElementContextInvalidTransitionID = 0; int32_t const ASLayoutElementContextDefaultTransitionID = ASLayoutElementContextInvalidTransitionID + 1; #if AS_TLS_AVAILABLE static _Thread_local __unsafe_unretained ASLayoutElementContext *tls_context; void ASLayoutElementPushContext(ASLayoutElementContext *context) { // NOTE: It would be easy to support nested contexts – just use an NSMutableArray here. ASDisplayNodeCAssertNil(tls_context, @"Nested ASLayoutElementContexts aren't supported."); tls_context = (__bridge ASLayoutElementContext *)(__bridge_retained CFTypeRef)context; } ASLayoutElementContext *ASLayoutElementGetCurrentContext() { // Don't retain here. Caller will retain if it wants to! return tls_context; } void ASLayoutElementPopContext() { ASDisplayNodeCAssertNotNil(tls_context, @"Attempt to pop context when there wasn't a context!"); CFRelease((__bridge CFTypeRef)tls_context); tls_context = nil; } #else static pthread_key_t ASLayoutElementContextKey() { static pthread_key_t k; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ pthread_key_create(&k, NULL); }); return k; } void ASLayoutElementPushContext(ASLayoutElementContext *context) { // NOTE: It would be easy to support nested contexts – just use an NSMutableArray here. ASDisplayNodeCAssertNil(pthread_getspecific(ASLayoutElementContextKey()), @"Nested ASLayoutElementContexts aren't supported."); const auto cfCtx = (__bridge_retained CFTypeRef)context; pthread_setspecific(ASLayoutElementContextKey(), cfCtx); } ASLayoutElementContext *ASLayoutElementGetCurrentContext() { // Don't retain here. Caller will retain if it wants to! const auto ctxPtr = pthread_getspecific(ASLayoutElementContextKey()); return (__bridge ASLayoutElementContext *)ctxPtr; } void ASLayoutElementPopContext() { const auto ctx = (CFTypeRef)pthread_getspecific(ASLayoutElementContextKey()); ASDisplayNodeCAssertNotNil(ctx, @"Attempt to pop context when there wasn't a context!"); CFRelease(ctx); pthread_setspecific(ASLayoutElementContextKey(), NULL); } #endif // AS_TLS_AVAILABLE #pragma mark - ASLayoutElementStyle NSString * const ASLayoutElementStyleWidthProperty = @"ASLayoutElementStyleWidthProperty"; NSString * const ASLayoutElementStyleMinWidthProperty = @"ASLayoutElementStyleMinWidthProperty"; NSString * const ASLayoutElementStyleMaxWidthProperty = @"ASLayoutElementStyleMaxWidthProperty"; NSString * const ASLayoutElementStyleHeightProperty = @"ASLayoutElementStyleHeightProperty"; NSString * const ASLayoutElementStyleMinHeightProperty = @"ASLayoutElementStyleMinHeightProperty"; NSString * const ASLayoutElementStyleMaxHeightProperty = @"ASLayoutElementStyleMaxHeightProperty"; NSString * const ASLayoutElementStyleSpacingBeforeProperty = @"ASLayoutElementStyleSpacingBeforeProperty"; NSString * const ASLayoutElementStyleSpacingAfterProperty = @"ASLayoutElementStyleSpacingAfterProperty"; NSString * const ASLayoutElementStyleFlexGrowProperty = @"ASLayoutElementStyleFlexGrowProperty"; NSString * const ASLayoutElementStyleFlexShrinkProperty = @"ASLayoutElementStyleFlexShrinkProperty"; NSString * const ASLayoutElementStyleFlexBasisProperty = @"ASLayoutElementStyleFlexBasisProperty"; NSString * const ASLayoutElementStyleAlignSelfProperty = @"ASLayoutElementStyleAlignSelfProperty"; NSString * const ASLayoutElementStyleAscenderProperty = @"ASLayoutElementStyleAscenderProperty"; NSString * const ASLayoutElementStyleDescenderProperty = @"ASLayoutElementStyleDescenderProperty"; NSString * const ASLayoutElementStyleLayoutPositionProperty = @"ASLayoutElementStyleLayoutPositionProperty"; #if YOGA NSString * const ASYogaFlexWrapProperty = @"ASLayoutElementStyleLayoutFlexWrapProperty"; NSString * const ASYogaFlexDirectionProperty = @"ASYogaFlexDirectionProperty"; NSString * const ASYogaDirectionProperty = @"ASYogaDirectionProperty"; NSString * const ASYogaSpacingProperty = @"ASYogaSpacingProperty"; NSString * const ASYogaJustifyContentProperty = @"ASYogaJustifyContentProperty"; NSString * const ASYogaAlignItemsProperty = @"ASYogaAlignItemsProperty"; NSString * const ASYogaPositionTypeProperty = @"ASYogaPositionTypeProperty"; NSString * const ASYogaPositionProperty = @"ASYogaPositionProperty"; NSString * const ASYogaMarginProperty = @"ASYogaMarginProperty"; NSString * const ASYogaPaddingProperty = @"ASYogaPaddingProperty"; NSString * const ASYogaBorderProperty = @"ASYogaBorderProperty"; NSString * const ASYogaAspectRatioProperty = @"ASYogaAspectRatioProperty"; #endif #define ASLayoutElementStyleSetSizeWithScope(x) \ __instanceLock__.lock(); \ ASLayoutElementSize newSize = _size.load(); \ { x } \ _size.store(newSize); \ __instanceLock__.unlock(); #define ASLayoutElementStyleCallDelegate(propertyName)\ do {\ [self propertyDidChange:propertyName];\ [_delegate style:self propertyDidChange:propertyName];\ } while(0) @implementation ASLayoutElementStyle { AS::RecursiveMutex __instanceLock__; ASLayoutElementStyleExtensions _extensions; std::atomic _size; std::atomic _spacingBefore; std::atomic _spacingAfter; std::atomic _flexGrow; std::atomic _flexShrink; std::atomic _flexBasis; std::atomic _alignSelf; std::atomic _ascender; std::atomic _descender; std::atomic _layoutPosition; #if YOGA YGNodeRef _yogaNode; std::atomic _flexWrap; std::atomic _flexDirection; std::atomic _direction; std::atomic _justifyContent; std::atomic _alignItems; std::atomic _positionType; std::atomic _position; std::atomic _margin; std::atomic _padding; std::atomic _border; std::atomic _aspectRatio; ASStackLayoutAlignItems _parentAlignStyle; #endif } @dynamic width, height, minWidth, maxWidth, minHeight, maxHeight; @dynamic preferredSize, minSize, maxSize, preferredLayoutSize, minLayoutSize, maxLayoutSize; #pragma mark - Lifecycle - (instancetype)initWithDelegate:(id)delegate { self = [self init]; if (self) { _delegate = delegate; } return self; } - (instancetype)init { self = [super init]; if (self) { _size = ASLayoutElementSizeMake(); #if YOGA _parentAlignStyle = ASStackLayoutAlignItemsNotSet; #endif } return self; } ASSynthesizeLockingMethodsWithMutex(__instanceLock__) #pragma mark - ASLayoutElementStyleSize - (ASLayoutElementSize)size { return _size.load(); } - (void)setSize:(ASLayoutElementSize)size { ASLayoutElementStyleSetSizeWithScope({ newSize = size; }); // No CallDelegate method as ASLayoutElementSize is currently internal. } #pragma mark - ASLayoutElementStyleSizeForwarding - (ASDimension)width { return _size.load().width; } - (void)setWidth:(ASDimension)width { ASLayoutElementStyleSetSizeWithScope({ newSize.width = width; }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleWidthProperty); } - (ASDimension)height { return _size.load().height; } - (void)setHeight:(ASDimension)height { ASLayoutElementStyleSetSizeWithScope({ newSize.height = height; }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleHeightProperty); } - (ASDimension)minWidth { return _size.load().minWidth; } - (void)setMinWidth:(ASDimension)minWidth { ASLayoutElementStyleSetSizeWithScope({ newSize.minWidth = minWidth; }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMinWidthProperty); } - (ASDimension)maxWidth { return _size.load().maxWidth; } - (void)setMaxWidth:(ASDimension)maxWidth { ASLayoutElementStyleSetSizeWithScope({ newSize.maxWidth = maxWidth; }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMaxWidthProperty); } - (ASDimension)minHeight { return _size.load().minHeight; } - (void)setMinHeight:(ASDimension)minHeight { ASLayoutElementStyleSetSizeWithScope({ newSize.minHeight = minHeight; }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMinHeightProperty); } - (ASDimension)maxHeight { return _size.load().maxHeight; } - (void)setMaxHeight:(ASDimension)maxHeight { ASLayoutElementStyleSetSizeWithScope({ newSize.maxHeight = maxHeight; }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMaxHeightProperty); } #pragma mark - ASLayoutElementStyleSizeHelpers - (void)setPreferredSize:(CGSize)preferredSize { ASLayoutElementStyleSetSizeWithScope({ newSize.width = ASDimensionMakeWithPoints(preferredSize.width); newSize.height = ASDimensionMakeWithPoints(preferredSize.height); }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleWidthProperty); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleHeightProperty); } - (CGSize)preferredSize { ASLayoutElementSize size = _size.load(); if (size.width.unit == ASDimensionUnitFraction) { NSCAssert(NO, @"Cannot get preferredSize of element with fractional width. Width: %@.", NSStringFromASDimension(size.width)); return CGSizeZero; } if (size.height.unit == ASDimensionUnitFraction) { NSCAssert(NO, @"Cannot get preferredSize of element with fractional height. Height: %@.", NSStringFromASDimension(size.height)); return CGSizeZero; } return CGSizeMake(size.width.value, size.height.value); } - (void)setMinSize:(CGSize)minSize { ASLayoutElementStyleSetSizeWithScope({ newSize.minWidth = ASDimensionMakeWithPoints(minSize.width); newSize.minHeight = ASDimensionMakeWithPoints(minSize.height); }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMinWidthProperty); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMinHeightProperty); } - (void)setMaxSize:(CGSize)maxSize { ASLayoutElementStyleSetSizeWithScope({ newSize.maxWidth = ASDimensionMakeWithPoints(maxSize.width); newSize.maxHeight = ASDimensionMakeWithPoints(maxSize.height); }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMaxWidthProperty); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMaxHeightProperty); } - (ASLayoutSize)preferredLayoutSize { ASLayoutElementSize size = _size.load(); return ASLayoutSizeMake(size.width, size.height); } - (void)setPreferredLayoutSize:(ASLayoutSize)preferredLayoutSize { ASLayoutElementStyleSetSizeWithScope({ newSize.width = preferredLayoutSize.width; newSize.height = preferredLayoutSize.height; }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleWidthProperty); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleHeightProperty); } - (ASLayoutSize)minLayoutSize { ASLayoutElementSize size = _size.load(); return ASLayoutSizeMake(size.minWidth, size.minHeight); } - (void)setMinLayoutSize:(ASLayoutSize)minLayoutSize { ASLayoutElementStyleSetSizeWithScope({ newSize.minWidth = minLayoutSize.width; newSize.minHeight = minLayoutSize.height; }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMinWidthProperty); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMinHeightProperty); } - (ASLayoutSize)maxLayoutSize { ASLayoutElementSize size = _size.load(); return ASLayoutSizeMake(size.maxWidth, size.maxHeight); } - (void)setMaxLayoutSize:(ASLayoutSize)maxLayoutSize { ASLayoutElementStyleSetSizeWithScope({ newSize.maxWidth = maxLayoutSize.width; newSize.maxHeight = maxLayoutSize.height; }); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMaxWidthProperty); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleMaxHeightProperty); } #pragma mark - ASStackLayoutElement - (void)setSpacingBefore:(CGFloat)spacingBefore { _spacingBefore.store(spacingBefore); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleSpacingBeforeProperty); } - (CGFloat)spacingBefore { return _spacingBefore.load(); } - (void)setSpacingAfter:(CGFloat)spacingAfter { _spacingAfter.store(spacingAfter); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleSpacingAfterProperty); } - (CGFloat)spacingAfter { return _spacingAfter.load(); } - (void)setFlexGrow:(CGFloat)flexGrow { _flexGrow.store(flexGrow); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleFlexGrowProperty); } - (CGFloat)flexGrow { return _flexGrow.load(); } - (void)setFlexShrink:(CGFloat)flexShrink { _flexShrink.store(flexShrink); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleFlexShrinkProperty); } - (CGFloat)flexShrink { return _flexShrink.load(); } - (void)setFlexBasis:(ASDimension)flexBasis { _flexBasis.store(flexBasis); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleFlexBasisProperty); } - (ASDimension)flexBasis { return _flexBasis.load(); } - (void)setAlignSelf:(ASStackLayoutAlignSelf)alignSelf { _alignSelf.store(alignSelf); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleAlignSelfProperty); } - (ASStackLayoutAlignSelf)alignSelf { return _alignSelf.load(); } - (void)setAscender:(CGFloat)ascender { _ascender.store(ascender); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleAscenderProperty); } - (CGFloat)ascender { return _ascender.load(); } - (void)setDescender:(CGFloat)descender { _descender.store(descender); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleDescenderProperty); } - (CGFloat)descender { return _descender.load(); } #pragma mark - ASAbsoluteLayoutElement - (void)setLayoutPosition:(CGPoint)layoutPosition { _layoutPosition.store(layoutPosition); ASLayoutElementStyleCallDelegate(ASLayoutElementStyleLayoutPositionProperty); } - (CGPoint)layoutPosition { return _layoutPosition.load(); } #pragma mark - Extensions - (void)setLayoutOptionExtensionBool:(BOOL)value atIndex:(int)idx { NSCAssert(idx < kMaxLayoutElementBoolExtensions, @"Setting index outside of max bool extensions space"); MutexLocker l(__instanceLock__); _extensions.boolExtensions[idx] = value; } - (BOOL)layoutOptionExtensionBoolAtIndex:(int)idx\ { NSCAssert(idx < kMaxLayoutElementBoolExtensions, @"Accessing index outside of max bool extensions space"); MutexLocker l(__instanceLock__); return _extensions.boolExtensions[idx]; } - (void)setLayoutOptionExtensionInteger:(NSInteger)value atIndex:(int)idx { NSCAssert(idx < kMaxLayoutElementStateIntegerExtensions, @"Setting index outside of max integer extensions space"); MutexLocker l(__instanceLock__); _extensions.integerExtensions[idx] = value; } - (NSInteger)layoutOptionExtensionIntegerAtIndex:(int)idx { NSCAssert(idx < kMaxLayoutElementStateIntegerExtensions, @"Accessing index outside of max integer extensions space"); MutexLocker l(__instanceLock__); return _extensions.integerExtensions[idx]; } - (void)setLayoutOptionExtensionEdgeInsets:(UIEdgeInsets)value atIndex:(int)idx { NSCAssert(idx < kMaxLayoutElementStateEdgeInsetExtensions, @"Setting index outside of max edge insets extensions space"); MutexLocker l(__instanceLock__); _extensions.edgeInsetsExtensions[idx] = value; } - (UIEdgeInsets)layoutOptionExtensionEdgeInsetsAtIndex:(int)idx { NSCAssert(idx < kMaxLayoutElementStateEdgeInsetExtensions, @"Accessing index outside of max edge insets extensions space"); MutexLocker l(__instanceLock__); return _extensions.edgeInsetsExtensions[idx]; } #pragma mark - Debugging - (NSString *)description { return ASObjectDescriptionMake(self, [self propertiesForDescription]); } - (NSMutableArray *)propertiesForDescription { NSMutableArray *result = [NSMutableArray array]; if ((self.minLayoutSize.width.unit != ASDimensionUnitAuto || self.minLayoutSize.height.unit != ASDimensionUnitAuto)) { [result addObject:@{ @"minLayoutSize" : NSStringFromASLayoutSize(self.minLayoutSize) }]; } if ((self.preferredLayoutSize.width.unit != ASDimensionUnitAuto || self.preferredLayoutSize.height.unit != ASDimensionUnitAuto)) { [result addObject:@{ @"preferredSize" : NSStringFromASLayoutSize(self.preferredLayoutSize) }]; } if ((self.maxLayoutSize.width.unit != ASDimensionUnitAuto || self.maxLayoutSize.height.unit != ASDimensionUnitAuto)) { [result addObject:@{ @"maxLayoutSize" : NSStringFromASLayoutSize(self.maxLayoutSize) }]; } if (self.alignSelf != ASStackLayoutAlignSelfAuto) { [result addObject:@{ @"alignSelf" : [@[@"ASStackLayoutAlignSelfAuto", @"ASStackLayoutAlignSelfStart", @"ASStackLayoutAlignSelfEnd", @"ASStackLayoutAlignSelfCenter", @"ASStackLayoutAlignSelfStretch"] objectAtIndex:self.alignSelf] }]; } if (self.ascender != 0) { [result addObject:@{ @"ascender" : @(self.ascender) }]; } if (self.descender != 0) { [result addObject:@{ @"descender" : @(self.descender) }]; } if (ASDimensionEqualToDimension(self.flexBasis, ASDimensionAuto) == NO) { [result addObject:@{ @"flexBasis" : NSStringFromASDimension(self.flexBasis) }]; } if (self.flexGrow != 0) { [result addObject:@{ @"flexGrow" : @(self.flexGrow) }]; } if (self.flexShrink != 0) { [result addObject:@{ @"flexShrink" : @(self.flexShrink) }]; } if (self.spacingAfter != 0) { [result addObject:@{ @"spacingAfter" : @(self.spacingAfter) }]; } if (self.spacingBefore != 0) { [result addObject:@{ @"spacingBefore" : @(self.spacingBefore) }]; } if (CGPointEqualToPoint(self.layoutPosition, CGPointZero) == NO) { [result addObject:@{ @"layoutPosition" : [NSValue valueWithCGPoint:self.layoutPosition] }]; } return result; } - (void)propertyDidChange:(NSString *)propertyName { #if YOGA /* TODO(appleguy): STYLE SETTER METHODS LEFT TO IMPLEMENT void YGNodeStyleSetOverflow(YGNodeRef node, YGOverflow overflow); void YGNodeStyleSetFlex(YGNodeRef node, float flex); */ if (_yogaNode == NULL) { return; } // Because the NSStrings used to identify each property are const, use efficient pointer comparison. if (propertyName == ASLayoutElementStyleWidthProperty) { YGNODE_STYLE_SET_DIMENSION(_yogaNode, Width, self.width); } else if (propertyName == ASLayoutElementStyleMinWidthProperty) { YGNODE_STYLE_SET_DIMENSION(_yogaNode, MinWidth, self.minWidth); } else if (propertyName == ASLayoutElementStyleMaxWidthProperty) { YGNODE_STYLE_SET_DIMENSION(_yogaNode, MaxWidth, self.maxWidth); } else if (propertyName == ASLayoutElementStyleHeightProperty) { YGNODE_STYLE_SET_DIMENSION(_yogaNode, Height, self.height); } else if (propertyName == ASLayoutElementStyleMinHeightProperty) { YGNODE_STYLE_SET_DIMENSION(_yogaNode, MinHeight, self.minHeight); } else if (propertyName == ASLayoutElementStyleMaxHeightProperty) { YGNODE_STYLE_SET_DIMENSION(_yogaNode, MaxHeight, self.maxHeight); } else if (propertyName == ASLayoutElementStyleFlexGrowProperty) { YGNodeStyleSetFlexGrow(_yogaNode, self.flexGrow); } else if (propertyName == ASLayoutElementStyleFlexShrinkProperty) { YGNodeStyleSetFlexShrink(_yogaNode, self.flexShrink); } else if (propertyName == ASLayoutElementStyleFlexBasisProperty) { YGNODE_STYLE_SET_DIMENSION(_yogaNode, FlexBasis, self.flexBasis); } else if (propertyName == ASLayoutElementStyleAlignSelfProperty) { YGNodeStyleSetAlignSelf(_yogaNode, yogaAlignSelf(self.alignSelf)); } else if (propertyName == ASYogaFlexWrapProperty) { YGNodeStyleSetFlexWrap(_yogaNode, self.flexWrap); } else if (propertyName == ASYogaFlexDirectionProperty) { YGNodeStyleSetFlexDirection(_yogaNode, yogaFlexDirection(self.flexDirection)); } else if (propertyName == ASYogaDirectionProperty) { YGNodeStyleSetDirection(_yogaNode, self.direction); } else if (propertyName == ASYogaJustifyContentProperty) { YGNodeStyleSetJustifyContent(_yogaNode, yogaJustifyContent(self.justifyContent)); } else if (propertyName == ASYogaAlignItemsProperty) { ASStackLayoutAlignItems alignItems = self.alignItems; if (alignItems != ASStackLayoutAlignItemsNotSet) { YGNodeStyleSetAlignItems(_yogaNode, yogaAlignItems(alignItems)); } } else if (propertyName == ASYogaPositionTypeProperty) { YGNodeStyleSetPositionType(_yogaNode, self.positionType); } else if (propertyName == ASYogaPositionProperty) { ASEdgeInsets position = self.position; YGEdge edge = YGEdgeLeft; for (int i = 0; i < YGEdgeAll + 1; ++i) { YGNODE_STYLE_SET_DIMENSION_WITH_EDGE(_yogaNode, Position, dimensionForEdgeWithEdgeInsets(edge, position), edge); edge = (YGEdge)(edge + 1); } } else if (propertyName == ASYogaMarginProperty) { ASEdgeInsets margin = self.margin; YGEdge edge = YGEdgeLeft; for (int i = 0; i < YGEdgeAll + 1; ++i) { YGNODE_STYLE_SET_DIMENSION_WITH_EDGE(_yogaNode, Margin, dimensionForEdgeWithEdgeInsets(edge, margin), edge); edge = (YGEdge)(edge + 1); } } else if (propertyName == ASYogaPaddingProperty) { ASEdgeInsets padding = self.padding; YGEdge edge = YGEdgeLeft; for (int i = 0; i < YGEdgeAll + 1; ++i) { YGNODE_STYLE_SET_DIMENSION_WITH_EDGE(_yogaNode, Padding, dimensionForEdgeWithEdgeInsets(edge, padding), edge); edge = (YGEdge)(edge + 1); } } else if (propertyName == ASYogaBorderProperty) { ASEdgeInsets border = self.border; YGEdge edge = YGEdgeLeft; for (int i = 0; i < YGEdgeAll + 1; ++i) { YGNODE_STYLE_SET_FLOAT_WITH_EDGE(_yogaNode, Border, dimensionForEdgeWithEdgeInsets(edge, border), edge); edge = (YGEdge)(edge + 1); } } else if (propertyName == ASYogaAspectRatioProperty) { CGFloat aspectRatio = self.aspectRatio; if (aspectRatio > FLT_EPSILON && aspectRatio < CGFLOAT_MAX / 2.0) { YGNodeStyleSetAspectRatio(_yogaNode, aspectRatio); } } #endif } #pragma mark - Yoga Flexbox Properties #if YOGA + (void)initialize { [super initialize]; YGConfigSetPointScaleFactor(YGConfigGetDefault(), ASScreenScale()); // Yoga recommends using Web Defaults for all new projects. This will be enabled for Texture very soon. //YGConfigSetUseWebDefaults(YGConfigGetDefault(), true); } - (YGNodeRef)yogaNode { return _yogaNode; } - (YGNodeRef)yogaNodeCreateIfNeeded { if (_yogaNode == NULL) { _yogaNode = YGNodeNew(); } return _yogaNode; } - (void)destroyYogaNode { if (_yogaNode != NULL) { // Release the __bridge_retained Context object. ASLayoutElementYogaUpdateMeasureFunc(_yogaNode, nil); YGNodeFree(_yogaNode); _yogaNode = NULL; } } - (void)dealloc { [self destroyYogaNode]; } - (YGWrap)flexWrap { return _flexWrap.load(); } - (ASStackLayoutDirection)flexDirection { return _flexDirection.load(); } - (YGDirection)direction { return _direction.load(); } - (ASStackLayoutJustifyContent)justifyContent { return _justifyContent.load(); } - (ASStackLayoutAlignItems)alignItems { return _alignItems.load(); } - (YGPositionType)positionType { return _positionType.load(); } - (ASEdgeInsets)position { return _position.load(); } - (ASEdgeInsets)margin { return _margin.load(); } - (ASEdgeInsets)padding { return _padding.load(); } - (ASEdgeInsets)border { return _border.load(); } - (CGFloat)aspectRatio { return _aspectRatio.load(); } // private (ASLayoutElementStylePrivate.h) - (ASStackLayoutAlignItems)parentAlignStyle { return _parentAlignStyle; } - (void)setFlexWrap:(YGWrap)flexWrap { _flexWrap.store(flexWrap); ASLayoutElementStyleCallDelegate(ASYogaFlexWrapProperty); } - (void)setFlexDirection:(ASStackLayoutDirection)flexDirection { _flexDirection.store(flexDirection); ASLayoutElementStyleCallDelegate(ASYogaFlexDirectionProperty); } - (void)setDirection:(YGDirection)direction { _direction.store(direction); ASLayoutElementStyleCallDelegate(ASYogaDirectionProperty); } - (void)setJustifyContent:(ASStackLayoutJustifyContent)justify { _justifyContent.store(justify); ASLayoutElementStyleCallDelegate(ASYogaJustifyContentProperty); } - (void)setAlignItems:(ASStackLayoutAlignItems)alignItems { _alignItems.store(alignItems); ASLayoutElementStyleCallDelegate(ASYogaAlignItemsProperty); } - (void)setPositionType:(YGPositionType)positionType { _positionType.store(positionType); ASLayoutElementStyleCallDelegate(ASYogaPositionTypeProperty); } - (void)setPosition:(ASEdgeInsets)position { _position.store(position); ASLayoutElementStyleCallDelegate(ASYogaPositionProperty); } - (void)setMargin:(ASEdgeInsets)margin { _margin.store(margin); ASLayoutElementStyleCallDelegate(ASYogaMarginProperty); } - (void)setPadding:(ASEdgeInsets)padding { _padding.store(padding); ASLayoutElementStyleCallDelegate(ASYogaPaddingProperty); } - (void)setBorder:(ASEdgeInsets)border { _border.store(border); ASLayoutElementStyleCallDelegate(ASYogaBorderProperty); } - (void)setAspectRatio:(CGFloat)aspectRatio { _aspectRatio.store(aspectRatio); ASLayoutElementStyleCallDelegate(ASYogaAspectRatioProperty); } // private (ASLayoutElementStylePrivate.h) - (void)setParentAlignStyle:(ASStackLayoutAlignItems)style { _parentAlignStyle = style; } #endif /* YOGA */ @end