[Yoga] Rewrite YOGA_TREE_CONTIGUOUS mode with improved behavior and cleaner integration (#343)

* [Yoga] Rewrite YOGA_TREE_CONTIGUOUS mode with support for mixing with ASLayoutSpec.

After experimentation with the ASYogaLayoutSpec (or non-contiguous) approach to
integrating Yoga, test results and feedback from the authors of Yoga have shown
that this approach can't be made completely correct,

There are issues with some of the features required to represent Web-style
flexbox; in particular: padding, margins, and border handling have varience.

This diff is a first step towards a truly correct and elegant implementation of
Yoga integration with Texture. In addition to reducing the footprint of
the integration, which is an explicit goal of work at this stage, these changes
already support improved behavior - including mixing between ASLayoutSpecs
even as subnodes of Yoga layout-driven nodes, in addition to above them. Yoga
may be used for any set of nodes.

Because Yoga usage is limited at this time, it's safe to merge this diff and
further improvements will be refinements in this direction.

* [ASDKgram] Add Yoga layout implementation for PhotoCellNode.

* [Yoga] Final fixes for the upgraded implementation of the Contiguous layout mode.

* [Yoga] Add CHANGELOG.md entry and fix for Yoga rounding to screen scale.

* [Yoga] Minor cleanup to remove old comments and generalize utility methods.
This commit is contained in:
appleguy
2017-06-14 19:36:13 -07:00
committed by GitHub
parent 13f6f14e9f
commit 55928f343d
15 changed files with 450 additions and 155 deletions

View File

@@ -424,12 +424,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
[self _scheduleIvarsForMainDeallocation];
}
#if YOGA_TREE_CONTIGUOUS
if (_yogaNode != NULL) {
YGNodeFree(_yogaNode);
}
#endif
// TODO: Remove this? If supernode isn't already nil, this method isn't dealloc-safe anyway.
[self _setSupernode:nil];
}
@@ -966,22 +960,32 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
ASDN::MutexLocker l(__instanceLock__);
#if YOGA_TREE_CONTIGUOUS /* YOGA */
if (ASHierarchyStateIncludesYogaLayoutEnabled(_hierarchyState) == YES) {
if (ASHierarchyStateIncludesYogaLayoutMeasuring(_hierarchyState) == NO && self.yogaCalculatedLayout == nil) {
ASDN::MutexUnlocker ul(__instanceLock__);
// There are several cases where Yoga could arrive here:
// - This node is not in a Yoga tree: it has neither a yogaParent nor yogaChildren.
// - This node is a Yoga tree root: it has no yogaParent, but has yogaChildren.
// - This node is a Yoga tree node: it has both a yogaParent and yogaChildren.
// - This node is a Yoga tree leaf: it has a yogaParent, but no yogaChidlren.
// If we're a leaf node, we are probably being called by a measure function and proceed as normal.
// If we're a yoga root or tree node, initiate a new Yoga calculation pass from root.
YGNodeRef yogaNode = _style.yogaNode;
BOOL hasYogaParent = (_yogaParent != nil);
BOOL hasYogaChildren = (_yogaChildren.count > 0);
BOOL usesYoga = (yogaNode != NULL && (hasYogaParent || hasYogaChildren));
if (usesYoga && (_yogaParent == nil || _yogaChildren.count > 0)) {
// This node has some connection to a Yoga tree.
ASDN::MutexUnlocker ul(__instanceLock__);
if (self.yogaLayoutInProgress == NO) {
[self calculateLayoutFromYogaRoot:constrainedSize];
}
// The call above may set yogaCalculatedLayout, even if it tested as nil to enter it.
if (self.yogaCalculatedLayout && self.yogaChildren.count > 0) {
return self.yogaCalculatedLayout;
}
ASDisplayNodeAssert(_yogaCalculatedLayout, @"Yoga node should have a non-nil layout at this stage: %@", self);
return _yogaCalculatedLayout;
}
ASYogaLog(@"PROCEEDING past Yoga check to calculate ASLayout for: %@", self);
#endif /* YOGA */
// Manual size calculation via calculateSizeThatFits:
if (((_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) ||
(_layoutSpecBlock != NULL)) == NO) {
if (_layoutSpecBlock == NULL && (_methodOverrides & ASDisplayNodeMethodOverrideLayoutSpecThatFits) == 0) {
CGSize size = [self calculateSizeThatFits:constrainedSize.max];
ASDisplayNodeLogEvent(self, @"calculatedSize: %@", NSStringFromCGSize(size));
return [ASLayout layoutWithLayoutElement:self size:ASSizeRangeClamp(constrainedSize, size) sublayouts:nil];