Skip to content

Commit

Permalink
Fix a bug with Yoga nodes whose position change and don't update. (#1408
Browse files Browse the repository at this point in the history
)
  • Loading branch information
tnorman42 authored and Adlai-Holler committed Mar 22, 2019
1 parent 09365b9 commit 5937ac3
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 6 deletions.
10 changes: 10 additions & 0 deletions Source/ASDisplayNode+Layout.mm
Original file line number Diff line number Diff line change
Expand Up @@ -402,9 +402,19 @@ - (void)_u_measureNodeWithBoundsIfNecessary:(CGRect)bounds
// Use the last known constrainedSize passed from a parent during layout (if never, use bounds).
NSUInteger version = _layoutVersion;
ASSizeRange constrainedSize = [self _locked_constrainedSizeForLayoutPass];
#if YOGA
// This flag indicates to the Texture+Yoga code that this next layout is intended to be
// displayed (vs. just for measurement). This will cause it to call setNeedsLayout on any nodes
// whose layout changes as a result of the Yoga recalculation. This is necessary because a
// change in one Yoga node can change the layout for any other node in the tree.
self.willApplyNextYogaCalculatedLayout = YES;
#endif
ASLayout *layout = [self calculateLayoutThatFits:constrainedSize
restrictedToSize:self.style.size
relativeToParentSize:boundsSizeForLayout];
#if YOGA
self.willApplyNextYogaCalculatedLayout = NO;
#endif
nextLayout = ASDisplayNodeLayout(layout, constrainedSize, boundsSizeForLayout, version);
// Now that the constrained size of pending layout might have been reused, the layout is useless
// Release it and any orphaned subnodes it retains
Expand Down
3 changes: 2 additions & 1 deletion Source/ASDisplayNode+Yoga.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ AS_EXTERN void ASDisplayNodePerformBlockOnEveryYogaChild(ASDisplayNode * _Nullab
@property BOOL yogaLayoutInProgress;
// TODO: Make this atomic (lock).
@property (nullable, nonatomic) ASLayout *yogaCalculatedLayout;
@property (nonatomic) BOOL willApplyNextYogaCalculatedLayout;

// Will walk up the Yoga tree and returns the root node
- (ASDisplayNode *)yogaRoot;
Expand All @@ -54,7 +55,7 @@ AS_EXTERN void ASDisplayNodePerformBlockOnEveryYogaChild(ASDisplayNode * _Nullab
/// For internal usage only
- (ASLayout *)calculateLayoutYoga:(ASSizeRange)constrainedSize;
/// For internal usage only
- (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize;
- (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize willApply:(BOOL)willApply;
/// For internal usage only
- (void)invalidateCalculatedYogaLayout;
/**
Expand Down
25 changes: 20 additions & 5 deletions Source/ASDisplayNode+Yoga.mm
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ - (ASLayout *)yogaCalculatedLayout
return _yogaCalculatedLayout;
}

- (BOOL)willApplyNextYogaCalculatedLayout {
return _willApplyNextYogaCalculatedLayout;
}

- (void)setWillApplyNextYogaCalculatedLayout:(BOOL)willApplyNextYogaCalculatedLayout {
_willApplyNextYogaCalculatedLayout = willApplyNextYogaCalculatedLayout;
}

- (void)setYogaLayoutInProgress:(BOOL)yogaLayoutInProgress
{
setFlag(YogaLayoutInProgress, yogaLayoutInProgress);
Expand Down Expand Up @@ -194,7 +202,7 @@ - (ASLayout *)layoutForYogaNode
return [ASLayout layoutWithLayoutElement:self size:size position:position sublayouts:nil];
}

- (void)setupYogaCalculatedLayout
- (void)setupYogaCalculatedLayoutAndSetNeedsLayoutForChangedNodes:(BOOL)setNeedsLayoutForChangedNodes
{
ASScopedLockSelfOrToRoot();

Expand Down Expand Up @@ -231,6 +239,13 @@ - (void)setupYogaCalculatedLayout
layout = [layout filteredNodeLayoutTree];

if ([self.yogaCalculatedLayout isEqual:layout] == NO) {
if (setNeedsLayoutForChangedNodes && !self.willApplyNextYogaCalculatedLayout) {
// This flag will be set when this layout is intended for immediate display. In this case, we
// want to ensure that we call setNeedsLayout on any other nodes. Note that we skip any nodes
// whose willApplyNextYogaCalculatedLayout flags are set, as those are the nodes that are
// already being laid out.
[self setNeedsLayout];
}
self.yogaCalculatedLayout = layout;
} else {
layout = self.yogaCalculatedLayout;
Expand Down Expand Up @@ -320,7 +335,7 @@ - (ASLayout *)calculateLayoutYoga:(ASSizeRange)constrainedSize
if (self.yogaLayoutInProgress == NO) {
ASYogaLog("Calculating yoga layout from root %@, %@", self,
NSStringFromASSizeRange(constrainedSize));
[self calculateLayoutFromYogaRoot:constrainedSize];
[self calculateLayoutFromYogaRoot:constrainedSize willApply:self.willApplyNextYogaCalculatedLayout];
} else {
ASYogaLog("Reusing existing yoga layout %@", _yogaCalculatedLayout);
}
Expand All @@ -337,15 +352,15 @@ - (ASLayout *)calculateLayoutYoga:(ASSizeRange)constrainedSize
return [self calculateLayoutLayoutSpec:constrainedSize];
}

- (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize
- (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize willApply:(BOOL)willApply
{
ASScopedLockSet lockSet = [self lockToRootIfNeededForLayout];
ASDisplayNode *yogaRoot = self.yogaRoot;

if (self != yogaRoot) {
ASYogaLog("ESCALATING to Yoga root: %@", self);
// TODO(appleguy): Consider how to get the constrainedSize for the yogaRoot when escalating manually.
[yogaRoot calculateLayoutFromYogaRoot:ASSizeRangeUnconstrained];
[yogaRoot calculateLayoutFromYogaRoot:ASSizeRangeUnconstrained willApply:willApply];
return;
}

Expand Down Expand Up @@ -398,7 +413,7 @@ - (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize
});

ASDisplayNodePerformBlockOnEveryYogaChild(self, ^(ASDisplayNode * _Nonnull node) {
[node setupYogaCalculatedLayout];
[node setupYogaCalculatedLayoutAndSetNeedsLayoutForChangedNodes:willApply];
node.yogaLayoutInProgress = NO;
});

Expand Down
1 change: 1 addition & 0 deletions Source/Private/ASDisplayNodeInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ AS_EXTERN NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimest
NSMutableArray<ASDisplayNode *> *_yogaChildren;
__weak ASDisplayNode *_yogaParent;
ASLayout *_yogaCalculatedLayout;
BOOL _willApplyNextYogaCalculatedLayout;
#endif

// Automatically manages subnodes
Expand Down

0 comments on commit 5937ac3

Please sign in to comment.