Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
- 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)
4 changes: 3 additions & 1 deletion Source/ASDisplayNode+Beta.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,14 @@ extern void ASDisplayNodePerformBlockOnEveryYogaChild(ASDisplayNode * _Nullable
// These methods should not normally be called directly.
- (void)invalidateCalculatedYogaLayout;
- (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize;
- (void)semanticContentAttributeDidChange:(UISemanticContentAttribute)attribute;

@end

@interface ASLayoutElementStyle (Yoga)

@property (nonatomic, assign, readwrite) ASStackLayoutDirection direction;
@property (nonatomic, assign, readwrite) ASStackLayoutDirection flexDirection;
@property (nonatomic, assign, readwrite) YGDirection direction;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if these are implemented using C++ atomics, we ought to declare them as atomic.

@property (nonatomic, assign, readwrite) CGFloat spacing;
@property (nonatomic, assign, readwrite) ASStackLayoutJustifyContent justifyContent;
@property (nonatomic, assign, readwrite) ASStackLayoutAlignItems alignItems;
Expand Down
45 changes: 32 additions & 13 deletions Source/ASDisplayNode+Yoga.mm
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,15 @@ float yogaDimensionToPercent(ASDimension dimension)
ASDimension dimensionForEdgeWithEdgeInsets(YGEdge edge, ASEdgeInsets insets)
{
switch (edge) {
case YGEdgeLeft: return insets.left;
case YGEdgeTop: return insets.top;
case YGEdgeRight: return insets.right;
case YGEdgeBottom: return insets.bottom;
case YGEdgeLeft: return insets.left;
case YGEdgeTop: return insets.top;
case YGEdgeRight: return insets.right;
case YGEdgeBottom: return insets.bottom;
case YGEdgeStart: return insets.start;
case YGEdgeEnd: return insets.end;
case YGEdgeHorizontal: return insets.horizontal;
case YGEdgeVertical: return insets.vertical;
case YGEdgeAll: return insets.all;
default: ASDisplayNodeCAssert(NO, @"YGEdge other than ASEdgeInsets is not supported.");
return ASDimensionAuto;
}
Expand Down Expand Up @@ -314,10 +319,9 @@ - (void)setupYogaCalculatedLayout

- (void)setYogaMeasureFuncIfNeeded
{
// Manual size calculation via calculateSizeThatFits:
// This will be used for ASTextNode, as well as any other leaf node that has no layout spec.
if ((self.methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) == NO
&& self.layoutSpecBlock == NULL && self.yogaChildren.count == 0) {
// Size calculation via calculateSizeThatFits: or layoutSpecThatFits:
// This will be used for ASTextNode, as well as any other node that has no Yoga children
if (self.yogaChildren.count == 0) {
YGNodeRef yogaNode = self.yogaNode; // Use property to assign Ref if needed.
YGNodeSetContext(yogaNode, (__bridge void *)self);
YGNodeSetMeasureFunc(yogaNode, &ASLayoutElementYogaMeasureFunc);
Expand All @@ -333,8 +337,24 @@ - (void)invalidateCalculatedYogaLayout
}
}

- (void)semanticContentAttributeDidChange:(UISemanticContentAttribute)attribute
{
if (AS_AT_LEAST_IOS9) {
UIUserInterfaceLayoutDirection layoutDirection =
[UIView userInterfaceLayoutDirectionForSemanticContentAttribute:attribute];
self.style.direction = (layoutDirection == UIUserInterfaceLayoutDirectionLeftToRight
? YGDirectionLTR : YGDirectionRTL);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! That class method may not be safe off-main, but I expect you've considered that. Even if so, the risk here is teeny tiny.

}

- (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize
{
if (self.yogaParent) {
if (ASHierarchyStateIncludesYogaLayoutMeasuring(self.hierarchyState) == NO) {
[self _setNeedsLayoutFromAbove];
}
return;
}
if (ASHierarchyStateIncludesYogaLayoutMeasuring(self.hierarchyState)) {
ASDisplayNodeAssert(NO, @"A Yoga layout is being performed by a parent; children must not perform their own until it is done! %@", [self displayNodeRecursiveDescription]);
return;
Expand All @@ -356,14 +376,14 @@ - (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize
ASLayoutElementStyle *style = node.style;
YGNodeRef yogaNode = node.yogaNode;

YGNodeStyleSetDirection (yogaNode, YGDirectionInherit);
YGNodeStyleSetDirection (yogaNode, style.direction);

YGNodeStyleSetFlexWrap (yogaNode, style.flexWrap);
YGNodeStyleSetFlexGrow (yogaNode, style.flexGrow);
YGNodeStyleSetFlexShrink (yogaNode, style.flexShrink);
YGNODE_STYLE_SET_DIMENSION (yogaNode, FlexBasis, style.flexBasis);

YGNodeStyleSetFlexDirection (yogaNode, yogaFlexDirection(style.direction));
YGNodeStyleSetFlexDirection (yogaNode, yogaFlexDirection(style.flexDirection));
YGNodeStyleSetJustifyContent(yogaNode, yogaJustifyContent(style.justifyContent));
YGNodeStyleSetAlignSelf (yogaNode, yogaAlignSelf(style.alignSelf));
ASStackLayoutAlignItems alignItems = style.alignItems;
Expand All @@ -378,12 +398,12 @@ - (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize
ASEdgeInsets border = style.border;

YGEdge edge = YGEdgeLeft;
for (int i = 0; i < 4; i++) {
for (int i = 0; i < YGEdgeAll + 1; ++i) {
YGNODE_STYLE_SET_DIMENSION_WITH_EDGE(yogaNode, Position, dimensionForEdgeWithEdgeInsets(edge, position), edge);
YGNODE_STYLE_SET_DIMENSION_WITH_EDGE(yogaNode, Margin, dimensionForEdgeWithEdgeInsets(edge, margin), edge);
YGNODE_STYLE_SET_DIMENSION_WITH_EDGE(yogaNode, Padding, dimensionForEdgeWithEdgeInsets(edge, padding), edge);
YGNODE_STYLE_SET_FLOAT_WITH_EDGE(yogaNode, Border, dimensionForEdgeWithEdgeInsets(edge, border), edge);
edge = (edge == YGEdgeLeft ? YGEdgeTop : (edge == YGEdgeTop ? YGEdgeRight : YGEdgeBottom));
edge = (YGEdge)(edge + 1);
}

CGFloat aspectRatio = style.aspectRatio;
Expand All @@ -406,7 +426,6 @@ - (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize
[node setYogaMeasureFuncIfNeeded];

/* TODO(appleguy): STYLE SETTER METHODS LEFT TO IMPLEMENT
void YGNodeStyleSetFlexDirection(YGNodeRef node, YGFlexDirection flexDirection);
void YGNodeStyleSetOverflow(YGNodeRef node, YGOverflow overflow);
void YGNodeStyleSetFlex(YGNodeRef node, float flex);
*/
Expand Down
32 changes: 21 additions & 11 deletions Source/Layout/ASDimension.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#pragma once
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <AsyncDisplayKit/ASAvailability.h>
#import <AsyncDisplayKit/ASBaseDefines.h>
#import <AsyncDisplayKit/ASAssert.h>

Expand Down Expand Up @@ -213,17 +214,6 @@ ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT NSString *NSStringFromASLayoutSize(AS
NSStringFromASDimension(size.height)];
}

#pragma mark - ASEdgeInsets

typedef struct {
ASDimension top;
ASDimension left;
ASDimension bottom;
ASDimension right;
} ASEdgeInsets;

extern ASEdgeInsets const ASEdgeInsetsZero;

#pragma mark - ASSizeRange

/**
Expand Down Expand Up @@ -308,5 +298,25 @@ ASDISPLAYNODE_INLINE AS_WARN_UNUSED_RESULT BOOL ASSizeRangeEqualToSizeRange(ASSi
*/
extern AS_WARN_UNUSED_RESULT NSString *NSStringFromASSizeRange(ASSizeRange sizeRange);

#if YOGA

#pragma mark - ASEdgeInsets

typedef struct {
ASDimension top;
ASDimension left;
ASDimension bottom;
ASDimension right;
ASDimension start;
ASDimension end;
ASDimension horizontal;
ASDimension vertical;
ASDimension all;
} ASEdgeInsets;

extern ASEdgeInsets const ASEdgeInsetsZero;

#endif

NS_ASSUME_NONNULL_END
ASDISPLAYNODE_EXTERN_C_END
9 changes: 5 additions & 4 deletions Source/Layout/ASDimension.mm
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,6 @@ ASOVERLOADABLE ASDimension ASDimensionMake(NSString *dimension)

ASLayoutSize const ASLayoutSizeAuto = {ASDimensionAuto, ASDimensionAuto};

#pragma mark - ASEdgeInsets

ASEdgeInsets const ASEdgeInsetsZero = {};

#pragma mark - ASSizeRange

ASSizeRange const ASSizeRangeZero = {};
Expand Down Expand Up @@ -115,3 +111,8 @@ ASSizeRange ASSizeRangeIntersect(ASSizeRange sizeRange, ASSizeRange otherSizeRan
NSStringFromCGSize(sizeRange.min),
NSStringFromCGSize(sizeRange.max)];
}

#if YOGA
#pragma mark - Yoga - ASEdgeInsets
ASEdgeInsets const ASEdgeInsetsZero = {};
#endif
9 changes: 6 additions & 3 deletions Source/Layout/ASLayoutElement.mm
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ @implementation ASLayoutElementStyle {
std::atomic<CGPoint> _layoutPosition;

#if YOGA
std::atomic<ASStackLayoutDirection> _direction;
std::atomic<ASStackLayoutDirection> _flexDirection;
std::atomic<YGDirection> _direction;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(You knew it was coming!) Maybe these would be better-off as Objective-C atomic properties to improve performance and cut down on boilerplate?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As all of them are currently c++ atomics let's go with it for now and do the whole change in a another diff if we want to.

std::atomic<CGFloat> _spacing;
std::atomic<ASStackLayoutJustifyContent> _justifyContent;
std::atomic<ASStackLayoutAlignItems> _alignItems;
Expand Down Expand Up @@ -600,7 +601,8 @@ - (NSString *)description

#if YOGA

- (ASStackLayoutDirection)direction { return _direction.load(); }
- (ASStackLayoutDirection)flexDirection { return _flexDirection.load(); }
- (YGDirection)direction { return _direction.load(); }
- (CGFloat)spacing { return _spacing.load(); }
- (ASStackLayoutJustifyContent)justifyContent { return _justifyContent.load(); }
- (ASStackLayoutAlignItems)alignItems { return _alignItems.load(); }
Expand All @@ -612,7 +614,8 @@ - (ASEdgeInsets)border { return _border.load(); }
- (CGFloat)aspectRatio { return _aspectRatio.load(); }
- (YGWrap)flexWrap { return _flexWrap.load(); }

- (void)setDirection:(ASStackLayoutDirection)direction { _direction.store(direction); }
- (void)setFlexDirection:(ASStackLayoutDirection)flexDirection { _flexDirection.store(flexDirection); }
- (void)setDirection:(YGDirection)direction { _direction.store(direction); }
- (void)setSpacing:(CGFloat)spacing { _spacing.store(spacing); }
- (void)setJustifyContent:(ASStackLayoutJustifyContent)justify { _justifyContent.store(justify); }
- (void)setAlignItems:(ASStackLayoutAlignItems)alignItems { _alignItems.store(alignItems); }
Expand Down
8 changes: 8 additions & 0 deletions Source/Private/ASDisplayNode+FrameworkPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,14 @@ __unused static NSString * _Nonnull NSStringFromASHierarchyState(ASHierarchyStat
*/
- (BOOL)shouldScheduleDisplayWithNewInterfaceState:(ASInterfaceState)newInterfaceState;

/**
* @abstract Informs the root node that the intrinsic size of the receiver is no longer valid.
*
* @discussion The size of a root node is determined by each subnode. Calling invalidateSize will let the root node know
* that the intrinsic size of the receiver node is no longer valid and a resizing of the root node needs to happen.
*/
- (void)_setNeedsLayoutFromAbove;

/**
* @abstract Subclass hook for nodes that are acting as root nodes. This method is called if one of the subnodes
* size is invalidated and may need to result in a different size as the current calculated size.
Expand Down
3 changes: 3 additions & 0 deletions Source/Private/ASDisplayNode+UIViewBridge.mm
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,9 @@ - (void)setSemanticContentAttribute:(UISemanticContentAttribute)semanticContentA
_bridge_prologue_write;
if (AS_AT_LEAST_IOS9) {
_setToViewOnly(semanticContentAttribute, semanticContentAttribute);
#if YOGA
[self semanticContentAttributeDidChange:semanticContentAttribute];
#endif
}
}

Expand Down