2018-06-22 11:29:05 -07:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the MIT license found in the LICENSE
|
|
|
|
* file in the root directory of this source tree.
|
2015-08-13 16:56:41 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2017-12-05 08:16:49 -08:00
|
|
|
#include "Yoga.h"
|
2018-03-14 04:17:07 -07:00
|
|
|
#include <float.h>
|
2015-08-13 16:56:41 +08:00
|
|
|
#include <string.h>
|
2017-12-05 08:16:49 -08:00
|
|
|
#include <algorithm>
|
2018-01-10 04:30:27 -08:00
|
|
|
#include "Utils.h"
|
2017-12-19 11:18:00 -08:00
|
|
|
#include "YGNode.h"
|
2017-11-23 09:40:02 -08:00
|
|
|
#include "YGNodePrint.h"
|
2017-07-26 19:22:03 -07:00
|
|
|
#include "Yoga-internal.h"
|
2015-08-13 16:56:41 +08:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#include <float.h>
|
2016-11-07 12:54:03 -08:00
|
|
|
|
2015-08-13 16:56:41 +08:00
|
|
|
/* define fmaxf if < VC12 */
|
|
|
|
#if _MSC_VER < 1800
|
2016-08-15 09:15:02 -07:00
|
|
|
__forceinline const float fmaxf(const float a, const float b) {
|
2018-03-01 04:00:35 -08:00
|
|
|
if (!YGFloatIsUndefined(a) && !YGFloatIsUndefined(b)) {
|
|
|
|
return (a > b) ? a : b;
|
|
|
|
}
|
|
|
|
return YGFloatIsUndefined(a) ? b : a;
|
2016-08-15 09:15:02 -07:00
|
|
|
}
|
2015-08-13 16:56:41 +08:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2017-05-03 09:22:35 -07:00
|
|
|
#ifdef ANDROID
|
2018-07-19 09:57:04 -07:00
|
|
|
static int YGAndroidLog(
|
|
|
|
const YGConfigRef config,
|
|
|
|
const YGNodeRef node,
|
|
|
|
YGLogLevel level,
|
|
|
|
const char* format,
|
|
|
|
va_list args);
|
2017-05-03 09:22:35 -07:00
|
|
|
#else
|
2018-07-19 09:57:04 -07:00
|
|
|
static int YGDefaultLog(
|
|
|
|
const YGConfigRef config,
|
|
|
|
const YGNodeRef node,
|
|
|
|
YGLogLevel level,
|
|
|
|
const char* format,
|
|
|
|
va_list args);
|
2017-05-03 09:22:35 -07:00
|
|
|
#endif
|
|
|
|
|
2018-04-04 09:24:34 -07:00
|
|
|
const YGValue YGValueZero = {0, YGUnitPoint};
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined};
|
|
|
|
const YGValue YGValueAuto = {YGUndefined, YGUnitAuto};
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
|
2018-07-23 13:24:21 -07:00
|
|
|
bool operator==(const YGValue& lhs, const YGValue& rhs) {
|
|
|
|
if ((lhs.unit == YGUnitUndefined && rhs.unit == YGUnitUndefined) ||
|
|
|
|
(lhs.unit == YGUnitAuto && rhs.unit == YGUnitAuto)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lhs.unit == rhs.unit && lhs.value == rhs.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const YGValue& lhs, const YGValue& rhs) {
|
|
|
|
return !(lhs == rhs);
|
|
|
|
}
|
|
|
|
|
2016-10-23 10:56:11 -07:00
|
|
|
#ifdef ANDROID
|
|
|
|
#include <android/log.h>
|
2018-07-19 09:57:04 -07:00
|
|
|
static int YGAndroidLog(
|
|
|
|
const YGConfigRef config,
|
|
|
|
const YGNodeRef node,
|
|
|
|
YGLogLevel level,
|
|
|
|
const char* format,
|
|
|
|
va_list args) {
|
2016-12-02 05:47:43 -08:00
|
|
|
int androidLevel = YGLogLevelDebug;
|
2016-11-09 09:45:37 -08:00
|
|
|
switch (level) {
|
2017-05-03 09:22:35 -07:00
|
|
|
case YGLogLevelFatal:
|
|
|
|
androidLevel = ANDROID_LOG_FATAL;
|
|
|
|
break;
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGLogLevelError:
|
2016-11-09 09:45:37 -08:00
|
|
|
androidLevel = ANDROID_LOG_ERROR;
|
|
|
|
break;
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGLogLevelWarn:
|
2016-11-09 09:45:37 -08:00
|
|
|
androidLevel = ANDROID_LOG_WARN;
|
|
|
|
break;
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGLogLevelInfo:
|
2016-11-09 09:45:37 -08:00
|
|
|
androidLevel = ANDROID_LOG_INFO;
|
|
|
|
break;
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGLogLevelDebug:
|
2016-11-09 09:45:37 -08:00
|
|
|
androidLevel = ANDROID_LOG_DEBUG;
|
|
|
|
break;
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGLogLevelVerbose:
|
2016-11-09 09:45:37 -08:00
|
|
|
androidLevel = ANDROID_LOG_VERBOSE;
|
|
|
|
break;
|
|
|
|
}
|
2017-05-03 09:22:35 -07:00
|
|
|
const int result = __android_log_vprint(androidLevel, "yoga", format, args);
|
2016-10-23 10:56:11 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#else
|
2017-11-28 10:15:53 -08:00
|
|
|
#define YG_UNUSED(x) (void)(x);
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static int YGDefaultLog(
|
|
|
|
const YGConfigRef config,
|
|
|
|
const YGNodeRef node,
|
|
|
|
YGLogLevel level,
|
|
|
|
const char* format,
|
|
|
|
va_list args) {
|
2017-11-28 10:15:53 -08:00
|
|
|
YG_UNUSED(config);
|
|
|
|
YG_UNUSED(node);
|
2016-11-09 09:45:37 -08:00
|
|
|
switch (level) {
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGLogLevelError:
|
2017-05-03 09:22:35 -07:00
|
|
|
case YGLogLevelFatal:
|
2016-11-09 09:45:37 -08:00
|
|
|
return vfprintf(stderr, format, args);
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGLogLevelWarn:
|
|
|
|
case YGLogLevelInfo:
|
|
|
|
case YGLogLevelDebug:
|
|
|
|
case YGLogLevelVerbose:
|
2016-11-09 09:45:37 -08:00
|
|
|
default:
|
|
|
|
return vprintf(format, args);
|
|
|
|
}
|
|
|
|
}
|
2017-11-28 10:15:53 -08:00
|
|
|
|
|
|
|
#undef YG_UNUSED
|
2016-10-23 10:56:11 -07:00
|
|
|
#endif
|
2016-10-19 11:01:24 -07:00
|
|
|
|
2017-11-21 10:10:30 -08:00
|
|
|
bool YGFloatIsUndefined(const float value) {
|
2018-07-18 02:23:58 -07:00
|
|
|
return facebook::yoga::isUndefined(value);
|
2017-11-21 10:10:30 -08:00
|
|
|
}
|
|
|
|
|
2017-11-23 09:40:02 -08:00
|
|
|
const YGValue* YGComputedEdgeValue(
|
2017-12-19 11:18:00 -08:00
|
|
|
const std::array<YGValue, YGEdgeCount>& edges,
|
2017-11-23 09:40:02 -08:00
|
|
|
const YGEdge edge,
|
|
|
|
const YGValue* const defaultValue) {
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
if (edges[edge].unit != YGUnitUndefined) {
|
|
|
|
return &edges[edge];
|
2016-08-17 10:36:40 -07:00
|
|
|
}
|
|
|
|
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
if ((edge == YGEdgeTop || edge == YGEdgeBottom) &&
|
|
|
|
edges[YGEdgeVertical].unit != YGUnitUndefined) {
|
|
|
|
return &edges[YGEdgeVertical];
|
2016-08-17 10:36:40 -07:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
if ((edge == YGEdgeLeft || edge == YGEdgeRight || edge == YGEdgeStart ||
|
|
|
|
edge == YGEdgeEnd) &&
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
edges[YGEdgeHorizontal].unit != YGUnitUndefined) {
|
|
|
|
return &edges[YGEdgeHorizontal];
|
2016-08-17 10:36:40 -07:00
|
|
|
}
|
|
|
|
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
if (edges[YGEdgeAll].unit != YGUnitUndefined) {
|
|
|
|
return &edges[YGEdgeAll];
|
2016-08-17 10:36:40 -07:00
|
|
|
}
|
|
|
|
|
2016-12-02 05:47:43 -08:00
|
|
|
if (edge == YGEdgeStart || edge == YGEdgeEnd) {
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
return &YGValueUndefined;
|
2016-08-17 10:36:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return defaultValue;
|
|
|
|
}
|
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
void* YGNodeGetContext(YGNodeRef node) {
|
|
|
|
return node->getContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeSetContext(YGNodeRef node, void* context) {
|
|
|
|
return node->setContext(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
YGMeasureFunc YGNodeGetMeasureFunc(YGNodeRef node) {
|
|
|
|
return node->getMeasure();
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc) {
|
|
|
|
node->setMeasureFunc(measureFunc);
|
|
|
|
}
|
|
|
|
|
|
|
|
YGBaselineFunc YGNodeGetBaselineFunc(YGNodeRef node) {
|
|
|
|
return node->getBaseline();
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc) {
|
|
|
|
node->setBaseLineFunc(baselineFunc);
|
|
|
|
}
|
|
|
|
|
2018-01-15 15:35:51 -08:00
|
|
|
YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeRef node) {
|
|
|
|
return node->getDirtied();
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc) {
|
|
|
|
node->setDirtiedFunc(dirtiedFunc);
|
|
|
|
}
|
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
YGPrintFunc YGNodeGetPrintFunc(YGNodeRef node) {
|
|
|
|
return node->getPrintFunc();
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) {
|
|
|
|
node->setPrintFunc(printFunc);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool YGNodeGetHasNewLayout(YGNodeRef node) {
|
|
|
|
return node->getHasNewLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) {
|
|
|
|
node->setHasNewLayout(hasNewLayout);
|
|
|
|
}
|
|
|
|
|
|
|
|
YGNodeType YGNodeGetNodeType(YGNodeRef node) {
|
|
|
|
return node->getNodeType();
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType) {
|
|
|
|
return node->setNodeType(nodeType);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool YGNodeIsDirty(YGNodeRef node) {
|
|
|
|
return node->isDirty();
|
2017-02-14 14:26:09 -08:00
|
|
|
}
|
|
|
|
|
2018-02-02 07:38:17 -08:00
|
|
|
bool YGNodeLayoutGetDidUseLegacyFlag(const YGNodeRef node) {
|
|
|
|
return node->didUseLegacyFlag();
|
|
|
|
}
|
|
|
|
|
2018-02-08 04:51:12 -08:00
|
|
|
void YGNodeMarkDirtyAndPropogateToDescendants(const YGNodeRef node) {
|
|
|
|
return node->markDirtyAndPropogateDownwards();
|
|
|
|
}
|
|
|
|
|
2016-12-06 14:37:54 -08:00
|
|
|
int32_t gNodeInstanceCount = 0;
|
2017-04-10 14:22:23 -07:00
|
|
|
int32_t gConfigInstanceCount = 0;
|
2016-12-06 14:37:54 -08:00
|
|
|
|
2017-03-01 09:19:55 -08:00
|
|
|
WIN_EXPORT YGNodeRef YGNodeNewWithConfig(const YGConfigRef config) {
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGNodeRef node = new YGNode();
|
2017-11-21 10:10:30 -08:00
|
|
|
YGAssertWithConfig(
|
|
|
|
config, node != nullptr, "Could not allocate memory for node");
|
2016-12-06 14:37:54 -08:00
|
|
|
gNodeInstanceCount++;
|
|
|
|
|
2017-03-03 10:47:42 -08:00
|
|
|
if (config->useWebDefaults) {
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setStyleFlexDirection(YGFlexDirectionRow);
|
|
|
|
node->setStyleAlignContent(YGAlignStretch);
|
2017-03-03 10:47:42 -08:00
|
|
|
}
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setConfig(config);
|
2016-12-06 14:37:54 -08:00
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
2018-04-04 09:24:34 -07:00
|
|
|
YGConfigRef YGConfigGetDefault() {
|
|
|
|
static YGConfigRef defaultConfig = YGConfigNew();
|
|
|
|
return defaultConfig;
|
|
|
|
}
|
|
|
|
|
2017-03-01 09:19:55 -08:00
|
|
|
YGNodeRef YGNodeNew(void) {
|
2018-04-04 09:24:34 -07:00
|
|
|
return YGNodeNewWithConfig(YGConfigGetDefault());
|
2017-03-01 09:19:55 -08:00
|
|
|
}
|
|
|
|
|
2017-12-05 08:16:49 -08:00
|
|
|
YGNodeRef YGNodeClone(YGNodeRef oldNode) {
|
|
|
|
YGNodeRef node = new YGNode(*oldNode);
|
2017-11-21 10:10:30 -08:00
|
|
|
YGAssertWithConfig(
|
2017-12-19 11:18:00 -08:00
|
|
|
oldNode->getConfig(),
|
|
|
|
node != nullptr,
|
|
|
|
"Could not allocate memory for node");
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
gNodeInstanceCount++;
|
2018-04-01 18:27:06 -07:00
|
|
|
node->setOwner(nullptr);
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
2018-02-09 04:47:49 -08:00
|
|
|
static YGConfigRef YGConfigClone(const YGConfig& oldConfig) {
|
|
|
|
const YGConfigRef config = new YGConfig(oldConfig);
|
|
|
|
YGAssert(config != nullptr, "Could not allocate memory for config");
|
|
|
|
if (config == nullptr) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
gConfigInstanceCount++;
|
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
2018-02-02 07:38:17 -08:00
|
|
|
static YGNodeRef YGNodeDeepClone(YGNodeRef oldNode) {
|
|
|
|
YGNodeRef node = YGNodeClone(oldNode);
|
|
|
|
YGVector vec = YGVector();
|
|
|
|
vec.reserve(oldNode->getChildren().size());
|
|
|
|
YGNodeRef childNode = nullptr;
|
2018-07-13 12:34:46 -07:00
|
|
|
for (auto* item : oldNode->getChildren()) {
|
2018-02-02 07:38:17 -08:00
|
|
|
childNode = YGNodeDeepClone(item);
|
2018-04-01 18:27:06 -07:00
|
|
|
childNode->setOwner(node);
|
2018-02-02 07:38:17 -08:00
|
|
|
vec.push_back(childNode);
|
|
|
|
}
|
|
|
|
node->setChildren(vec);
|
|
|
|
|
2018-02-09 04:47:49 -08:00
|
|
|
if (oldNode->getConfig() != nullptr) {
|
|
|
|
node->setConfig(YGConfigClone(*(oldNode->getConfig())));
|
2018-02-02 07:38:17 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
2016-12-06 14:37:54 -08:00
|
|
|
void YGNodeFree(const YGNodeRef node) {
|
2018-04-01 18:27:06 -07:00
|
|
|
if (YGNodeRef owner = node->getOwner()) {
|
|
|
|
owner->removeChild(node);
|
|
|
|
node->setOwner(nullptr);
|
2016-12-06 14:37:54 -08:00
|
|
|
}
|
|
|
|
|
2016-12-16 04:39:13 -08:00
|
|
|
const uint32_t childCount = YGNodeGetChildCount(node);
|
2016-12-06 14:37:54 -08:00
|
|
|
for (uint32_t i = 0; i < childCount; i++) {
|
|
|
|
const YGNodeRef child = YGNodeGetChild(node, i);
|
2018-04-01 18:27:06 -07:00
|
|
|
child->setOwner(nullptr);
|
2016-12-06 14:37:54 -08:00
|
|
|
}
|
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
node->clearChildren();
|
2018-01-31 17:54:42 -08:00
|
|
|
delete node;
|
2016-12-06 14:37:54 -08:00
|
|
|
gNodeInstanceCount--;
|
|
|
|
}
|
|
|
|
|
2018-02-09 04:47:49 -08:00
|
|
|
static void YGConfigFreeRecursive(const YGNodeRef root) {
|
|
|
|
if (root->getConfig() != nullptr) {
|
|
|
|
gConfigInstanceCount--;
|
|
|
|
delete root->getConfig();
|
|
|
|
}
|
|
|
|
// Delete configs recursively for childrens
|
2018-07-13 12:34:46 -07:00
|
|
|
for (auto* child : root->getChildren()) {
|
|
|
|
YGConfigFreeRecursive(child);
|
2018-02-09 04:47:49 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-06 14:37:54 -08:00
|
|
|
void YGNodeFreeRecursive(const YGNodeRef root) {
|
2016-12-16 04:39:13 -08:00
|
|
|
while (YGNodeGetChildCount(root) > 0) {
|
2016-12-06 14:37:54 -08:00
|
|
|
const YGNodeRef child = YGNodeGetChild(root, 0);
|
2018-04-01 18:27:06 -07:00
|
|
|
if (child->getOwner() != root) {
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
// Don't free shared nodes that we don't own.
|
|
|
|
break;
|
|
|
|
}
|
2016-12-06 14:37:54 -08:00
|
|
|
YGNodeRemoveChild(root, child);
|
|
|
|
YGNodeFreeRecursive(child);
|
|
|
|
}
|
|
|
|
YGNodeFree(root);
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeReset(const YGNodeRef node) {
|
2018-07-19 09:57:04 -07:00
|
|
|
YGAssertWithNode(
|
|
|
|
node,
|
|
|
|
YGNodeGetChildCount(node) == 0,
|
|
|
|
"Cannot reset a node which still has children attached");
|
2017-11-21 10:10:30 -08:00
|
|
|
YGAssertWithNode(
|
|
|
|
node,
|
2018-04-01 18:27:06 -07:00
|
|
|
node->getOwner() == nullptr,
|
|
|
|
"Cannot reset a node still attached to a owner");
|
2016-12-06 14:37:54 -08:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
node->clearChildren();
|
2017-03-01 09:19:55 -08:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGConfigRef config = node->getConfig();
|
|
|
|
*node = YGNode();
|
2017-03-29 03:06:19 -07:00
|
|
|
if (config->useWebDefaults) {
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setStyleFlexDirection(YGFlexDirectionRow);
|
|
|
|
node->setStyleAlignContent(YGAlignStretch);
|
2017-03-29 03:06:19 -07:00
|
|
|
}
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setConfig(config);
|
2016-12-06 14:37:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
int32_t YGNodeGetInstanceCount(void) {
|
|
|
|
return gNodeInstanceCount;
|
|
|
|
}
|
|
|
|
|
2017-04-10 14:22:23 -07:00
|
|
|
int32_t YGConfigGetInstanceCount(void) {
|
|
|
|
return gConfigInstanceCount;
|
|
|
|
}
|
|
|
|
|
2017-03-01 09:19:55 -08:00
|
|
|
YGConfigRef YGConfigNew(void) {
|
2018-07-19 09:57:04 -07:00
|
|
|
#ifdef ANDROID
|
2018-04-04 09:24:34 -07:00
|
|
|
const YGConfigRef config = new YGConfig(YGAndroidLog);
|
2018-07-19 09:57:04 -07:00
|
|
|
#else
|
2018-04-04 09:24:34 -07:00
|
|
|
const YGConfigRef config = new YGConfig(YGDefaultLog);
|
2018-07-19 09:57:04 -07:00
|
|
|
#endif
|
2017-04-10 14:22:23 -07:00
|
|
|
gConfigInstanceCount++;
|
2017-03-01 09:19:55 -08:00
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGConfigFree(const YGConfigRef config) {
|
2017-11-21 10:10:30 -08:00
|
|
|
free(config);
|
2017-04-10 14:22:23 -07:00
|
|
|
gConfigInstanceCount--;
|
2017-03-01 09:19:55 -08:00
|
|
|
}
|
|
|
|
|
2017-04-26 11:49:26 -07:00
|
|
|
void YGConfigCopy(const YGConfigRef dest, const YGConfigRef src) {
|
|
|
|
memcpy(dest, src, sizeof(YGConfig));
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGNodeInsertChild(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGNodeRef child,
|
|
|
|
const uint32_t index) {
|
2018-04-04 10:30:16 -07:00
|
|
|
YGAssertWithNode(
|
|
|
|
node,
|
|
|
|
child->getOwner() == nullptr,
|
|
|
|
"Child already has a owner, it must be removed first.");
|
|
|
|
|
2017-11-21 10:10:30 -08:00
|
|
|
YGAssertWithNode(
|
|
|
|
node,
|
2018-04-01 18:27:08 -07:00
|
|
|
node->getMeasure() == nullptr,
|
|
|
|
"Cannot add child: Nodes with measure functions cannot have children.");
|
|
|
|
|
|
|
|
node->cloneChildrenIfNeeded();
|
|
|
|
node->insertChild(child, index);
|
|
|
|
YGNodeRef owner = child->getOwner() ? nullptr : node;
|
|
|
|
child->setOwner(owner);
|
|
|
|
node->markDirtyAndPropogate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeInsertSharedChild(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGNodeRef child,
|
|
|
|
const uint32_t index) {
|
2017-11-21 10:10:30 -08:00
|
|
|
YGAssertWithNode(
|
|
|
|
node,
|
2017-12-19 11:18:00 -08:00
|
|
|
node->getMeasure() == nullptr,
|
2017-11-21 10:10:30 -08:00
|
|
|
"Cannot add child: Nodes with measure functions cannot have children.");
|
2017-05-03 09:22:35 -07:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
node->insertChild(child, index);
|
2018-04-01 18:27:08 -07:00
|
|
|
child->setOwner(nullptr);
|
2018-01-08 02:48:35 -08:00
|
|
|
node->markDirtyAndPropogate();
|
2016-07-25 06:31:32 -07:00
|
|
|
}
|
|
|
|
|
2018-04-01 18:27:06 -07:00
|
|
|
void YGNodeRemoveChild(const YGNodeRef owner, const YGNodeRef excludedChild) {
|
2018-01-08 02:48:32 -08:00
|
|
|
// This algorithm is a forked variant from cloneChildrenIfNeeded in YGNode
|
|
|
|
// that excludes a child.
|
2018-04-01 18:27:06 -07:00
|
|
|
const uint32_t childCount = YGNodeGetChildCount(owner);
|
2017-12-05 08:16:49 -08:00
|
|
|
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
if (childCount == 0) {
|
|
|
|
// This is an empty set. Nothing to remove.
|
|
|
|
return;
|
|
|
|
}
|
2018-04-01 18:27:06 -07:00
|
|
|
const YGNodeRef firstChild = YGNodeGetChild(owner, 0);
|
|
|
|
if (firstChild->getOwner() == owner) {
|
2018-07-19 09:57:04 -07:00
|
|
|
// If the first child has this node as its owner, we assume that it is
|
|
|
|
// already unique. We can now try to delete a child in this list.
|
2018-04-01 18:27:06 -07:00
|
|
|
if (owner->removeChild(excludedChild)) {
|
2017-12-19 11:18:00 -08:00
|
|
|
excludedChild->setLayout(
|
|
|
|
YGNode().getLayout()); // layout is no longer valid
|
2018-04-01 18:27:06 -07:00
|
|
|
excludedChild->setOwner(nullptr);
|
|
|
|
owner->markDirtyAndPropogate();
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2018-07-19 09:57:04 -07:00
|
|
|
// Otherwise we have to clone the node list except for the child we're trying
|
|
|
|
// to delete. We don't want to simply clone all children, because then the
|
|
|
|
// host will need to free the clone of the child that was just deleted.
|
2018-04-01 18:27:04 -07:00
|
|
|
const YGCloneNodeFunc cloneNodeCallback =
|
2018-04-01 18:27:06 -07:00
|
|
|
owner->getConfig()->cloneNodeCallback;
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
uint32_t nextInsertIndex = 0;
|
|
|
|
for (uint32_t i = 0; i < childCount; i++) {
|
2018-04-01 18:27:06 -07:00
|
|
|
const YGNodeRef oldChild = owner->getChild(i);
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
if (excludedChild == oldChild) {
|
2018-07-19 09:57:04 -07:00
|
|
|
// Ignore the deleted child. Don't reset its layout or owner since it is
|
|
|
|
// still valid in the other owner. However, since this owner has now
|
|
|
|
// changed, we need to mark it as dirty.
|
2018-04-01 18:27:06 -07:00
|
|
|
owner->markDirtyAndPropogate();
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
continue;
|
|
|
|
}
|
2018-04-01 18:27:04 -07:00
|
|
|
YGNodeRef newChild = nullptr;
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
if (cloneNodeCallback) {
|
2018-04-01 18:27:06 -07:00
|
|
|
newChild = cloneNodeCallback(oldChild, owner, nextInsertIndex);
|
2018-04-01 18:27:04 -07:00
|
|
|
}
|
|
|
|
if (newChild == nullptr) {
|
|
|
|
newChild = YGNodeClone(oldChild);
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
}
|
2018-04-01 18:27:06 -07:00
|
|
|
owner->replaceChild(newChild, nextInsertIndex);
|
|
|
|
newChild->setOwner(owner);
|
2018-04-01 18:27:04 -07:00
|
|
|
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
nextInsertIndex++;
|
|
|
|
}
|
|
|
|
while (nextInsertIndex < childCount) {
|
2018-04-01 18:27:06 -07:00
|
|
|
owner->removeChild(nextInsertIndex);
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
nextInsertIndex++;
|
2016-11-03 13:30:34 -07:00
|
|
|
}
|
2016-07-25 06:31:32 -07:00
|
|
|
}
|
|
|
|
|
2018-04-01 18:27:06 -07:00
|
|
|
void YGNodeRemoveAllChildren(const YGNodeRef owner) {
|
|
|
|
const uint32_t childCount = YGNodeGetChildCount(owner);
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
if (childCount == 0) {
|
|
|
|
// This is an empty set already. Nothing to do.
|
|
|
|
return;
|
|
|
|
}
|
2018-04-01 18:27:06 -07:00
|
|
|
const YGNodeRef firstChild = YGNodeGetChild(owner, 0);
|
|
|
|
if (firstChild->getOwner() == owner) {
|
2018-07-19 09:57:04 -07:00
|
|
|
// If the first child has this node as its owner, we assume that this child
|
|
|
|
// set is unique.
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
for (uint32_t i = 0; i < childCount; i++) {
|
2018-04-01 18:27:06 -07:00
|
|
|
const YGNodeRef oldChild = YGNodeGetChild(owner, i);
|
2017-12-19 11:18:00 -08:00
|
|
|
oldChild->setLayout(YGNode().getLayout()); // layout is no longer valid
|
2018-04-01 18:27:06 -07:00
|
|
|
oldChild->setOwner(nullptr);
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
}
|
2018-04-01 18:27:06 -07:00
|
|
|
owner->clearChildren();
|
|
|
|
owner->markDirtyAndPropogate();
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
return;
|
|
|
|
}
|
2018-07-19 09:57:04 -07:00
|
|
|
// Otherwise, we are not the owner of the child set. We don't have to do
|
|
|
|
// anything to clear it.
|
2018-04-01 18:27:06 -07:00
|
|
|
owner->setChildren(YGVector());
|
|
|
|
owner->markDirtyAndPropogate();
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static void YGNodeSetChildrenInternal(
|
|
|
|
YGNodeRef const owner,
|
|
|
|
const std::vector<YGNodeRef>& children) {
|
2018-04-01 18:27:06 -07:00
|
|
|
if (!owner) {
|
2018-03-25 13:56:13 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (children.size() == 0) {
|
2018-04-01 18:27:06 -07:00
|
|
|
if (YGNodeGetChildCount(owner) > 0) {
|
|
|
|
for (YGNodeRef const child : owner->getChildren()) {
|
2018-03-25 13:56:13 -07:00
|
|
|
child->setLayout(YGLayout());
|
2018-04-01 18:27:06 -07:00
|
|
|
child->setOwner(nullptr);
|
2018-03-25 13:56:13 -07:00
|
|
|
}
|
2018-04-01 18:27:06 -07:00
|
|
|
owner->setChildren(YGVector());
|
|
|
|
owner->markDirtyAndPropogate();
|
2018-03-25 13:56:13 -07:00
|
|
|
}
|
|
|
|
} else {
|
2018-04-01 18:27:06 -07:00
|
|
|
if (YGNodeGetChildCount(owner) > 0) {
|
|
|
|
for (YGNodeRef const oldChild : owner->getChildren()) {
|
2018-07-19 09:57:04 -07:00
|
|
|
// Our new children may have nodes in common with the old children. We
|
|
|
|
// don't reset these common nodes.
|
|
|
|
if (std::find(children.begin(), children.end(), oldChild) ==
|
|
|
|
children.end()) {
|
2018-03-25 13:56:13 -07:00
|
|
|
oldChild->setLayout(YGLayout());
|
2018-04-01 18:27:06 -07:00
|
|
|
oldChild->setOwner(nullptr);
|
2018-03-25 13:56:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-04-01 18:27:06 -07:00
|
|
|
owner->setChildren(children);
|
2018-03-25 13:56:13 -07:00
|
|
|
for (YGNodeRef child : children) {
|
2018-04-01 18:27:06 -07:00
|
|
|
child->setOwner(owner);
|
2018-03-25 13:56:13 -07:00
|
|
|
}
|
2018-04-01 18:27:06 -07:00
|
|
|
owner->markDirtyAndPropogate();
|
2018-03-25 13:56:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGNodeSetChildren(
|
|
|
|
YGNodeRef const owner,
|
|
|
|
const YGNodeRef c[],
|
|
|
|
const uint32_t count) {
|
2018-03-25 13:56:13 -07:00
|
|
|
const YGVector children = {c, c + count};
|
2018-04-01 18:27:06 -07:00
|
|
|
YGNodeSetChildrenInternal(owner, children);
|
2018-03-25 13:56:13 -07:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGNodeSetChildren(
|
|
|
|
YGNodeRef const owner,
|
|
|
|
const std::vector<YGNodeRef>& children) {
|
2018-04-01 18:27:06 -07:00
|
|
|
YGNodeSetChildrenInternal(owner, children);
|
2018-03-25 13:56:13 -07:00
|
|
|
}
|
|
|
|
|
2016-12-03 04:40:18 -08:00
|
|
|
YGNodeRef YGNodeGetChild(const YGNodeRef node, const uint32_t index) {
|
2017-12-19 11:18:00 -08:00
|
|
|
if (index < node->getChildren().size()) {
|
|
|
|
return node->getChild(index);
|
2017-12-05 08:16:49 -08:00
|
|
|
}
|
|
|
|
return nullptr;
|
2016-07-25 06:31:32 -07:00
|
|
|
}
|
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
uint32_t YGNodeGetChildCount(const YGNodeRef node) {
|
2018-01-09 04:21:58 -08:00
|
|
|
return static_cast<uint32_t>(node->getChildren().size());
|
2016-12-15 08:49:51 -08:00
|
|
|
}
|
|
|
|
|
2018-04-01 18:27:06 -07:00
|
|
|
YGNodeRef YGNodeGetOwner(const YGNodeRef node) {
|
|
|
|
return node->getOwner();
|
2016-08-15 09:15:02 -07:00
|
|
|
}
|
2016-07-25 06:31:32 -07:00
|
|
|
|
2018-06-11 04:07:38 -07:00
|
|
|
YGNodeRef YGNodeGetParent(const YGNodeRef node) {
|
|
|
|
return node->getOwner();
|
|
|
|
}
|
|
|
|
|
2016-12-03 04:40:18 -08:00
|
|
|
void YGNodeMarkDirty(const YGNodeRef node) {
|
2017-11-21 10:10:30 -08:00
|
|
|
YGAssertWithNode(
|
|
|
|
node,
|
2017-12-19 11:18:00 -08:00
|
|
|
node->getMeasure() != nullptr,
|
2017-11-21 10:10:30 -08:00
|
|
|
"Only leaf nodes with custom measure functions"
|
|
|
|
"should manually mark themselves as dirty");
|
2017-05-03 09:22:35 -07:00
|
|
|
|
2018-01-08 02:48:35 -08:00
|
|
|
node->markDirtyAndPropogate();
|
2016-07-25 06:31:32 -07:00
|
|
|
}
|
|
|
|
|
2016-12-03 04:40:18 -08:00
|
|
|
void YGNodeCopyStyle(const YGNodeRef dstNode, const YGNodeRef srcNode) {
|
2017-12-19 11:18:00 -08:00
|
|
|
if (!(dstNode->getStyle() == srcNode->getStyle())) {
|
|
|
|
dstNode->setStyle(srcNode->getStyle());
|
2018-01-08 02:48:35 -08:00
|
|
|
dstNode->markDirtyAndPropogate();
|
2016-11-17 09:10:45 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-28 09:17:17 -08:00
|
|
|
float YGNodeStyleGetFlexGrow(const YGNodeRef node) {
|
2018-03-15 12:29:02 -07:00
|
|
|
return node->getStyle().flexGrow.isUndefined()
|
2017-12-19 11:18:00 -08:00
|
|
|
? kDefaultFlexGrow
|
2018-03-15 12:29:02 -07:00
|
|
|
: node->getStyle().flexGrow.getValue();
|
2016-10-24 03:34:54 -07:00
|
|
|
}
|
|
|
|
|
2017-02-28 09:17:17 -08:00
|
|
|
float YGNodeStyleGetFlexShrink(const YGNodeRef node) {
|
2018-03-15 12:29:02 -07:00
|
|
|
return node->getStyle().flexShrink.isUndefined()
|
2017-12-19 11:18:00 -08:00
|
|
|
? (node->getConfig()->useWebDefaults ? kWebDefaultFlexShrink
|
|
|
|
: kDefaultFlexShrink)
|
2018-03-15 12:29:02 -07:00
|
|
|
: node->getStyle().flexShrink.getValue();
|
2017-02-28 09:17:17 -08:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:08 -07:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
template <typename T, T YGStyle::*P>
|
|
|
|
struct StyleProp {
|
|
|
|
static T get(YGNodeRef node) {
|
|
|
|
return node->getStyle().*P;
|
|
|
|
}
|
|
|
|
static void set(YGNodeRef node, T newValue) {
|
|
|
|
if (node->getStyle().*P != newValue) {
|
|
|
|
YGStyle style = node->getStyle();
|
|
|
|
style.*P = newValue;
|
|
|
|
node->setStyle(style);
|
|
|
|
node->markDirtyAndPropogate();
|
|
|
|
}
|
2016-10-24 03:34:54 -07:00
|
|
|
}
|
2018-07-19 09:57:08 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
2016-10-24 03:34:54 -07:00
|
|
|
|
2018-04-04 09:24:34 -07:00
|
|
|
#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL( \
|
|
|
|
type, name, paramName, instanceName) \
|
|
|
|
void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
|
|
|
|
YGValue value = { \
|
|
|
|
YGFloatSanitize(paramName), \
|
|
|
|
YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
|
|
|
|
}; \
|
|
|
|
if ((node->getStyle().instanceName.value != value.value && \
|
|
|
|
value.unit != YGUnitUndefined) || \
|
|
|
|
node->getStyle().instanceName.unit != value.unit) { \
|
|
|
|
YGStyle style = node->getStyle(); \
|
|
|
|
style.instanceName = value; \
|
|
|
|
node->setStyle(style); \
|
|
|
|
node->markDirtyAndPropogate(); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
void YGNodeStyleSet##name##Percent( \
|
|
|
|
const YGNodeRef node, const type paramName) { \
|
|
|
|
YGValue value = { \
|
|
|
|
YGFloatSanitize(paramName), \
|
|
|
|
YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \
|
|
|
|
}; \
|
|
|
|
if ((node->getStyle().instanceName.value != value.value && \
|
|
|
|
value.unit != YGUnitUndefined) || \
|
|
|
|
node->getStyle().instanceName.unit != value.unit) { \
|
|
|
|
YGStyle style = node->getStyle(); \
|
|
|
|
\
|
|
|
|
style.instanceName = value; \
|
|
|
|
node->setStyle(style); \
|
|
|
|
node->markDirtyAndPropogate(); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \
|
|
|
|
type, name, paramName, instanceName) \
|
|
|
|
void YGNodeStyleSet##name(const YGNodeRef node, const type paramName) { \
|
|
|
|
YGValue value = { \
|
|
|
|
YGFloatSanitize(paramName), \
|
|
|
|
YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
|
|
|
|
}; \
|
|
|
|
if ((node->getStyle().instanceName.value != value.value && \
|
|
|
|
value.unit != YGUnitUndefined) || \
|
|
|
|
node->getStyle().instanceName.unit != value.unit) { \
|
|
|
|
YGStyle style = node->getStyle(); \
|
|
|
|
style.instanceName = value; \
|
|
|
|
node->setStyle(style); \
|
|
|
|
node->markDirtyAndPropogate(); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
void YGNodeStyleSet##name##Percent( \
|
|
|
|
const YGNodeRef node, const type paramName) { \
|
|
|
|
if (node->getStyle().instanceName.value != YGFloatSanitize(paramName) || \
|
|
|
|
node->getStyle().instanceName.unit != YGUnitPercent) { \
|
|
|
|
YGStyle style = node->getStyle(); \
|
|
|
|
style.instanceName.value = YGFloatSanitize(paramName); \
|
|
|
|
style.instanceName.unit = \
|
|
|
|
YGFloatIsUndefined(paramName) ? YGUnitAuto : YGUnitPercent; \
|
|
|
|
node->setStyle(style); \
|
|
|
|
node->markDirtyAndPropogate(); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
void YGNodeStyleSet##name##Auto(const YGNodeRef node) { \
|
|
|
|
if (node->getStyle().instanceName.unit != YGUnitAuto) { \
|
|
|
|
YGStyle style = node->getStyle(); \
|
|
|
|
style.instanceName.value = 0; \
|
|
|
|
style.instanceName.unit = YGUnitAuto; \
|
|
|
|
node->setStyle(style); \
|
|
|
|
node->markDirtyAndPropogate(); \
|
|
|
|
} \
|
2017-02-14 14:26:09 -08:00
|
|
|
}
|
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
#define YG_NODE_STYLE_PROPERTY_UNIT_IMPL(type, name, paramName, instanceName) \
|
|
|
|
YG_NODE_STYLE_PROPERTY_SETTER_UNIT_IMPL( \
|
|
|
|
float, name, paramName, instanceName) \
|
|
|
|
\
|
|
|
|
type YGNodeStyleGet##name(const YGNodeRef node) { \
|
2018-03-15 07:13:03 -07:00
|
|
|
YGValue value = node->getStyle().instanceName; \
|
2018-04-03 14:56:27 -07:00
|
|
|
if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
|
2018-03-15 07:13:03 -07:00
|
|
|
value.value = YGUndefined; \
|
|
|
|
} \
|
|
|
|
return value; \
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
}
|
|
|
|
|
2018-04-03 14:56:27 -07:00
|
|
|
#define YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL( \
|
|
|
|
type, name, paramName, instanceName) \
|
|
|
|
YG_NODE_STYLE_PROPERTY_SETTER_UNIT_AUTO_IMPL( \
|
|
|
|
float, name, paramName, instanceName) \
|
|
|
|
\
|
|
|
|
type YGNodeStyleGet##name(const YGNodeRef node) { \
|
|
|
|
YGValue value = node->getStyle().instanceName; \
|
|
|
|
if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
|
|
|
|
value.value = YGUndefined; \
|
|
|
|
} \
|
|
|
|
return value; \
|
2017-02-14 14:26:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(type, name, instanceName) \
|
|
|
|
void YGNodeStyleSet##name##Auto(const YGNodeRef node, const YGEdge edge) { \
|
2017-12-19 11:18:00 -08:00
|
|
|
if (node->getStyle().instanceName[edge].unit != YGUnitAuto) { \
|
|
|
|
YGStyle style = node->getStyle(); \
|
2018-03-15 07:13:02 -07:00
|
|
|
style.instanceName[edge].value = 0; \
|
2017-12-19 11:18:00 -08:00
|
|
|
style.instanceName[edge].unit = YGUnitAuto; \
|
|
|
|
node->setStyle(style); \
|
2018-01-08 02:48:35 -08:00
|
|
|
node->markDirtyAndPropogate(); \
|
2017-02-14 14:26:09 -08:00
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
2018-04-04 09:24:34 -07:00
|
|
|
#define YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL( \
|
|
|
|
type, name, paramName, instanceName) \
|
|
|
|
void YGNodeStyleSet##name( \
|
|
|
|
const YGNodeRef node, const YGEdge edge, const float paramName) { \
|
|
|
|
YGValue value = { \
|
|
|
|
YGFloatSanitize(paramName), \
|
|
|
|
YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPoint, \
|
|
|
|
}; \
|
|
|
|
if ((node->getStyle().instanceName[edge].value != value.value && \
|
|
|
|
value.unit != YGUnitUndefined) || \
|
|
|
|
node->getStyle().instanceName[edge].unit != value.unit) { \
|
|
|
|
YGStyle style = node->getStyle(); \
|
|
|
|
style.instanceName[edge] = value; \
|
|
|
|
node->setStyle(style); \
|
|
|
|
node->markDirtyAndPropogate(); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
void YGNodeStyleSet##name##Percent( \
|
|
|
|
const YGNodeRef node, const YGEdge edge, const float paramName) { \
|
|
|
|
YGValue value = { \
|
|
|
|
YGFloatSanitize(paramName), \
|
|
|
|
YGFloatIsUndefined(paramName) ? YGUnitUndefined : YGUnitPercent, \
|
|
|
|
}; \
|
|
|
|
if ((node->getStyle().instanceName[edge].value != value.value && \
|
|
|
|
value.unit != YGUnitUndefined) || \
|
|
|
|
node->getStyle().instanceName[edge].unit != value.unit) { \
|
|
|
|
YGStyle style = node->getStyle(); \
|
|
|
|
style.instanceName[edge] = value; \
|
|
|
|
node->setStyle(style); \
|
|
|
|
node->markDirtyAndPropogate(); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
WIN_STRUCT(type) \
|
|
|
|
YGNodeStyleGet##name(const YGNodeRef node, const YGEdge edge) { \
|
|
|
|
YGValue value = node->getStyle().instanceName[edge]; \
|
|
|
|
if (value.unit == YGUnitUndefined || value.unit == YGUnitAuto) { \
|
|
|
|
value.value = YGUndefined; \
|
|
|
|
} \
|
|
|
|
return WIN_STRUCT_REF(value); \
|
2016-08-15 09:15:10 -07:00
|
|
|
}
|
|
|
|
|
2016-12-03 04:40:18 -08:00
|
|
|
#define YG_NODE_LAYOUT_PROPERTY_IMPL(type, name, instanceName) \
|
|
|
|
type YGNodeLayoutGet##name(const YGNodeRef node) { \
|
2017-12-19 11:18:00 -08:00
|
|
|
return node->getLayout().instanceName; \
|
2016-08-15 09:15:02 -07:00
|
|
|
}
|
2016-07-25 06:31:32 -07:00
|
|
|
|
2017-11-27 02:54:59 -08:00
|
|
|
#define YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(type, name, instanceName) \
|
|
|
|
type YGNodeLayoutGet##name(const YGNodeRef node, const YGEdge edge) { \
|
|
|
|
YGAssertWithNode( \
|
|
|
|
node, \
|
|
|
|
edge <= YGEdgeEnd, \
|
|
|
|
"Cannot get layout properties of multi-edge shorthands"); \
|
|
|
|
\
|
|
|
|
if (edge == YGEdgeLeft) { \
|
2017-12-19 11:18:00 -08:00
|
|
|
if (node->getLayout().direction == YGDirectionRTL) { \
|
|
|
|
return node->getLayout().instanceName[YGEdgeEnd]; \
|
2017-11-27 02:54:59 -08:00
|
|
|
} else { \
|
2017-12-19 11:18:00 -08:00
|
|
|
return node->getLayout().instanceName[YGEdgeStart]; \
|
2017-11-27 02:54:59 -08:00
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
if (edge == YGEdgeRight) { \
|
2017-12-19 11:18:00 -08:00
|
|
|
if (node->getLayout().direction == YGDirectionRTL) { \
|
|
|
|
return node->getLayout().instanceName[YGEdgeStart]; \
|
2017-11-27 02:54:59 -08:00
|
|
|
} else { \
|
2017-12-19 11:18:00 -08:00
|
|
|
return node->getLayout().instanceName[YGEdgeEnd]; \
|
2017-11-27 02:54:59 -08:00
|
|
|
} \
|
|
|
|
} \
|
|
|
|
\
|
2017-12-19 11:18:00 -08:00
|
|
|
return node->getLayout().instanceName[edge]; \
|
2017-01-15 15:16:10 -08:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:08 -07:00
|
|
|
void YGNodeStyleSetDirection(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGDirection direction) {
|
|
|
|
StyleProp<YGDirection, &YGStyle::direction>::set(node, direction);
|
|
|
|
}
|
|
|
|
YGDirection YGNodeStyleGetDirection(const YGNodeRef node) {
|
|
|
|
return StyleProp<YGDirection, &YGStyle::direction>::get(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeStyleSetFlexDirection(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGFlexDirection flexDirection) {
|
|
|
|
StyleProp<YGFlexDirection, &YGStyle::flexDirection>::set(node, flexDirection);
|
|
|
|
}
|
|
|
|
YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeRef node) {
|
|
|
|
return StyleProp<YGFlexDirection, &YGStyle::flexDirection>::get(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeStyleSetJustifyContent(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGJustify justifyContent) {
|
|
|
|
StyleProp<YGJustify, &YGStyle::justifyContent>::set(node, justifyContent);
|
|
|
|
}
|
|
|
|
YGJustify YGNodeStyleGetJustifyContent(const YGNodeRef node) {
|
|
|
|
return StyleProp<YGJustify, &YGStyle::justifyContent>::get(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeStyleSetAlignContent(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGAlign alignContent) {
|
|
|
|
StyleProp<YGAlign, &YGStyle::alignContent>::set(node, alignContent);
|
|
|
|
}
|
|
|
|
YGAlign YGNodeStyleGetAlignContent(const YGNodeRef node) {
|
|
|
|
return StyleProp<YGAlign, &YGStyle::alignContent>::get(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeStyleSetAlignItems(const YGNodeRef node, const YGAlign alignItems) {
|
|
|
|
StyleProp<YGAlign, &YGStyle::alignItems>::set(node, alignItems);
|
|
|
|
}
|
|
|
|
YGAlign YGNodeStyleGetAlignItems(const YGNodeRef node) {
|
|
|
|
return StyleProp<YGAlign, &YGStyle::alignItems>::get(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeStyleSetAlignSelf(const YGNodeRef node, const YGAlign alignSelf) {
|
|
|
|
StyleProp<YGAlign, &YGStyle::alignSelf>::set(node, alignSelf);
|
|
|
|
}
|
|
|
|
YGAlign YGNodeStyleGetAlignSelf(const YGNodeRef node) {
|
|
|
|
return StyleProp<YGAlign, &YGStyle::alignSelf>::get(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeStyleSetPositionType(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGPositionType positionType) {
|
|
|
|
StyleProp<YGPositionType, &YGStyle::positionType>::set(node, positionType);
|
|
|
|
}
|
|
|
|
YGPositionType YGNodeStyleGetPositionType(const YGNodeRef node) {
|
|
|
|
return StyleProp<YGPositionType, &YGStyle::positionType>::get(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeStyleSetFlexWrap(const YGNodeRef node, const YGWrap flexWrap) {
|
|
|
|
StyleProp<YGWrap, &YGStyle::flexWrap>::set(node, flexWrap);
|
|
|
|
}
|
|
|
|
YGWrap YGNodeStyleGetFlexWrap(const YGNodeRef node) {
|
|
|
|
return StyleProp<YGWrap, &YGStyle::flexWrap>::get(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeStyleSetOverflow(const YGNodeRef node, const YGOverflow overflow) {
|
|
|
|
StyleProp<YGOverflow, &YGStyle::overflow>::set(node, overflow);
|
|
|
|
}
|
|
|
|
YGOverflow YGNodeStyleGetOverflow(const YGNodeRef node) {
|
|
|
|
return StyleProp<YGOverflow, &YGStyle::overflow>::get(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeStyleSetDisplay(const YGNodeRef node, const YGDisplay display) {
|
|
|
|
StyleProp<YGDisplay, &YGStyle::display>::set(node, display);
|
|
|
|
}
|
|
|
|
YGDisplay YGNodeStyleGetDisplay(const YGNodeRef node) {
|
|
|
|
return StyleProp<YGDisplay, &YGStyle::display>::get(node);
|
|
|
|
}
|
2016-10-24 03:34:54 -07:00
|
|
|
|
2018-03-14 04:17:09 -07:00
|
|
|
// TODO(T26792433): Change the API to accept YGFloatOptional.
|
|
|
|
void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) {
|
2018-04-03 14:56:31 -07:00
|
|
|
if (node->getStyle().flex != flex) {
|
2018-03-14 04:17:09 -07:00
|
|
|
YGStyle style = node->getStyle();
|
|
|
|
if (YGFloatIsUndefined(flex)) {
|
2018-03-15 12:29:02 -07:00
|
|
|
style.flex = YGFloatOptional();
|
2018-03-14 04:17:09 -07:00
|
|
|
} else {
|
2018-03-15 12:29:02 -07:00
|
|
|
style.flex = YGFloatOptional(flex);
|
2018-03-14 04:17:09 -07:00
|
|
|
}
|
|
|
|
node->setStyle(style);
|
|
|
|
node->markDirtyAndPropogate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(T26792433): Change the API to accept YGFloatOptional.
|
|
|
|
float YGNodeStyleGetFlex(const YGNodeRef node) {
|
2018-03-15 12:29:02 -07:00
|
|
|
return node->getStyle().flex.isUndefined() ? YGUndefined
|
|
|
|
: node->getStyle().flex.getValue();
|
2018-03-14 04:17:09 -07:00
|
|
|
}
|
|
|
|
|
2018-03-14 04:17:11 -07:00
|
|
|
// TODO(T26792433): Change the API to accept YGFloatOptional.
|
|
|
|
void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) {
|
2018-04-03 14:56:31 -07:00
|
|
|
if (node->getStyle().flexGrow != flexGrow) {
|
2018-03-14 04:17:11 -07:00
|
|
|
YGStyle style = node->getStyle();
|
|
|
|
if (YGFloatIsUndefined(flexGrow)) {
|
2018-03-15 12:29:02 -07:00
|
|
|
style.flexGrow = YGFloatOptional();
|
2018-03-14 04:17:11 -07:00
|
|
|
} else {
|
2018-03-15 12:29:02 -07:00
|
|
|
style.flexGrow = YGFloatOptional(flexGrow);
|
2018-03-14 04:17:11 -07:00
|
|
|
}
|
|
|
|
node->setStyle(style);
|
|
|
|
node->markDirtyAndPropogate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-14 04:17:16 -07:00
|
|
|
// TODO(T26792433): Change the API to accept YGFloatOptional.
|
|
|
|
void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) {
|
2018-04-03 14:56:31 -07:00
|
|
|
if (node->getStyle().flexShrink != flexShrink) {
|
2018-03-14 04:17:16 -07:00
|
|
|
YGStyle style = node->getStyle();
|
|
|
|
if (YGFloatIsUndefined(flexShrink)) {
|
2018-03-15 12:29:02 -07:00
|
|
|
style.flexShrink = YGFloatOptional();
|
2018-03-14 04:17:16 -07:00
|
|
|
} else {
|
2018-03-15 12:29:02 -07:00
|
|
|
style.flexShrink = YGFloatOptional(flexShrink);
|
2018-03-14 04:17:16 -07:00
|
|
|
}
|
|
|
|
node->setStyle(style);
|
|
|
|
node->markDirtyAndPropogate();
|
|
|
|
}
|
|
|
|
}
|
2016-07-25 06:31:32 -07:00
|
|
|
|
2018-03-14 04:17:18 -07:00
|
|
|
YGValue YGNodeStyleGetFlexBasis(const YGNodeRef node) {
|
|
|
|
YGValue flexBasis = node->getStyle().flexBasis;
|
|
|
|
if (flexBasis.unit == YGUnitUndefined || flexBasis.unit == YGUnitAuto) {
|
|
|
|
// TODO(T26792433): Get rid off the use of YGUndefined at client side
|
|
|
|
flexBasis.value = YGUndefined;
|
|
|
|
}
|
|
|
|
return flexBasis;
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) {
|
|
|
|
YGValue value = {
|
2018-04-04 09:24:34 -07:00
|
|
|
YGFloatSanitize(flexBasis),
|
|
|
|
YGFloatIsUndefined(flexBasis) ? YGUnitUndefined : YGUnitPoint,
|
2018-03-14 04:17:18 -07:00
|
|
|
};
|
|
|
|
if ((node->getStyle().flexBasis.value != value.value &&
|
|
|
|
value.unit != YGUnitUndefined) ||
|
|
|
|
node->getStyle().flexBasis.unit != value.unit) {
|
|
|
|
YGStyle style = node->getStyle();
|
|
|
|
style.flexBasis = value;
|
|
|
|
node->setStyle(style);
|
|
|
|
node->markDirtyAndPropogate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeStyleSetFlexBasisPercent(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const float flexBasisPercent) {
|
|
|
|
if (node->getStyle().flexBasis.value != flexBasisPercent ||
|
|
|
|
node->getStyle().flexBasis.unit != YGUnitPercent) {
|
|
|
|
YGStyle style = node->getStyle();
|
|
|
|
style.flexBasis.value = YGFloatSanitize(flexBasisPercent);
|
|
|
|
style.flexBasis.unit =
|
|
|
|
YGFloatIsUndefined(flexBasisPercent) ? YGUnitAuto : YGUnitPercent;
|
|
|
|
node->setStyle(style);
|
|
|
|
node->markDirtyAndPropogate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) {
|
|
|
|
if (node->getStyle().flexBasis.unit != YGUnitAuto) {
|
|
|
|
YGStyle style = node->getStyle();
|
|
|
|
style.flexBasis.value = 0;
|
|
|
|
style.flexBasis.unit = YGUnitAuto;
|
|
|
|
node->setStyle(style);
|
|
|
|
node->markDirtyAndPropogate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-03 11:19:40 -08:00
|
|
|
YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Position, position, position);
|
|
|
|
YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Margin, margin, margin);
|
2017-02-14 14:26:09 -08:00
|
|
|
YG_NODE_STYLE_EDGE_PROPERTY_UNIT_AUTO_IMPL(YGValue, Margin, margin);
|
2017-02-03 11:19:40 -08:00
|
|
|
YG_NODE_STYLE_EDGE_PROPERTY_UNIT_IMPL(YGValue, Padding, padding, padding);
|
2018-03-14 04:17:05 -07:00
|
|
|
|
2018-03-14 04:17:09 -07:00
|
|
|
// TODO(T26792433): Change the API to accept YGFloatOptional.
|
2018-03-14 04:17:05 -07:00
|
|
|
void YGNodeStyleSetBorder(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGEdge edge,
|
|
|
|
const float border) {
|
|
|
|
YGValue value = {
|
2018-04-04 09:24:34 -07:00
|
|
|
YGFloatSanitize(border),
|
|
|
|
YGFloatIsUndefined(border) ? YGUnitUndefined : YGUnitPoint,
|
2018-03-14 04:17:05 -07:00
|
|
|
};
|
|
|
|
if ((node->getStyle().border[edge].value != value.value &&
|
|
|
|
value.unit != YGUnitUndefined) ||
|
|
|
|
node->getStyle().border[edge].unit != value.unit) {
|
|
|
|
YGStyle style = node->getStyle();
|
|
|
|
style.border[edge] = value;
|
|
|
|
node->setStyle(style);
|
|
|
|
node->markDirtyAndPropogate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float YGNodeStyleGetBorder(const YGNodeRef node, const YGEdge edge) {
|
2018-03-15 07:13:02 -07:00
|
|
|
if (node->getStyle().border[edge].unit == YGUnitUndefined ||
|
|
|
|
node->getStyle().border[edge].unit == YGUnitAuto) {
|
2018-03-14 04:17:09 -07:00
|
|
|
// TODO(T26792433): Rather than returning YGUndefined, change the api to
|
|
|
|
// return YGFloatOptional.
|
2018-03-14 04:17:05 -07:00
|
|
|
return YGUndefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
return node->getStyle().border[edge].value;
|
|
|
|
}
|
2016-07-25 06:31:32 -07:00
|
|
|
|
2018-04-03 14:56:29 -07:00
|
|
|
// Yoga specific properties, not compatible with flexbox specification
|
|
|
|
|
|
|
|
// TODO(T26792433): Change the API to accept YGFloatOptional.
|
|
|
|
float YGNodeStyleGetAspectRatio(const YGNodeRef node) {
|
|
|
|
const YGFloatOptional op = node->getStyle().aspectRatio;
|
|
|
|
return op.isUndefined() ? YGUndefined : op.getValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(T26792433): Change the API to accept YGFloatOptional.
|
|
|
|
void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) {
|
2018-04-03 14:56:31 -07:00
|
|
|
if (node->getStyle().aspectRatio != aspectRatio) {
|
2018-04-03 14:56:29 -07:00
|
|
|
YGStyle style = node->getStyle();
|
|
|
|
style.aspectRatio = YGFloatOptional(aspectRatio);
|
|
|
|
node->setStyle(style);
|
|
|
|
node->markDirtyAndPropogate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(
|
|
|
|
YGValue,
|
|
|
|
Width,
|
|
|
|
width,
|
|
|
|
dimensions[YGDimensionWidth]);
|
|
|
|
YG_NODE_STYLE_PROPERTY_UNIT_AUTO_IMPL(
|
|
|
|
YGValue,
|
|
|
|
Height,
|
|
|
|
height,
|
|
|
|
dimensions[YGDimensionHeight]);
|
|
|
|
YG_NODE_STYLE_PROPERTY_UNIT_IMPL(
|
|
|
|
YGValue,
|
|
|
|
MinWidth,
|
|
|
|
minWidth,
|
|
|
|
minDimensions[YGDimensionWidth]);
|
|
|
|
YG_NODE_STYLE_PROPERTY_UNIT_IMPL(
|
|
|
|
YGValue,
|
|
|
|
MinHeight,
|
|
|
|
minHeight,
|
|
|
|
minDimensions[YGDimensionHeight]);
|
|
|
|
YG_NODE_STYLE_PROPERTY_UNIT_IMPL(
|
|
|
|
YGValue,
|
|
|
|
MaxWidth,
|
|
|
|
maxWidth,
|
|
|
|
maxDimensions[YGDimensionWidth]);
|
|
|
|
YG_NODE_STYLE_PROPERTY_UNIT_IMPL(
|
|
|
|
YGValue,
|
|
|
|
MaxHeight,
|
|
|
|
maxHeight,
|
|
|
|
maxDimensions[YGDimensionHeight]);
|
2016-12-03 04:40:18 -08:00
|
|
|
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Left, position[YGEdgeLeft]);
|
|
|
|
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Top, position[YGEdgeTop]);
|
|
|
|
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Right, position[YGEdgeRight]);
|
|
|
|
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Bottom, position[YGEdgeBottom]);
|
|
|
|
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Width, dimensions[YGDimensionWidth]);
|
|
|
|
YG_NODE_LAYOUT_PROPERTY_IMPL(float, Height, dimensions[YGDimensionHeight]);
|
|
|
|
YG_NODE_LAYOUT_PROPERTY_IMPL(YGDirection, Direction, direction);
|
2017-06-30 09:19:33 -07:00
|
|
|
YG_NODE_LAYOUT_PROPERTY_IMPL(bool, HadOverflow, hadOverflow);
|
2016-07-25 06:31:32 -07:00
|
|
|
|
2017-01-15 15:16:10 -08:00
|
|
|
YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Margin, margin);
|
2017-01-26 13:36:38 -08:00
|
|
|
YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Border, border);
|
2017-01-15 15:16:10 -08:00
|
|
|
YG_NODE_LAYOUT_RESOLVED_PROPERTY_IMPL(float, Padding, padding);
|
2017-01-05 12:48:07 -08:00
|
|
|
|
2018-03-14 08:37:55 -07:00
|
|
|
bool YGNodeLayoutGetDidLegacyStretchFlagAffectLayout(const YGNodeRef node) {
|
|
|
|
return node->getLayout().doesLegacyStretchFlagAffectsLayout;
|
|
|
|
}
|
|
|
|
|
2016-08-02 08:06:55 -07:00
|
|
|
uint32_t gCurrentGenerationCount = 0;
|
2016-07-25 06:31:32 -07:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
bool YGLayoutNodeInternal(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const float availableWidth,
|
|
|
|
const float availableHeight,
|
|
|
|
const YGDirection ownerDirection,
|
|
|
|
const YGMeasureMode widthMeasureMode,
|
|
|
|
const YGMeasureMode heightMeasureMode,
|
|
|
|
const float ownerWidth,
|
|
|
|
const float ownerHeight,
|
|
|
|
const bool performLayout,
|
|
|
|
const char* reason,
|
|
|
|
const YGConfigRef config);
|
|
|
|
|
|
|
|
static void YGNodePrintInternal(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGPrintOptions options) {
|
2017-11-23 09:40:02 -08:00
|
|
|
std::string str;
|
|
|
|
facebook::yoga::YGNodeToString(&str, node, options, 0);
|
|
|
|
YGLog(node, YGLogLevelDebug, str.c_str());
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2016-12-03 04:40:18 -08:00
|
|
|
void YGNodePrint(const YGNodeRef node, const YGPrintOptions options) {
|
2017-09-21 07:30:21 -07:00
|
|
|
YGNodePrintInternal(node, options);
|
2016-08-15 09:15:02 -07:00
|
|
|
}
|
2015-08-13 16:56:41 +08:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
const std::array<YGEdge, 4> leading = {
|
|
|
|
{YGEdgeTop, YGEdgeBottom, YGEdgeLeft, YGEdgeRight}};
|
|
|
|
|
|
|
|
const std::array<YGEdge, 4> trailing = {
|
|
|
|
{YGEdgeBottom, YGEdgeTop, YGEdgeRight, YGEdgeLeft}};
|
|
|
|
static const std::array<YGEdge, 4> pos = {{
|
|
|
|
YGEdgeTop,
|
|
|
|
YGEdgeBottom,
|
|
|
|
YGEdgeLeft,
|
|
|
|
YGEdgeRight,
|
|
|
|
}};
|
2018-01-11 04:47:45 -08:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
static const std::array<YGDimension, 4> dim = {
|
|
|
|
{YGDimensionHeight, YGDimensionHeight, YGDimensionWidth, YGDimensionWidth}};
|
2015-08-13 16:56:41 +08:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static inline float YGNodePaddingAndBorderForAxis(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGFlexDirection axis,
|
|
|
|
const float widthSize) {
|
2018-04-04 07:55:37 -07:00
|
|
|
return YGUnwrapFloatOptional(
|
|
|
|
node->getLeadingPaddingAndBorder(axis, widthSize) +
|
|
|
|
node->getTrailingPaddingAndBorder(axis, widthSize));
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static inline YGAlign YGNodeAlignItem(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGNodeRef child) {
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGAlign align = child->getStyle().alignSelf == YGAlignAuto
|
|
|
|
? node->getStyle().alignItems
|
|
|
|
: child->getStyle().alignSelf;
|
|
|
|
if (align == YGAlignBaseline &&
|
|
|
|
YGFlexDirectionIsColumn(node->getStyle().flexDirection)) {
|
2017-01-06 06:51:56 -08:00
|
|
|
return YGAlignFlexStart;
|
|
|
|
}
|
|
|
|
return align;
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2017-01-06 06:51:56 -08:00
|
|
|
static float YGBaseline(const YGNodeRef node) {
|
2017-12-19 11:18:00 -08:00
|
|
|
if (node->getBaseline() != nullptr) {
|
|
|
|
const float baseline = node->getBaseline()(
|
|
|
|
node,
|
|
|
|
node->getLayout().measuredDimensions[YGDimensionWidth],
|
|
|
|
node->getLayout().measuredDimensions[YGDimensionHeight]);
|
2018-07-19 09:57:04 -07:00
|
|
|
YGAssertWithNode(
|
|
|
|
node,
|
|
|
|
!YGFloatIsUndefined(baseline),
|
|
|
|
"Expect custom baseline function to not return NaN");
|
2017-01-06 06:51:56 -08:00
|
|
|
return baseline;
|
|
|
|
}
|
|
|
|
|
2017-11-21 10:10:30 -08:00
|
|
|
YGNodeRef baselineChild = nullptr;
|
2017-02-15 13:35:24 -08:00
|
|
|
const uint32_t childCount = YGNodeGetChildCount(node);
|
|
|
|
for (uint32_t i = 0; i < childCount; i++) {
|
2017-01-06 06:51:56 -08:00
|
|
|
const YGNodeRef child = YGNodeGetChild(node, i);
|
2017-12-19 11:18:00 -08:00
|
|
|
if (child->getLineIndex() > 0) {
|
2017-01-06 06:51:56 -08:00
|
|
|
break;
|
|
|
|
}
|
2017-12-19 11:18:00 -08:00
|
|
|
if (child->getStyle().positionType == YGPositionTypeAbsolute) {
|
2017-01-06 06:51:56 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
|
|
|
|
baselineChild = child;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-11-21 10:10:30 -08:00
|
|
|
if (baselineChild == nullptr) {
|
2017-01-06 06:51:56 -08:00
|
|
|
baselineChild = child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-21 10:10:30 -08:00
|
|
|
if (baselineChild == nullptr) {
|
2017-12-19 11:18:00 -08:00
|
|
|
return node->getLayout().measuredDimensions[YGDimensionHeight];
|
2017-01-06 06:51:56 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
const float baseline = YGBaseline(baselineChild);
|
2017-12-19 11:18:00 -08:00
|
|
|
return baseline + baselineChild->getLayout().position[YGEdgeTop];
|
2017-01-06 06:51:56 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool YGIsBaselineLayout(const YGNodeRef node) {
|
2017-12-19 11:18:00 -08:00
|
|
|
if (YGFlexDirectionIsColumn(node->getStyle().flexDirection)) {
|
2017-01-06 06:51:56 -08:00
|
|
|
return false;
|
|
|
|
}
|
2017-12-19 11:18:00 -08:00
|
|
|
if (node->getStyle().alignItems == YGAlignBaseline) {
|
2017-01-06 06:51:56 -08:00
|
|
|
return true;
|
|
|
|
}
|
2017-02-15 13:35:24 -08:00
|
|
|
const uint32_t childCount = YGNodeGetChildCount(node);
|
|
|
|
for (uint32_t i = 0; i < childCount; i++) {
|
2017-01-06 06:51:56 -08:00
|
|
|
const YGNodeRef child = YGNodeGetChild(node, i);
|
2017-12-19 11:18:00 -08:00
|
|
|
if (child->getStyle().positionType == YGPositionTypeRelative &&
|
|
|
|
child->getStyle().alignSelf == YGAlignBaseline) {
|
2017-01-06 06:51:56 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static inline float YGNodeDimWithMargin(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGFlexDirection axis,
|
|
|
|
const float widthSize) {
|
2017-12-19 11:18:00 -08:00
|
|
|
return node->getLayout().measuredDimensions[dim[axis]] +
|
2018-04-04 07:55:51 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
node->getLeadingMargin(axis, widthSize) +
|
|
|
|
node->getTrailingMargin(axis, widthSize));
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static inline bool YGNodeIsStyleDimDefined(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGFlexDirection axis,
|
|
|
|
const float ownerSize) {
|
2018-03-01 04:00:35 -08:00
|
|
|
bool isUndefined =
|
|
|
|
YGFloatIsUndefined(node->getResolvedDimension(dim[axis]).value);
|
2017-12-19 11:18:00 -08:00
|
|
|
return !(
|
|
|
|
node->getResolvedDimension(dim[axis]).unit == YGUnitAuto ||
|
|
|
|
node->getResolvedDimension(dim[axis]).unit == YGUnitUndefined ||
|
|
|
|
(node->getResolvedDimension(dim[axis]).unit == YGUnitPoint &&
|
2018-03-01 04:00:35 -08:00
|
|
|
!isUndefined && node->getResolvedDimension(dim[axis]).value < 0.0f) ||
|
2017-12-19 11:18:00 -08:00
|
|
|
(node->getResolvedDimension(dim[axis]).unit == YGUnitPercent &&
|
2018-03-01 04:00:35 -08:00
|
|
|
!isUndefined &&
|
2017-12-19 11:18:00 -08:00
|
|
|
(node->getResolvedDimension(dim[axis]).value < 0.0f ||
|
2018-04-01 18:27:06 -07:00
|
|
|
YGFloatIsUndefined(ownerSize))));
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static inline bool YGNodeIsLayoutDimDefined(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGFlexDirection axis) {
|
2017-12-19 11:18:00 -08:00
|
|
|
const float value = node->getLayout().measuredDimensions[dim[axis]];
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
return !YGFloatIsUndefined(value) && value >= 0.0f;
|
2015-10-15 01:30:33 +03:00
|
|
|
}
|
|
|
|
|
2018-04-04 07:55:28 -07:00
|
|
|
static YGFloatOptional YGNodeBoundAxisWithinMinAndMax(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGFlexDirection& axis,
|
|
|
|
const float& value,
|
|
|
|
const float& axisSize) {
|
|
|
|
YGFloatOptional min;
|
|
|
|
YGFloatOptional max;
|
2017-02-11 05:26:55 -08:00
|
|
|
|
|
|
|
if (YGFlexDirectionIsColumn(axis)) {
|
2018-04-04 07:55:28 -07:00
|
|
|
min = YGResolveValue(
|
|
|
|
node->getStyle().minDimensions[YGDimensionHeight], axisSize);
|
|
|
|
max = YGResolveValue(
|
|
|
|
node->getStyle().maxDimensions[YGDimensionHeight], axisSize);
|
2017-02-11 05:26:55 -08:00
|
|
|
} else if (YGFlexDirectionIsRow(axis)) {
|
2018-04-04 07:55:28 -07:00
|
|
|
min = YGResolveValue(
|
|
|
|
node->getStyle().minDimensions[YGDimensionWidth], axisSize);
|
|
|
|
max = YGResolveValue(
|
|
|
|
node->getStyle().maxDimensions[YGDimensionWidth], axisSize);
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2018-04-04 07:55:28 -07:00
|
|
|
if (!max.isUndefined() && max.getValue() >= 0 && value > max.getValue()) {
|
|
|
|
return max;
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
2016-08-22 06:58:13 -07:00
|
|
|
|
2018-04-04 07:55:28 -07:00
|
|
|
if (!min.isUndefined() && min.getValue() >= 0 && value < min.getValue()) {
|
|
|
|
return min;
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2018-04-04 07:55:28 -07:00
|
|
|
return YGFloatOptional(value);
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
// Like YGNodeBoundAxisWithinMinAndMax but also ensures that the value doesn't
|
|
|
|
// go below the padding and border amount.
|
|
|
|
static inline float YGNodeBoundAxis(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGFlexDirection axis,
|
|
|
|
const float value,
|
|
|
|
const float axisSize,
|
|
|
|
const float widthSize) {
|
2018-03-01 04:00:35 -08:00
|
|
|
return YGFloatMax(
|
2018-04-04 07:55:28 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
YGNodeBoundAxisWithinMinAndMax(node, axis, value, axisSize)),
|
2018-03-01 04:00:35 -08:00
|
|
|
YGNodePaddingAndBorderForAxis(node, axis, widthSize));
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static void YGNodeSetChildTrailingPosition(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGNodeRef child,
|
|
|
|
const YGFlexDirection axis) {
|
2017-12-19 11:18:00 -08:00
|
|
|
const float size = child->getLayout().measuredDimensions[dim[axis]];
|
|
|
|
child->setLayoutPosition(
|
|
|
|
node->getLayout().measuredDimensions[dim[axis]] - size -
|
|
|
|
child->getLayout().position[pos[axis]],
|
|
|
|
trailing[axis]);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2015-08-13 16:56:41 +08:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static void YGConstrainMaxSizeForMode(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const enum YGFlexDirection axis,
|
|
|
|
const float ownerAxisSize,
|
|
|
|
const float ownerWidth,
|
|
|
|
YGMeasureMode* mode,
|
|
|
|
float* size) {
|
2018-04-04 07:55:25 -07:00
|
|
|
const YGFloatOptional maxSize =
|
2018-07-19 09:57:04 -07:00
|
|
|
YGResolveValue(node->getStyle().maxDimensions[dim[axis]], ownerAxisSize) +
|
2018-04-04 07:55:25 -07:00
|
|
|
YGFloatOptional(node->getMarginForAxis(axis, ownerWidth));
|
2016-11-11 08:05:44 -08:00
|
|
|
switch (*mode) {
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGMeasureModeExactly:
|
|
|
|
case YGMeasureModeAtMost:
|
2018-04-04 07:55:25 -07:00
|
|
|
*size = (maxSize.isUndefined() || *size < maxSize.getValue())
|
|
|
|
? *size
|
|
|
|
: maxSize.getValue();
|
2016-11-11 08:05:44 -08:00
|
|
|
break;
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGMeasureModeUndefined:
|
2018-04-04 07:55:25 -07:00
|
|
|
if (!maxSize.isUndefined()) {
|
2016-12-02 05:47:43 -08:00
|
|
|
*mode = YGMeasureModeAtMost;
|
2018-04-04 07:55:25 -07:00
|
|
|
*size = maxSize.getValue();
|
2016-11-11 08:05:44 -08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static void YGNodeComputeFlexBasisForChild(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGNodeRef child,
|
|
|
|
const float width,
|
|
|
|
const YGMeasureMode widthMode,
|
|
|
|
const float height,
|
|
|
|
const float ownerWidth,
|
|
|
|
const float ownerHeight,
|
|
|
|
const YGMeasureMode heightMode,
|
|
|
|
const YGDirection direction,
|
|
|
|
const YGConfigRef config) {
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGFlexDirection mainAxis =
|
|
|
|
YGResolveFlexDirection(node->getStyle().flexDirection, direction);
|
2016-12-03 04:40:18 -08:00
|
|
|
const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
const float mainAxisSize = isMainAxisRow ? width : height;
|
2018-04-01 18:27:06 -07:00
|
|
|
const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
|
2016-10-17 05:28:50 -07:00
|
|
|
|
|
|
|
float childWidth;
|
|
|
|
float childHeight;
|
2016-12-02 05:47:43 -08:00
|
|
|
YGMeasureMode childWidthMeasureMode;
|
|
|
|
YGMeasureMode childHeightMeasureMode;
|
2016-10-17 05:28:50 -07:00
|
|
|
|
2018-04-04 07:55:39 -07:00
|
|
|
const YGFloatOptional resolvedFlexBasis =
|
|
|
|
YGResolveValue(child->resolveFlexBasisPtr(), mainAxisownerSize);
|
2018-07-19 09:57:04 -07:00
|
|
|
const bool isRowStyleDimDefined =
|
|
|
|
YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, ownerWidth);
|
2017-02-03 05:37:44 -08:00
|
|
|
const bool isColumnStyleDimDefined =
|
2018-04-01 18:27:06 -07:00
|
|
|
YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, ownerHeight);
|
2016-10-24 12:26:57 -07:00
|
|
|
|
2018-04-04 07:55:39 -07:00
|
|
|
if (!resolvedFlexBasis.isUndefined() && !YGFloatIsUndefined(mainAxisSize)) {
|
|
|
|
if (child->getLayout().computedFlexBasis.isUndefined() ||
|
2017-12-19 11:18:00 -08:00
|
|
|
(YGConfigIsExperimentalFeatureEnabled(
|
|
|
|
child->getConfig(), YGExperimentalFeatureWebFlexBasis) &&
|
|
|
|
child->getLayout().computedFlexBasisGeneration !=
|
|
|
|
gCurrentGenerationCount)) {
|
2018-04-04 07:55:39 -07:00
|
|
|
const YGFloatOptional& paddingAndBorder = YGFloatOptional(
|
|
|
|
YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth));
|
|
|
|
child->setLayoutComputedFlexBasis(
|
|
|
|
YGFloatOptionalMax(resolvedFlexBasis, paddingAndBorder));
|
2016-10-19 06:39:34 -07:00
|
|
|
}
|
2016-10-24 12:26:57 -07:00
|
|
|
} else if (isMainAxisRow && isRowStyleDimDefined) {
|
2016-10-17 05:28:50 -07:00
|
|
|
// The width is definite, so use that as the flex basis.
|
2018-04-04 07:55:39 -07:00
|
|
|
const YGFloatOptional& paddingAndBorder = YGFloatOptional(
|
|
|
|
YGNodePaddingAndBorderForAxis(child, YGFlexDirectionRow, ownerWidth));
|
|
|
|
|
|
|
|
child->setLayoutComputedFlexBasis(YGFloatOptionalMax(
|
|
|
|
YGResolveValue(
|
|
|
|
child->getResolvedDimension(YGDimensionWidth), ownerWidth),
|
|
|
|
paddingAndBorder));
|
2016-10-24 12:26:57 -07:00
|
|
|
} else if (!isMainAxisRow && isColumnStyleDimDefined) {
|
2016-10-17 05:28:50 -07:00
|
|
|
// The height is definite, so use that as the flex basis.
|
2018-04-04 07:55:39 -07:00
|
|
|
const YGFloatOptional& paddingAndBorder =
|
|
|
|
YGFloatOptional(YGNodePaddingAndBorderForAxis(
|
|
|
|
child, YGFlexDirectionColumn, ownerWidth));
|
|
|
|
child->setLayoutComputedFlexBasis(YGFloatOptionalMax(
|
|
|
|
YGResolveValue(
|
|
|
|
child->getResolvedDimension(YGDimensionHeight), ownerHeight),
|
|
|
|
paddingAndBorder));
|
2016-10-17 05:28:50 -07:00
|
|
|
} else {
|
|
|
|
// Compute the flex basis and hypothetical main size (i.e. the clamped
|
|
|
|
// flex basis).
|
2016-12-02 05:47:43 -08:00
|
|
|
childWidth = YGUndefined;
|
|
|
|
childHeight = YGUndefined;
|
|
|
|
childWidthMeasureMode = YGMeasureModeUndefined;
|
|
|
|
childHeightMeasureMode = YGMeasureModeUndefined;
|
2016-10-17 05:28:50 -07:00
|
|
|
|
2018-07-13 12:34:51 -07:00
|
|
|
auto marginRow = YGUnwrapFloatOptional(
|
2018-04-04 07:55:54 -07:00
|
|
|
child->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
|
2018-07-13 12:34:51 -07:00
|
|
|
auto marginColumn = YGUnwrapFloatOptional(
|
2018-04-04 07:55:54 -07:00
|
|
|
child->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
|
2017-01-27 09:56:35 -08:00
|
|
|
|
2016-10-24 12:26:57 -07:00
|
|
|
if (isRowStyleDimDefined) {
|
2017-01-27 09:56:35 -08:00
|
|
|
childWidth =
|
2018-03-14 04:17:07 -07:00
|
|
|
YGUnwrapFloatOptional(YGResolveValue(
|
2018-04-01 18:27:06 -07:00
|
|
|
child->getResolvedDimension(YGDimensionWidth), ownerWidth)) +
|
2017-12-19 11:18:00 -08:00
|
|
|
marginRow;
|
2016-12-02 05:47:43 -08:00
|
|
|
childWidthMeasureMode = YGMeasureModeExactly;
|
2016-10-17 05:28:50 -07:00
|
|
|
}
|
2016-10-24 12:26:57 -07:00
|
|
|
if (isColumnStyleDimDefined) {
|
2017-02-11 08:32:50 -08:00
|
|
|
childHeight =
|
2018-03-14 04:17:07 -07:00
|
|
|
YGUnwrapFloatOptional(YGResolveValue(
|
2018-04-01 18:27:06 -07:00
|
|
|
child->getResolvedDimension(YGDimensionHeight), ownerHeight)) +
|
2017-12-19 11:18:00 -08:00
|
|
|
marginColumn;
|
2016-12-02 05:47:43 -08:00
|
|
|
childHeightMeasureMode = YGMeasureModeExactly;
|
2016-10-17 05:28:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// The W3C spec doesn't say anything about the 'overflow' property,
|
|
|
|
// but all major browsers appear to implement the following logic.
|
2017-12-19 11:18:00 -08:00
|
|
|
if ((!isMainAxisRow && node->getStyle().overflow == YGOverflowScroll) ||
|
|
|
|
node->getStyle().overflow != YGOverflowScroll) {
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
if (YGFloatIsUndefined(childWidth) && !YGFloatIsUndefined(width)) {
|
2016-10-17 05:28:50 -07:00
|
|
|
childWidth = width;
|
2016-12-02 05:47:43 -08:00
|
|
|
childWidthMeasureMode = YGMeasureModeAtMost;
|
2016-10-17 05:28:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
if ((isMainAxisRow && node->getStyle().overflow == YGOverflowScroll) ||
|
|
|
|
node->getStyle().overflow != YGOverflowScroll) {
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
if (YGFloatIsUndefined(childHeight) && !YGFloatIsUndefined(height)) {
|
2016-10-17 05:28:50 -07:00
|
|
|
childHeight = height;
|
2016-12-02 05:47:43 -08:00
|
|
|
childHeightMeasureMode = YGMeasureModeAtMost;
|
2016-10-17 05:28:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-03 14:56:29 -07:00
|
|
|
if (!child->getStyle().aspectRatio.isUndefined()) {
|
2017-08-21 03:09:09 -07:00
|
|
|
if (!isMainAxisRow && childWidthMeasureMode == YGMeasureModeExactly) {
|
2018-02-15 07:16:59 -08:00
|
|
|
childHeight = marginColumn +
|
2018-04-03 14:56:29 -07:00
|
|
|
(childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
|
2017-08-21 03:09:09 -07:00
|
|
|
childHeightMeasureMode = YGMeasureModeExactly;
|
2018-07-19 09:57:04 -07:00
|
|
|
} else if (
|
|
|
|
isMainAxisRow && childHeightMeasureMode == YGMeasureModeExactly) {
|
2018-02-15 07:16:59 -08:00
|
|
|
childWidth = marginRow +
|
2018-04-03 14:56:29 -07:00
|
|
|
(childHeight - marginColumn) *
|
|
|
|
child->getStyle().aspectRatio.getValue();
|
2017-08-21 03:09:09 -07:00
|
|
|
childWidthMeasureMode = YGMeasureModeExactly;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-17 05:28:50 -07:00
|
|
|
// If child has no defined size in the cross axis and is set to stretch,
|
|
|
|
// set the cross
|
|
|
|
// axis to be measured exactly with the available inner width
|
2017-08-21 03:09:09 -07:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
const bool hasExactWidth =
|
|
|
|
!YGFloatIsUndefined(width) && widthMode == YGMeasureModeExactly;
|
|
|
|
const bool childWidthStretch =
|
|
|
|
YGNodeAlignItem(node, child) == YGAlignStretch &&
|
|
|
|
childWidthMeasureMode != YGMeasureModeExactly;
|
|
|
|
if (!isMainAxisRow && !isRowStyleDimDefined && hasExactWidth &&
|
|
|
|
childWidthStretch) {
|
2016-10-17 05:28:50 -07:00
|
|
|
childWidth = width;
|
2016-12-02 05:47:43 -08:00
|
|
|
childWidthMeasureMode = YGMeasureModeExactly;
|
2018-04-03 14:56:29 -07:00
|
|
|
if (!child->getStyle().aspectRatio.isUndefined()) {
|
|
|
|
childHeight =
|
|
|
|
(childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
|
2017-08-21 03:09:09 -07:00
|
|
|
childHeightMeasureMode = YGMeasureModeExactly;
|
|
|
|
}
|
2016-10-17 05:28:50 -07:00
|
|
|
}
|
2017-08-21 03:09:09 -07:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
const bool hasExactHeight =
|
|
|
|
!YGFloatIsUndefined(height) && heightMode == YGMeasureModeExactly;
|
|
|
|
const bool childHeightStretch =
|
|
|
|
YGNodeAlignItem(node, child) == YGAlignStretch &&
|
|
|
|
childHeightMeasureMode != YGMeasureModeExactly;
|
|
|
|
if (isMainAxisRow && !isColumnStyleDimDefined && hasExactHeight &&
|
|
|
|
childHeightStretch) {
|
2016-10-17 05:28:50 -07:00
|
|
|
childHeight = height;
|
2016-12-02 05:47:43 -08:00
|
|
|
childHeightMeasureMode = YGMeasureModeExactly;
|
2016-10-17 05:28:50 -07:00
|
|
|
|
2018-04-03 14:56:29 -07:00
|
|
|
if (!child->getStyle().aspectRatio.isUndefined()) {
|
|
|
|
childWidth = (childHeight - marginColumn) *
|
|
|
|
child->getStyle().aspectRatio.getValue();
|
2017-08-21 03:09:09 -07:00
|
|
|
childWidthMeasureMode = YGMeasureModeExactly;
|
2016-11-21 10:12:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-09 03:48:33 -08:00
|
|
|
YGConstrainMaxSizeForMode(
|
2018-07-19 09:57:04 -07:00
|
|
|
child,
|
|
|
|
YGFlexDirectionRow,
|
|
|
|
ownerWidth,
|
|
|
|
ownerWidth,
|
|
|
|
&childWidthMeasureMode,
|
|
|
|
&childWidth);
|
|
|
|
YGConstrainMaxSizeForMode(
|
|
|
|
child,
|
|
|
|
YGFlexDirectionColumn,
|
|
|
|
ownerHeight,
|
|
|
|
ownerWidth,
|
|
|
|
&childHeightMeasureMode,
|
|
|
|
&childHeight);
|
2016-11-08 09:45:58 -08:00
|
|
|
|
2016-10-17 05:28:50 -07:00
|
|
|
// Measure the child
|
2018-07-19 09:57:04 -07:00
|
|
|
YGLayoutNodeInternal(
|
|
|
|
child,
|
|
|
|
childWidth,
|
|
|
|
childHeight,
|
|
|
|
direction,
|
|
|
|
childWidthMeasureMode,
|
|
|
|
childHeightMeasureMode,
|
|
|
|
ownerWidth,
|
|
|
|
ownerHeight,
|
|
|
|
false,
|
|
|
|
"measure",
|
|
|
|
config);
|
2016-10-17 05:28:50 -07:00
|
|
|
|
2018-04-04 07:55:39 -07:00
|
|
|
child->setLayoutComputedFlexBasis(YGFloatOptional(YGFloatMax(
|
2017-12-19 11:18:00 -08:00
|
|
|
child->getLayout().measuredDimensions[dim[mainAxis]],
|
2018-04-04 07:55:39 -07:00
|
|
|
YGNodePaddingAndBorderForAxis(child, mainAxis, ownerWidth))));
|
2016-10-17 05:28:50 -07:00
|
|
|
}
|
2017-12-19 11:18:00 -08:00
|
|
|
child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount);
|
2016-10-17 05:28:50 -07:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static void YGNodeAbsoluteLayoutChild(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGNodeRef child,
|
|
|
|
const float width,
|
|
|
|
const YGMeasureMode widthMode,
|
|
|
|
const float height,
|
|
|
|
const YGDirection direction,
|
|
|
|
const YGConfigRef config) {
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGFlexDirection mainAxis =
|
|
|
|
YGResolveFlexDirection(node->getStyle().flexDirection, direction);
|
2016-12-03 04:40:18 -08:00
|
|
|
const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
|
|
|
|
const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
|
2016-10-17 12:12:34 -07:00
|
|
|
|
2016-12-02 05:47:43 -08:00
|
|
|
float childWidth = YGUndefined;
|
|
|
|
float childHeight = YGUndefined;
|
|
|
|
YGMeasureMode childWidthMeasureMode = YGMeasureModeUndefined;
|
|
|
|
YGMeasureMode childHeightMeasureMode = YGMeasureModeUndefined;
|
2016-10-17 12:12:34 -07:00
|
|
|
|
2018-07-13 12:34:51 -07:00
|
|
|
auto marginRow =
|
2018-04-04 07:55:54 -07:00
|
|
|
YGUnwrapFloatOptional(child->getMarginForAxis(YGFlexDirectionRow, width));
|
2018-07-13 12:34:51 -07:00
|
|
|
auto marginColumn = YGUnwrapFloatOptional(
|
2018-04-04 07:55:54 -07:00
|
|
|
child->getMarginForAxis(YGFlexDirectionColumn, width));
|
2017-01-27 09:56:35 -08:00
|
|
|
|
2017-02-03 05:37:44 -08:00
|
|
|
if (YGNodeIsStyleDimDefined(child, YGFlexDirectionRow, width)) {
|
2018-07-19 09:57:04 -07:00
|
|
|
childWidth = YGUnwrapFloatOptional(YGResolveValue(
|
|
|
|
child->getResolvedDimension(YGDimensionWidth), width)) +
|
2017-12-19 11:18:00 -08:00
|
|
|
marginRow;
|
2016-10-17 12:12:34 -07:00
|
|
|
} else {
|
|
|
|
// If the child doesn't have a specified width, compute the width based
|
|
|
|
// on the left/right
|
|
|
|
// offsets if they're defined.
|
2018-01-11 04:47:38 -08:00
|
|
|
if (child->isLeadingPositionDefined(YGFlexDirectionRow) &&
|
2018-01-11 04:47:40 -08:00
|
|
|
child->isTrailingPosDefined(YGFlexDirectionRow)) {
|
2017-12-19 11:18:00 -08:00
|
|
|
childWidth = node->getLayout().measuredDimensions[YGDimensionWidth] -
|
2018-01-15 10:09:44 -08:00
|
|
|
(node->getLeadingBorder(YGFlexDirectionRow) +
|
2018-01-15 10:09:46 -08:00
|
|
|
node->getTrailingBorder(YGFlexDirectionRow)) -
|
2018-04-04 07:55:44 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
child->getLeadingPosition(YGFlexDirectionRow, width) +
|
|
|
|
child->getTrailingPosition(YGFlexDirectionRow, width));
|
2018-07-19 09:57:04 -07:00
|
|
|
childWidth =
|
|
|
|
YGNodeBoundAxis(child, YGFlexDirectionRow, childWidth, width, width);
|
2016-10-17 12:12:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-03 05:37:44 -08:00
|
|
|
if (YGNodeIsStyleDimDefined(child, YGFlexDirectionColumn, height)) {
|
2018-07-19 09:57:04 -07:00
|
|
|
childHeight = YGUnwrapFloatOptional(YGResolveValue(
|
|
|
|
child->getResolvedDimension(YGDimensionHeight), height)) +
|
2017-12-19 11:18:00 -08:00
|
|
|
marginColumn;
|
2016-10-17 12:12:34 -07:00
|
|
|
} else {
|
|
|
|
// If the child doesn't have a specified height, compute the height
|
|
|
|
// based on the top/bottom
|
|
|
|
// offsets if they're defined.
|
2018-01-11 04:47:38 -08:00
|
|
|
if (child->isLeadingPositionDefined(YGFlexDirectionColumn) &&
|
2018-01-11 04:47:40 -08:00
|
|
|
child->isTrailingPosDefined(YGFlexDirectionColumn)) {
|
2018-04-04 07:55:44 -07:00
|
|
|
childHeight =
|
|
|
|
node->getLayout().measuredDimensions[YGDimensionHeight] -
|
2018-01-15 10:09:44 -08:00
|
|
|
(node->getLeadingBorder(YGFlexDirectionColumn) +
|
2018-01-15 10:09:46 -08:00
|
|
|
node->getTrailingBorder(YGFlexDirectionColumn)) -
|
2018-04-04 07:55:44 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
child->getLeadingPosition(YGFlexDirectionColumn, height) +
|
|
|
|
child->getTrailingPosition(YGFlexDirectionColumn, height));
|
2018-07-19 09:57:04 -07:00
|
|
|
childHeight = YGNodeBoundAxis(
|
|
|
|
child, YGFlexDirectionColumn, childHeight, height, width);
|
2016-10-17 12:12:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
// Exactly one dimension needs to be defined for us to be able to do aspect
|
|
|
|
// ratio calculation. One dimension being the anchor and the other being
|
|
|
|
// flexible.
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
if (YGFloatIsUndefined(childWidth) ^ YGFloatIsUndefined(childHeight)) {
|
2018-04-03 14:56:29 -07:00
|
|
|
if (!child->getStyle().aspectRatio.isUndefined()) {
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
if (YGFloatIsUndefined(childWidth)) {
|
2017-12-19 11:18:00 -08:00
|
|
|
childWidth = marginRow +
|
2018-04-03 14:56:29 -07:00
|
|
|
(childHeight - marginColumn) *
|
|
|
|
child->getStyle().aspectRatio.getValue();
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
} else if (YGFloatIsUndefined(childHeight)) {
|
2017-12-19 11:18:00 -08:00
|
|
|
childHeight = marginColumn +
|
2018-04-03 14:56:29 -07:00
|
|
|
(childWidth - marginRow) / child->getStyle().aspectRatio.getValue();
|
2016-11-21 10:12:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-17 12:12:34 -07:00
|
|
|
// If we're still missing one or the other dimension, measure the content.
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
if (YGFloatIsUndefined(childWidth) || YGFloatIsUndefined(childHeight)) {
|
2018-07-19 09:57:04 -07:00
|
|
|
childWidthMeasureMode = YGFloatIsUndefined(childWidth)
|
|
|
|
? YGMeasureModeUndefined
|
|
|
|
: YGMeasureModeExactly;
|
|
|
|
childHeightMeasureMode = YGFloatIsUndefined(childHeight)
|
|
|
|
? YGMeasureModeUndefined
|
|
|
|
: YGMeasureModeExactly;
|
|
|
|
|
|
|
|
// If the size of the owner is defined then try to constrain the absolute
|
|
|
|
// child to that size as well. This allows text within the absolute child to
|
|
|
|
// wrap to the size of its owner. This is the same behavior as many browsers
|
|
|
|
// implement.
|
2018-03-01 04:00:35 -08:00
|
|
|
if (!isMainAxisRow && YGFloatIsUndefined(childWidth) &&
|
|
|
|
widthMode != YGMeasureModeUndefined && !YGFloatIsUndefined(width) &&
|
2017-01-26 13:36:39 -08:00
|
|
|
width > 0) {
|
2016-10-17 12:12:34 -07:00
|
|
|
childWidth = width;
|
2016-12-02 05:47:43 -08:00
|
|
|
childWidthMeasureMode = YGMeasureModeAtMost;
|
2016-10-17 12:12:34 -07:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
YGLayoutNodeInternal(
|
|
|
|
child,
|
|
|
|
childWidth,
|
|
|
|
childHeight,
|
|
|
|
direction,
|
|
|
|
childWidthMeasureMode,
|
|
|
|
childHeightMeasureMode,
|
|
|
|
childWidth,
|
|
|
|
childHeight,
|
|
|
|
false,
|
|
|
|
"abs-measure",
|
|
|
|
config);
|
2017-12-19 11:18:00 -08:00
|
|
|
childWidth = child->getLayout().measuredDimensions[YGDimensionWidth] +
|
2018-04-04 07:55:54 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
child->getMarginForAxis(YGFlexDirectionRow, width));
|
2017-12-19 11:18:00 -08:00
|
|
|
childHeight = child->getLayout().measuredDimensions[YGDimensionHeight] +
|
2018-04-04 07:55:54 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
child->getMarginForAxis(YGFlexDirectionColumn, width));
|
2016-10-17 12:12:34 -07:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
YGLayoutNodeInternal(
|
|
|
|
child,
|
|
|
|
childWidth,
|
|
|
|
childHeight,
|
|
|
|
direction,
|
|
|
|
YGMeasureModeExactly,
|
|
|
|
YGMeasureModeExactly,
|
|
|
|
childWidth,
|
|
|
|
childHeight,
|
|
|
|
true,
|
|
|
|
"abs-layout",
|
|
|
|
config);
|
2016-10-17 12:12:34 -07:00
|
|
|
|
2018-01-11 04:47:40 -08:00
|
|
|
if (child->isTrailingPosDefined(mainAxis) &&
|
2018-01-11 04:47:38 -08:00
|
|
|
!child->isLeadingPositionDefined(mainAxis)) {
|
2017-12-19 11:18:00 -08:00
|
|
|
child->setLayoutPosition(
|
|
|
|
node->getLayout().measuredDimensions[dim[mainAxis]] -
|
|
|
|
child->getLayout().measuredDimensions[dim[mainAxis]] -
|
2018-01-15 10:09:46 -08:00
|
|
|
node->getTrailingBorder(mainAxis) -
|
2018-04-04 07:55:51 -07:00
|
|
|
YGUnwrapFloatOptional(child->getTrailingMargin(mainAxis, width)) -
|
2018-04-04 07:55:44 -07:00
|
|
|
YGUnwrapFloatOptional(child->getTrailingPosition(
|
|
|
|
mainAxis, isMainAxisRow ? width : height)),
|
2017-12-19 11:18:00 -08:00
|
|
|
leading[mainAxis]);
|
|
|
|
} else if (
|
2018-01-11 04:47:38 -08:00
|
|
|
!child->isLeadingPositionDefined(mainAxis) &&
|
2017-12-19 11:18:00 -08:00
|
|
|
node->getStyle().justifyContent == YGJustifyCenter) {
|
|
|
|
child->setLayoutPosition(
|
|
|
|
(node->getLayout().measuredDimensions[dim[mainAxis]] -
|
|
|
|
child->getLayout().measuredDimensions[dim[mainAxis]]) /
|
|
|
|
2.0f,
|
|
|
|
leading[mainAxis]);
|
|
|
|
} else if (
|
2018-01-11 04:47:38 -08:00
|
|
|
!child->isLeadingPositionDefined(mainAxis) &&
|
2017-12-19 11:18:00 -08:00
|
|
|
node->getStyle().justifyContent == YGJustifyFlexEnd) {
|
|
|
|
child->setLayoutPosition(
|
|
|
|
(node->getLayout().measuredDimensions[dim[mainAxis]] -
|
|
|
|
child->getLayout().measuredDimensions[dim[mainAxis]]),
|
|
|
|
leading[mainAxis]);
|
2016-10-17 12:12:34 -07:00
|
|
|
}
|
|
|
|
|
2018-01-11 04:47:40 -08:00
|
|
|
if (child->isTrailingPosDefined(crossAxis) &&
|
2018-01-11 04:47:38 -08:00
|
|
|
!child->isLeadingPositionDefined(crossAxis)) {
|
2017-12-19 11:18:00 -08:00
|
|
|
child->setLayoutPosition(
|
|
|
|
node->getLayout().measuredDimensions[dim[crossAxis]] -
|
|
|
|
child->getLayout().measuredDimensions[dim[crossAxis]] -
|
2018-01-15 10:09:46 -08:00
|
|
|
node->getTrailingBorder(crossAxis) -
|
2018-04-04 07:55:51 -07:00
|
|
|
YGUnwrapFloatOptional(child->getTrailingMargin(crossAxis, width)) -
|
2018-04-04 07:55:44 -07:00
|
|
|
YGUnwrapFloatOptional(child->getTrailingPosition(
|
|
|
|
crossAxis, isMainAxisRow ? height : width)),
|
2017-12-19 11:18:00 -08:00
|
|
|
leading[crossAxis]);
|
|
|
|
|
2018-01-11 04:47:38 -08:00
|
|
|
} else if (
|
|
|
|
!child->isLeadingPositionDefined(crossAxis) &&
|
|
|
|
YGNodeAlignItem(node, child) == YGAlignCenter) {
|
2017-12-19 11:18:00 -08:00
|
|
|
child->setLayoutPosition(
|
|
|
|
(node->getLayout().measuredDimensions[dim[crossAxis]] -
|
|
|
|
child->getLayout().measuredDimensions[dim[crossAxis]]) /
|
|
|
|
2.0f,
|
|
|
|
leading[crossAxis]);
|
|
|
|
} else if (
|
2018-01-11 04:47:38 -08:00
|
|
|
!child->isLeadingPositionDefined(crossAxis) &&
|
2017-12-19 11:18:00 -08:00
|
|
|
((YGNodeAlignItem(node, child) == YGAlignFlexEnd) ^
|
|
|
|
(node->getStyle().flexWrap == YGWrapWrapReverse))) {
|
|
|
|
child->setLayoutPosition(
|
|
|
|
(node->getLayout().measuredDimensions[dim[crossAxis]] -
|
|
|
|
child->getLayout().measuredDimensions[dim[crossAxis]]),
|
|
|
|
leading[crossAxis]);
|
2016-10-17 12:12:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static void YGNodeWithMeasureFuncSetMeasuredDimensions(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const float availableWidth,
|
|
|
|
const float availableHeight,
|
|
|
|
const YGMeasureMode widthMeasureMode,
|
|
|
|
const YGMeasureMode heightMeasureMode,
|
|
|
|
const float ownerWidth,
|
|
|
|
const float ownerHeight) {
|
2017-11-21 10:10:30 -08:00
|
|
|
YGAssertWithNode(
|
|
|
|
node,
|
2017-12-19 11:18:00 -08:00
|
|
|
node->getMeasure() != nullptr,
|
2017-11-21 10:10:30 -08:00
|
|
|
"Expected node to have custom measure function");
|
2016-11-21 11:03:53 -08:00
|
|
|
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
const float paddingAndBorderAxisRow =
|
|
|
|
YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth);
|
2018-07-19 09:57:04 -07:00
|
|
|
const float paddingAndBorderAxisColumn = YGNodePaddingAndBorderForAxis(
|
|
|
|
node, YGFlexDirectionColumn, availableWidth);
|
2018-04-04 07:55:54 -07:00
|
|
|
const float marginAxisRow = YGUnwrapFloatOptional(
|
|
|
|
node->getMarginForAxis(YGFlexDirectionRow, availableWidth));
|
|
|
|
const float marginAxisColumn = YGUnwrapFloatOptional(
|
|
|
|
node->getMarginForAxis(YGFlexDirectionColumn, availableWidth));
|
2016-11-21 11:03:53 -08:00
|
|
|
|
2017-05-23 11:11:37 -07:00
|
|
|
// We want to make sure we don't call measure with negative size
|
|
|
|
const float innerWidth = YGFloatIsUndefined(availableWidth)
|
2018-02-06 08:39:53 -08:00
|
|
|
? availableWidth
|
2018-03-01 04:00:35 -08:00
|
|
|
: YGFloatMax(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow);
|
2018-02-06 08:39:53 -08:00
|
|
|
const float innerHeight = YGFloatIsUndefined(availableHeight)
|
|
|
|
? availableHeight
|
2018-03-01 04:00:35 -08:00
|
|
|
: YGFloatMax(
|
2018-02-06 08:39:53 -08:00
|
|
|
0, availableHeight - marginAxisColumn - paddingAndBorderAxisColumn);
|
|
|
|
|
|
|
|
if (widthMeasureMode == YGMeasureModeExactly &&
|
|
|
|
heightMeasureMode == YGMeasureModeExactly) {
|
2016-11-21 11:03:53 -08:00
|
|
|
// Don't bother sizing the text if both dimensions are already defined.
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutMeasuredDimension(
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
YGFlexDirectionRow,
|
|
|
|
availableWidth - marginAxisRow,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerWidth,
|
|
|
|
ownerWidth),
|
2017-12-19 11:18:00 -08:00
|
|
|
YGDimensionWidth);
|
|
|
|
node->setLayoutMeasuredDimension(
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
YGFlexDirectionColumn,
|
|
|
|
availableHeight - marginAxisColumn,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerHeight,
|
|
|
|
ownerWidth),
|
2017-12-19 11:18:00 -08:00
|
|
|
YGDimensionHeight);
|
2016-11-21 11:03:53 -08:00
|
|
|
} else {
|
|
|
|
// Measure the text under the current constraints.
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGSize measuredSize = node->getMeasure()(
|
|
|
|
node, innerWidth, widthMeasureMode, innerHeight, heightMeasureMode);
|
|
|
|
|
|
|
|
node->setLayoutMeasuredDimension(
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
YGFlexDirectionRow,
|
|
|
|
(widthMeasureMode == YGMeasureModeUndefined ||
|
|
|
|
widthMeasureMode == YGMeasureModeAtMost)
|
|
|
|
? measuredSize.width + paddingAndBorderAxisRow
|
|
|
|
: availableWidth - marginAxisRow,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerWidth,
|
|
|
|
ownerWidth),
|
2017-12-19 11:18:00 -08:00
|
|
|
YGDimensionWidth);
|
|
|
|
|
|
|
|
node->setLayoutMeasuredDimension(
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
YGFlexDirectionColumn,
|
|
|
|
(heightMeasureMode == YGMeasureModeUndefined ||
|
|
|
|
heightMeasureMode == YGMeasureModeAtMost)
|
|
|
|
? measuredSize.height + paddingAndBorderAxisColumn
|
|
|
|
: availableHeight - marginAxisColumn,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerHeight,
|
|
|
|
ownerWidth),
|
2017-12-19 11:18:00 -08:00
|
|
|
YGDimensionHeight);
|
2016-11-21 11:03:53 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-21 11:03:56 -08:00
|
|
|
// For nodes with no children, use the available values if they were provided,
|
|
|
|
// or the minimum size as indicated by the padding and border sizes.
|
2018-07-19 09:57:04 -07:00
|
|
|
static void YGNodeEmptyContainerSetMeasuredDimensions(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const float availableWidth,
|
|
|
|
const float availableHeight,
|
|
|
|
const YGMeasureMode widthMeasureMode,
|
|
|
|
const YGMeasureMode heightMeasureMode,
|
|
|
|
const float ownerWidth,
|
|
|
|
const float ownerHeight) {
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
const float paddingAndBorderAxisRow =
|
2018-04-01 18:27:06 -07:00
|
|
|
YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, ownerWidth);
|
2016-12-03 04:40:18 -08:00
|
|
|
const float paddingAndBorderAxisColumn =
|
2018-04-01 18:27:06 -07:00
|
|
|
YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, ownerWidth);
|
2018-04-04 07:55:54 -07:00
|
|
|
const float marginAxisRow = YGUnwrapFloatOptional(
|
|
|
|
node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
|
|
|
|
const float marginAxisColumn = YGUnwrapFloatOptional(
|
|
|
|
node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
|
2016-12-02 05:47:43 -08:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutMeasuredDimension(
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
YGFlexDirectionRow,
|
|
|
|
(widthMeasureMode == YGMeasureModeUndefined ||
|
|
|
|
widthMeasureMode == YGMeasureModeAtMost)
|
|
|
|
? paddingAndBorderAxisRow
|
|
|
|
: availableWidth - marginAxisRow,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerWidth,
|
|
|
|
ownerWidth),
|
2017-12-19 11:18:00 -08:00
|
|
|
YGDimensionWidth);
|
|
|
|
|
|
|
|
node->setLayoutMeasuredDimension(
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
YGFlexDirectionColumn,
|
|
|
|
(heightMeasureMode == YGMeasureModeUndefined ||
|
|
|
|
heightMeasureMode == YGMeasureModeAtMost)
|
|
|
|
? paddingAndBorderAxisColumn
|
|
|
|
: availableHeight - marginAxisColumn,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerHeight,
|
|
|
|
ownerWidth),
|
2017-12-19 11:18:00 -08:00
|
|
|
YGDimensionHeight);
|
2016-12-03 04:40:18 -08:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static bool YGNodeFixedSizeSetMeasuredDimensions(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const float availableWidth,
|
|
|
|
const float availableHeight,
|
|
|
|
const YGMeasureMode widthMeasureMode,
|
|
|
|
const YGMeasureMode heightMeasureMode,
|
|
|
|
const float ownerWidth,
|
|
|
|
const float ownerHeight) {
|
2018-03-01 04:00:35 -08:00
|
|
|
if ((!YGFloatIsUndefined(availableWidth) &&
|
|
|
|
widthMeasureMode == YGMeasureModeAtMost && availableWidth <= 0.0f) ||
|
|
|
|
(!YGFloatIsUndefined(availableHeight) &&
|
|
|
|
heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) ||
|
|
|
|
(widthMeasureMode == YGMeasureModeExactly &&
|
|
|
|
heightMeasureMode == YGMeasureModeExactly)) {
|
2018-07-13 12:34:51 -07:00
|
|
|
auto marginAxisColumn = YGUnwrapFloatOptional(
|
2018-04-04 07:55:54 -07:00
|
|
|
node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
|
2018-07-13 12:34:51 -07:00
|
|
|
auto marginAxisRow = YGUnwrapFloatOptional(
|
2018-04-04 07:55:54 -07:00
|
|
|
node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
|
2016-12-02 05:47:43 -08:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutMeasuredDimension(
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
YGFlexDirectionRow,
|
|
|
|
YGFloatIsUndefined(availableWidth) ||
|
|
|
|
(widthMeasureMode == YGMeasureModeAtMost &&
|
|
|
|
availableWidth < 0.0f)
|
|
|
|
? 0.0f
|
|
|
|
: availableWidth - marginAxisRow,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerWidth,
|
|
|
|
ownerWidth),
|
2017-12-19 11:18:00 -08:00
|
|
|
YGDimensionWidth);
|
|
|
|
|
|
|
|
node->setLayoutMeasuredDimension(
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
YGFlexDirectionColumn,
|
|
|
|
YGFloatIsUndefined(availableHeight) ||
|
|
|
|
(heightMeasureMode == YGMeasureModeAtMost &&
|
|
|
|
availableHeight < 0.0f)
|
|
|
|
? 0.0f
|
|
|
|
: availableHeight - marginAxisColumn,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerHeight,
|
|
|
|
ownerWidth),
|
2017-12-19 11:18:00 -08:00
|
|
|
YGDimensionHeight);
|
2016-11-21 11:03:57 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-02-06 09:31:22 -08:00
|
|
|
static void YGZeroOutLayoutRecursivly(const YGNodeRef node) {
|
2017-12-22 06:43:32 -08:00
|
|
|
memset(&(node->getLayout()), 0, sizeof(YGLayout));
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setHasNewLayout(true);
|
2018-01-08 02:48:32 -08:00
|
|
|
node->cloneChildrenIfNeeded();
|
2017-02-15 13:35:24 -08:00
|
|
|
const uint32_t childCount = YGNodeGetChildCount(node);
|
|
|
|
for (uint32_t i = 0; i < childCount; i++) {
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGNodeRef child = node->getChild(i);
|
2017-02-06 09:31:22 -08:00
|
|
|
YGZeroOutLayoutRecursivly(child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-15 05:33:37 -08:00
|
|
|
static float YGNodeCalculateAvailableInnerDim(
|
|
|
|
const YGNodeRef node,
|
|
|
|
YGFlexDirection axis,
|
|
|
|
float availableDim,
|
2018-04-01 18:27:06 -07:00
|
|
|
float ownerDim) {
|
2018-01-15 05:33:37 -08:00
|
|
|
YGFlexDirection direction =
|
|
|
|
YGFlexDirectionIsRow(axis) ? YGFlexDirectionRow : YGFlexDirectionColumn;
|
|
|
|
YGDimension dimension =
|
|
|
|
YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight;
|
|
|
|
|
2018-04-04 07:55:54 -07:00
|
|
|
const float margin =
|
|
|
|
YGUnwrapFloatOptional(node->getMarginForAxis(direction, ownerDim));
|
2018-01-15 05:33:37 -08:00
|
|
|
const float paddingAndBorder =
|
2018-04-01 18:27:06 -07:00
|
|
|
YGNodePaddingAndBorderForAxis(node, direction, ownerDim);
|
2018-01-15 05:33:37 -08:00
|
|
|
|
|
|
|
float availableInnerDim = availableDim - margin - paddingAndBorder;
|
|
|
|
// Max dimension overrides predefined dimension value; Min dimension in turn
|
|
|
|
// overrides both of the above
|
|
|
|
if (!YGFloatIsUndefined(availableInnerDim)) {
|
|
|
|
// We want to make sure our available height does not violate min and max
|
|
|
|
// constraints
|
2018-07-19 09:57:04 -07:00
|
|
|
const YGFloatOptional minDimensionOptional =
|
|
|
|
YGResolveValue(node->getStyle().minDimensions[dimension], ownerDim);
|
2018-03-15 12:29:02 -07:00
|
|
|
const float minInnerDim = minDimensionOptional.isUndefined()
|
2018-03-01 04:00:35 -08:00
|
|
|
? 0.0f
|
2018-03-15 12:29:02 -07:00
|
|
|
: minDimensionOptional.getValue() - paddingAndBorder;
|
2018-03-14 04:17:07 -07:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
const YGFloatOptional maxDimensionOptional =
|
|
|
|
YGResolveValue(node->getStyle().maxDimensions[dimension], ownerDim);
|
2018-03-14 04:17:07 -07:00
|
|
|
|
2018-03-15 12:29:02 -07:00
|
|
|
const float maxInnerDim = maxDimensionOptional.isUndefined()
|
|
|
|
? FLT_MAX
|
|
|
|
: maxDimensionOptional.getValue() - paddingAndBorder;
|
2018-01-15 05:33:37 -08:00
|
|
|
availableInnerDim =
|
2018-03-01 04:00:35 -08:00
|
|
|
YGFloatMax(YGFloatMin(availableInnerDim, maxInnerDim), minInnerDim);
|
2018-01-15 05:33:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return availableInnerDim;
|
|
|
|
}
|
|
|
|
|
2018-01-15 10:09:40 -08:00
|
|
|
static void YGNodeComputeFlexBasisForChildren(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const float availableInnerWidth,
|
|
|
|
const float availableInnerHeight,
|
|
|
|
YGMeasureMode widthMeasureMode,
|
|
|
|
YGMeasureMode heightMeasureMode,
|
|
|
|
YGDirection direction,
|
|
|
|
YGFlexDirection mainAxis,
|
|
|
|
const YGConfigRef config,
|
|
|
|
bool performLayout,
|
|
|
|
float& totalOuterFlexBasis) {
|
|
|
|
YGNodeRef singleFlexChild = nullptr;
|
|
|
|
YGVector children = node->getChildren();
|
|
|
|
YGMeasureMode measureModeMainDim =
|
|
|
|
YGFlexDirectionIsRow(mainAxis) ? widthMeasureMode : heightMeasureMode;
|
|
|
|
// If there is only one child with flexGrow + flexShrink it means we can set
|
|
|
|
// the computedFlexBasis to 0 instead of measuring and shrinking / flexing the
|
|
|
|
// child to exactly match the remaining space
|
|
|
|
if (measureModeMainDim == YGMeasureModeExactly) {
|
|
|
|
for (auto child : children) {
|
2018-07-11 05:55:02 -07:00
|
|
|
if (child->isNodeFlexible()) {
|
|
|
|
if (singleFlexChild != nullptr ||
|
|
|
|
YGFloatsEqual(child->resolveFlexGrow(), 0.0f) ||
|
|
|
|
YGFloatsEqual(child->resolveFlexShrink(), 0.0f)) {
|
|
|
|
// There is already a flexible child, or this flexible child doesn't
|
|
|
|
// have flexGrow and flexShrink, abort
|
2018-01-15 10:09:40 -08:00
|
|
|
singleFlexChild = nullptr;
|
|
|
|
break;
|
2018-07-11 05:55:02 -07:00
|
|
|
} else {
|
|
|
|
singleFlexChild = child;
|
2018-01-15 10:09:40 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto child : children) {
|
|
|
|
child->resolveDimension();
|
|
|
|
if (child->getStyle().display == YGDisplayNone) {
|
|
|
|
YGZeroOutLayoutRecursivly(child);
|
|
|
|
child->setHasNewLayout(true);
|
|
|
|
child->setDirty(false);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (performLayout) {
|
2018-04-01 18:27:06 -07:00
|
|
|
// Set the initial position (relative to the owner).
|
2018-01-15 10:09:50 -08:00
|
|
|
const YGDirection childDirection = child->resolveDirection(direction);
|
2018-01-15 10:09:40 -08:00
|
|
|
const float mainDim = YGFlexDirectionIsRow(mainAxis)
|
|
|
|
? availableInnerWidth
|
|
|
|
: availableInnerHeight;
|
|
|
|
const float crossDim = YGFlexDirectionIsRow(mainAxis)
|
|
|
|
? availableInnerHeight
|
|
|
|
: availableInnerWidth;
|
|
|
|
child->setPosition(
|
|
|
|
childDirection, mainDim, crossDim, availableInnerWidth);
|
|
|
|
}
|
2018-01-16 08:57:11 -08:00
|
|
|
|
|
|
|
if (child->getStyle().positionType == YGPositionTypeAbsolute) {
|
|
|
|
continue;
|
|
|
|
}
|
2018-01-15 10:09:40 -08:00
|
|
|
if (child == singleFlexChild) {
|
|
|
|
child->setLayoutComputedFlexBasisGeneration(gCurrentGenerationCount);
|
2018-04-04 07:55:39 -07:00
|
|
|
child->setLayoutComputedFlexBasis(YGFloatOptional(0));
|
2018-01-15 10:09:40 -08:00
|
|
|
} else {
|
|
|
|
YGNodeComputeFlexBasisForChild(
|
|
|
|
node,
|
|
|
|
child,
|
|
|
|
availableInnerWidth,
|
|
|
|
widthMeasureMode,
|
|
|
|
availableInnerHeight,
|
|
|
|
availableInnerWidth,
|
|
|
|
availableInnerHeight,
|
|
|
|
heightMeasureMode,
|
|
|
|
direction,
|
|
|
|
config);
|
|
|
|
}
|
|
|
|
|
2018-04-04 07:55:54 -07:00
|
|
|
totalOuterFlexBasis += YGUnwrapFloatOptional(
|
|
|
|
child->getLayout().computedFlexBasis +
|
|
|
|
child->getMarginForAxis(mainAxis, availableInnerWidth));
|
2018-01-15 10:09:40 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-05 06:32:59 -08:00
|
|
|
// This function assumes that all the children of node have their
|
|
|
|
// computedFlexBasis properly computed(To do this use
|
|
|
|
// YGNodeComputeFlexBasisForChildren function).
|
|
|
|
// This function calculates YGCollectFlexItemsRowMeasurement
|
|
|
|
static YGCollectFlexItemsRowValues YGCalculateCollectFlexItemsRowValues(
|
|
|
|
const YGNodeRef& node,
|
2018-04-01 18:27:06 -07:00
|
|
|
const YGDirection ownerDirection,
|
|
|
|
const float mainAxisownerSize,
|
2018-02-05 06:32:59 -08:00
|
|
|
const float availableInnerWidth,
|
|
|
|
const float availableInnerMainDim,
|
|
|
|
const uint32_t startOfLineIndex,
|
|
|
|
const uint32_t lineCount) {
|
|
|
|
YGCollectFlexItemsRowValues flexAlgoRowMeasurement = {};
|
|
|
|
flexAlgoRowMeasurement.relativeChildren.reserve(node->getChildren().size());
|
|
|
|
|
|
|
|
float sizeConsumedOnCurrentLineIncludingMinConstraint = 0;
|
|
|
|
const YGFlexDirection mainAxis = YGResolveFlexDirection(
|
2018-04-01 18:27:06 -07:00
|
|
|
node->getStyle().flexDirection, node->resolveDirection(ownerDirection));
|
2018-02-05 06:32:59 -08:00
|
|
|
const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
|
|
|
|
|
|
|
|
// Add items to the current line until it's full or we run out of items.
|
|
|
|
uint32_t endOfLineIndex = startOfLineIndex;
|
2018-07-13 12:34:46 -07:00
|
|
|
for (; endOfLineIndex < node->getChildren().size(); endOfLineIndex++) {
|
2018-02-05 06:32:59 -08:00
|
|
|
const YGNodeRef child = node->getChild(endOfLineIndex);
|
|
|
|
if (child->getStyle().display == YGDisplayNone ||
|
|
|
|
child->getStyle().positionType == YGPositionTypeAbsolute) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
child->setLineIndex(lineCount);
|
2018-04-04 07:55:54 -07:00
|
|
|
const float childMarginMainAxis = YGUnwrapFloatOptional(
|
|
|
|
child->getMarginForAxis(mainAxis, availableInnerWidth));
|
2018-02-05 06:32:59 -08:00
|
|
|
const float flexBasisWithMinAndMaxConstraints =
|
2018-04-04 07:55:28 -07:00
|
|
|
YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
|
2018-02-05 06:32:59 -08:00
|
|
|
child,
|
|
|
|
mainAxis,
|
2018-04-04 07:55:39 -07:00
|
|
|
YGUnwrapFloatOptional(child->getLayout().computedFlexBasis),
|
2018-04-04 07:55:28 -07:00
|
|
|
mainAxisownerSize));
|
2018-02-05 06:32:59 -08:00
|
|
|
|
|
|
|
// If this is a multi-line flow and this item pushes us over the
|
|
|
|
// available size, we've
|
|
|
|
// hit the end of the current line. Break out of the loop and lay out
|
|
|
|
// the current line.
|
|
|
|
if (sizeConsumedOnCurrentLineIncludingMinConstraint +
|
|
|
|
flexBasisWithMinAndMaxConstraints + childMarginMainAxis >
|
|
|
|
availableInnerMainDim &&
|
|
|
|
isNodeFlexWrap && flexAlgoRowMeasurement.itemsOnLine > 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sizeConsumedOnCurrentLineIncludingMinConstraint +=
|
|
|
|
flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
|
|
|
|
flexAlgoRowMeasurement.sizeConsumedOnCurrentLine +=
|
|
|
|
flexBasisWithMinAndMaxConstraints + childMarginMainAxis;
|
|
|
|
flexAlgoRowMeasurement.itemsOnLine++;
|
|
|
|
|
|
|
|
if (child->isNodeFlexible()) {
|
|
|
|
flexAlgoRowMeasurement.totalFlexGrowFactors += child->resolveFlexGrow();
|
|
|
|
|
|
|
|
// Unlike the grow factor, the shrink factor is scaled relative to the
|
|
|
|
// child dimension.
|
|
|
|
flexAlgoRowMeasurement.totalFlexShrinkScaledFactors +=
|
2018-04-04 07:55:39 -07:00
|
|
|
-child->resolveFlexShrink() *
|
|
|
|
YGUnwrapFloatOptional(child->getLayout().computedFlexBasis);
|
2018-02-05 06:32:59 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
flexAlgoRowMeasurement.relativeChildren.push_back(child);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The total flex factor needs to be floored to 1.
|
|
|
|
if (flexAlgoRowMeasurement.totalFlexGrowFactors > 0 &&
|
|
|
|
flexAlgoRowMeasurement.totalFlexGrowFactors < 1) {
|
|
|
|
flexAlgoRowMeasurement.totalFlexGrowFactors = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The total flex shrink factor needs to be floored to 1.
|
|
|
|
if (flexAlgoRowMeasurement.totalFlexShrinkScaledFactors > 0 &&
|
|
|
|
flexAlgoRowMeasurement.totalFlexShrinkScaledFactors < 1) {
|
|
|
|
flexAlgoRowMeasurement.totalFlexShrinkScaledFactors = 1;
|
|
|
|
}
|
|
|
|
flexAlgoRowMeasurement.endOfLineIndex = endOfLineIndex;
|
|
|
|
return flexAlgoRowMeasurement;
|
|
|
|
}
|
|
|
|
|
2018-02-05 06:33:05 -08:00
|
|
|
// It distributes the free space to the flexible items and ensures that the size
|
|
|
|
// of the flex items abide the min and max constraints. At the end of this
|
|
|
|
// function the child nodes would have proper size. Prior using this function
|
|
|
|
// please ensure that YGDistributeFreeSpaceFirstPass is called.
|
2018-02-06 07:05:18 -08:00
|
|
|
static float YGDistributeFreeSpaceSecondPass(
|
2018-02-05 06:33:03 -08:00
|
|
|
YGCollectFlexItemsRowValues& collectedFlexItemsValues,
|
|
|
|
const YGNodeRef node,
|
|
|
|
const YGFlexDirection mainAxis,
|
|
|
|
const YGFlexDirection crossAxis,
|
2018-04-01 18:27:06 -07:00
|
|
|
const float mainAxisownerSize,
|
2018-02-05 06:33:03 -08:00
|
|
|
const float availableInnerMainDim,
|
|
|
|
const float availableInnerCrossDim,
|
|
|
|
const float availableInnerWidth,
|
|
|
|
const float availableInnerHeight,
|
|
|
|
const bool flexBasisOverflows,
|
|
|
|
const YGMeasureMode measureModeCrossDim,
|
|
|
|
const bool performLayout,
|
|
|
|
const YGConfigRef config) {
|
|
|
|
float childFlexBasis = 0;
|
|
|
|
float flexShrinkScaledFactor = 0;
|
|
|
|
float flexGrowFactor = 0;
|
|
|
|
float deltaFreeSpace = 0;
|
|
|
|
const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
|
|
|
|
const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
|
|
|
|
|
|
|
|
for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
|
2018-04-04 07:55:28 -07:00
|
|
|
childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
|
2018-02-05 06:33:03 -08:00
|
|
|
currentRelativeChild,
|
|
|
|
mainAxis,
|
2018-04-04 07:55:39 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
currentRelativeChild->getLayout().computedFlexBasis),
|
2018-04-04 07:55:28 -07:00
|
|
|
mainAxisownerSize));
|
2018-02-05 06:33:03 -08:00
|
|
|
float updatedMainSize = childFlexBasis;
|
|
|
|
|
2018-03-01 04:00:35 -08:00
|
|
|
if (!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace < 0) {
|
2018-02-05 06:33:03 -08:00
|
|
|
flexShrinkScaledFactor =
|
|
|
|
-currentRelativeChild->resolveFlexShrink() * childFlexBasis;
|
|
|
|
// Is this child able to shrink?
|
|
|
|
if (flexShrinkScaledFactor != 0) {
|
|
|
|
float childSize;
|
|
|
|
|
2018-03-01 04:00:35 -08:00
|
|
|
if (!YGFloatIsUndefined(
|
|
|
|
collectedFlexItemsValues.totalFlexShrinkScaledFactors) &&
|
|
|
|
collectedFlexItemsValues.totalFlexShrinkScaledFactors == 0) {
|
2018-02-05 06:33:03 -08:00
|
|
|
childSize = childFlexBasis + flexShrinkScaledFactor;
|
|
|
|
} else {
|
|
|
|
childSize = childFlexBasis +
|
|
|
|
(collectedFlexItemsValues.remainingFreeSpace /
|
|
|
|
collectedFlexItemsValues.totalFlexShrinkScaledFactors) *
|
|
|
|
flexShrinkScaledFactor;
|
|
|
|
}
|
|
|
|
|
|
|
|
updatedMainSize = YGNodeBoundAxis(
|
|
|
|
currentRelativeChild,
|
|
|
|
mainAxis,
|
|
|
|
childSize,
|
|
|
|
availableInnerMainDim,
|
|
|
|
availableInnerWidth);
|
|
|
|
}
|
2018-03-01 04:00:35 -08:00
|
|
|
} else if (
|
|
|
|
!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace > 0) {
|
2018-02-05 06:33:03 -08:00
|
|
|
flexGrowFactor = currentRelativeChild->resolveFlexGrow();
|
|
|
|
|
|
|
|
// Is this child able to grow?
|
2018-03-01 04:00:35 -08:00
|
|
|
if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) {
|
2018-02-05 06:33:03 -08:00
|
|
|
updatedMainSize = YGNodeBoundAxis(
|
|
|
|
currentRelativeChild,
|
|
|
|
mainAxis,
|
|
|
|
childFlexBasis +
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace /
|
|
|
|
collectedFlexItemsValues.totalFlexGrowFactors *
|
|
|
|
flexGrowFactor,
|
|
|
|
availableInnerMainDim,
|
|
|
|
availableInnerWidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-06 07:05:18 -08:00
|
|
|
deltaFreeSpace += updatedMainSize - childFlexBasis;
|
2018-02-05 06:33:03 -08:00
|
|
|
|
2018-04-04 07:55:54 -07:00
|
|
|
const float marginMain = YGUnwrapFloatOptional(
|
|
|
|
currentRelativeChild->getMarginForAxis(mainAxis, availableInnerWidth));
|
|
|
|
const float marginCross = YGUnwrapFloatOptional(
|
|
|
|
currentRelativeChild->getMarginForAxis(crossAxis, availableInnerWidth));
|
2018-02-05 06:33:03 -08:00
|
|
|
|
|
|
|
float childCrossSize;
|
|
|
|
float childMainSize = updatedMainSize + marginMain;
|
|
|
|
YGMeasureMode childCrossMeasureMode;
|
|
|
|
YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
|
|
|
|
|
2018-04-03 14:56:29 -07:00
|
|
|
if (!currentRelativeChild->getStyle().aspectRatio.isUndefined()) {
|
2018-02-05 06:33:03 -08:00
|
|
|
childCrossSize = isMainAxisRow ? (childMainSize - marginMain) /
|
2018-04-03 14:56:29 -07:00
|
|
|
currentRelativeChild->getStyle().aspectRatio.getValue()
|
2018-02-05 06:33:03 -08:00
|
|
|
: (childMainSize - marginMain) *
|
2018-04-03 14:56:29 -07:00
|
|
|
currentRelativeChild->getStyle().aspectRatio.getValue();
|
2018-02-05 06:33:03 -08:00
|
|
|
childCrossMeasureMode = YGMeasureModeExactly;
|
|
|
|
|
|
|
|
childCrossSize += marginCross;
|
|
|
|
} else if (
|
|
|
|
!YGFloatIsUndefined(availableInnerCrossDim) &&
|
|
|
|
!YGNodeIsStyleDimDefined(
|
|
|
|
currentRelativeChild, crossAxis, availableInnerCrossDim) &&
|
|
|
|
measureModeCrossDim == YGMeasureModeExactly &&
|
|
|
|
!(isNodeFlexWrap && flexBasisOverflows) &&
|
|
|
|
YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch &&
|
|
|
|
currentRelativeChild->marginLeadingValue(crossAxis).unit !=
|
|
|
|
YGUnitAuto &&
|
|
|
|
currentRelativeChild->marginTrailingValue(crossAxis).unit !=
|
|
|
|
YGUnitAuto) {
|
|
|
|
childCrossSize = availableInnerCrossDim;
|
|
|
|
childCrossMeasureMode = YGMeasureModeExactly;
|
|
|
|
} else if (!YGNodeIsStyleDimDefined(
|
|
|
|
currentRelativeChild, crossAxis, availableInnerCrossDim)) {
|
|
|
|
childCrossSize = availableInnerCrossDim;
|
|
|
|
childCrossMeasureMode = YGFloatIsUndefined(childCrossSize)
|
|
|
|
? YGMeasureModeUndefined
|
|
|
|
: YGMeasureModeAtMost;
|
|
|
|
} else {
|
|
|
|
childCrossSize =
|
2018-03-14 04:17:07 -07:00
|
|
|
YGUnwrapFloatOptional(YGResolveValue(
|
2018-02-05 06:33:03 -08:00
|
|
|
currentRelativeChild->getResolvedDimension(dim[crossAxis]),
|
2018-03-14 04:17:07 -07:00
|
|
|
availableInnerCrossDim)) +
|
2018-02-05 06:33:03 -08:00
|
|
|
marginCross;
|
|
|
|
const bool isLoosePercentageMeasurement =
|
|
|
|
currentRelativeChild->getResolvedDimension(dim[crossAxis]).unit ==
|
|
|
|
YGUnitPercent &&
|
|
|
|
measureModeCrossDim != YGMeasureModeExactly;
|
|
|
|
childCrossMeasureMode =
|
|
|
|
YGFloatIsUndefined(childCrossSize) || isLoosePercentageMeasurement
|
|
|
|
? YGMeasureModeUndefined
|
|
|
|
: YGMeasureModeExactly;
|
|
|
|
}
|
|
|
|
|
|
|
|
YGConstrainMaxSizeForMode(
|
|
|
|
currentRelativeChild,
|
|
|
|
mainAxis,
|
|
|
|
availableInnerMainDim,
|
|
|
|
availableInnerWidth,
|
|
|
|
&childMainMeasureMode,
|
|
|
|
&childMainSize);
|
|
|
|
YGConstrainMaxSizeForMode(
|
|
|
|
currentRelativeChild,
|
|
|
|
crossAxis,
|
|
|
|
availableInnerCrossDim,
|
|
|
|
availableInnerWidth,
|
|
|
|
&childCrossMeasureMode,
|
|
|
|
&childCrossSize);
|
|
|
|
|
|
|
|
const bool requiresStretchLayout =
|
|
|
|
!YGNodeIsStyleDimDefined(
|
|
|
|
currentRelativeChild, crossAxis, availableInnerCrossDim) &&
|
|
|
|
YGNodeAlignItem(node, currentRelativeChild) == YGAlignStretch &&
|
|
|
|
currentRelativeChild->marginLeadingValue(crossAxis).unit !=
|
|
|
|
YGUnitAuto &&
|
|
|
|
currentRelativeChild->marginTrailingValue(crossAxis).unit != YGUnitAuto;
|
|
|
|
|
|
|
|
const float childWidth = isMainAxisRow ? childMainSize : childCrossSize;
|
|
|
|
const float childHeight = !isMainAxisRow ? childMainSize : childCrossSize;
|
|
|
|
|
|
|
|
const YGMeasureMode childWidthMeasureMode =
|
|
|
|
isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
|
|
|
|
const YGMeasureMode childHeightMeasureMode =
|
|
|
|
!isMainAxisRow ? childMainMeasureMode : childCrossMeasureMode;
|
|
|
|
|
|
|
|
// Recursively call the layout algorithm for this child with the updated
|
|
|
|
// main size.
|
|
|
|
YGLayoutNodeInternal(
|
|
|
|
currentRelativeChild,
|
|
|
|
childWidth,
|
|
|
|
childHeight,
|
|
|
|
node->getLayout().direction,
|
|
|
|
childWidthMeasureMode,
|
|
|
|
childHeightMeasureMode,
|
|
|
|
availableInnerWidth,
|
|
|
|
availableInnerHeight,
|
|
|
|
performLayout && !requiresStretchLayout,
|
|
|
|
"flex",
|
|
|
|
config);
|
|
|
|
node->setLayoutHadOverflow(
|
|
|
|
node->getLayout().hadOverflow |
|
|
|
|
currentRelativeChild->getLayout().hadOverflow);
|
|
|
|
}
|
2018-02-06 07:05:18 -08:00
|
|
|
return deltaFreeSpace;
|
2018-02-05 06:33:03 -08:00
|
|
|
}
|
|
|
|
|
2018-02-05 06:33:05 -08:00
|
|
|
// It distributes the free space to the flexible items.For those flexible items
|
|
|
|
// whose min and max constraints are triggered, those flex item's clamped size
|
|
|
|
// is removed from the remaingfreespace.
|
2018-02-05 06:33:01 -08:00
|
|
|
static void YGDistributeFreeSpaceFirstPass(
|
|
|
|
YGCollectFlexItemsRowValues& collectedFlexItemsValues,
|
|
|
|
const YGFlexDirection mainAxis,
|
2018-04-01 18:27:06 -07:00
|
|
|
const float mainAxisownerSize,
|
2018-02-05 06:33:01 -08:00
|
|
|
const float availableInnerMainDim,
|
|
|
|
const float availableInnerWidth) {
|
|
|
|
float flexShrinkScaledFactor = 0;
|
|
|
|
float flexGrowFactor = 0;
|
|
|
|
float baseMainSize = 0;
|
|
|
|
float boundMainSize = 0;
|
|
|
|
float deltaFreeSpace = 0;
|
|
|
|
|
|
|
|
for (auto currentRelativeChild : collectedFlexItemsValues.relativeChildren) {
|
2018-04-04 07:55:28 -07:00
|
|
|
float childFlexBasis = YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
|
2018-02-05 06:33:01 -08:00
|
|
|
currentRelativeChild,
|
|
|
|
mainAxis,
|
2018-04-04 07:55:39 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
currentRelativeChild->getLayout().computedFlexBasis),
|
2018-04-04 07:55:28 -07:00
|
|
|
mainAxisownerSize));
|
2018-02-05 06:33:01 -08:00
|
|
|
|
|
|
|
if (collectedFlexItemsValues.remainingFreeSpace < 0) {
|
|
|
|
flexShrinkScaledFactor =
|
|
|
|
-currentRelativeChild->resolveFlexShrink() * childFlexBasis;
|
|
|
|
|
|
|
|
// Is this child able to shrink?
|
2018-03-01 04:00:35 -08:00
|
|
|
if (!YGFloatIsUndefined(flexShrinkScaledFactor) &&
|
|
|
|
flexShrinkScaledFactor != 0) {
|
2018-02-05 06:33:01 -08:00
|
|
|
baseMainSize = childFlexBasis +
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace /
|
|
|
|
collectedFlexItemsValues.totalFlexShrinkScaledFactors *
|
|
|
|
flexShrinkScaledFactor;
|
|
|
|
boundMainSize = YGNodeBoundAxis(
|
|
|
|
currentRelativeChild,
|
|
|
|
mainAxis,
|
|
|
|
baseMainSize,
|
|
|
|
availableInnerMainDim,
|
|
|
|
availableInnerWidth);
|
2018-03-01 04:00:35 -08:00
|
|
|
if (!YGFloatIsUndefined(baseMainSize) &&
|
|
|
|
!YGFloatIsUndefined(boundMainSize) &&
|
|
|
|
baseMainSize != boundMainSize) {
|
2018-02-05 06:33:01 -08:00
|
|
|
// By excluding this item's size and flex factor from remaining,
|
|
|
|
// this item's
|
|
|
|
// min/max constraints should also trigger in the second pass
|
|
|
|
// resulting in the
|
|
|
|
// item's size calculation being identical in the first and second
|
|
|
|
// passes.
|
|
|
|
deltaFreeSpace += boundMainSize - childFlexBasis;
|
|
|
|
collectedFlexItemsValues.totalFlexShrinkScaledFactors -=
|
|
|
|
flexShrinkScaledFactor;
|
|
|
|
}
|
|
|
|
}
|
2018-03-01 04:00:35 -08:00
|
|
|
} else if (
|
|
|
|
!YGFloatIsUndefined(collectedFlexItemsValues.remainingFreeSpace) &&
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace > 0) {
|
2018-02-05 06:33:01 -08:00
|
|
|
flexGrowFactor = currentRelativeChild->resolveFlexGrow();
|
|
|
|
|
|
|
|
// Is this child able to grow?
|
2018-03-01 04:00:35 -08:00
|
|
|
if (!YGFloatIsUndefined(flexGrowFactor) && flexGrowFactor != 0) {
|
2018-02-05 06:33:01 -08:00
|
|
|
baseMainSize = childFlexBasis +
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace /
|
|
|
|
collectedFlexItemsValues.totalFlexGrowFactors * flexGrowFactor;
|
|
|
|
boundMainSize = YGNodeBoundAxis(
|
|
|
|
currentRelativeChild,
|
|
|
|
mainAxis,
|
|
|
|
baseMainSize,
|
|
|
|
availableInnerMainDim,
|
|
|
|
availableInnerWidth);
|
|
|
|
|
2018-03-01 04:00:35 -08:00
|
|
|
if (!YGFloatIsUndefined(baseMainSize) &&
|
|
|
|
!YGFloatIsUndefined(boundMainSize) &&
|
|
|
|
baseMainSize != boundMainSize) {
|
2018-02-05 06:33:01 -08:00
|
|
|
// By excluding this item's size and flex factor from remaining,
|
|
|
|
// this item's
|
|
|
|
// min/max constraints should also trigger in the second pass
|
|
|
|
// resulting in the
|
|
|
|
// item's size calculation being identical in the first and second
|
|
|
|
// passes.
|
|
|
|
deltaFreeSpace += boundMainSize - childFlexBasis;
|
|
|
|
collectedFlexItemsValues.totalFlexGrowFactors -= flexGrowFactor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace -= deltaFreeSpace;
|
|
|
|
}
|
|
|
|
|
2018-02-05 06:33:05 -08:00
|
|
|
// Do two passes over the flex items to figure out how to distribute the
|
|
|
|
// remaining space.
|
|
|
|
// The first pass finds the items whose min/max constraints trigger,
|
|
|
|
// freezes them at those
|
|
|
|
// sizes, and excludes those sizes from the remaining space. The second
|
|
|
|
// pass sets the size
|
|
|
|
// of each flexible item. It distributes the remaining space amongst the
|
|
|
|
// items whose min/max
|
|
|
|
// constraints didn't trigger in pass 1. For the other items, it sets
|
|
|
|
// their sizes by forcing
|
|
|
|
// their min/max constraints to trigger again.
|
|
|
|
//
|
|
|
|
// This two pass approach for resolving min/max constraints deviates from
|
|
|
|
// the spec. The
|
|
|
|
// spec (https://www.w3.org/TR/YG-flexbox-1/#resolve-flexible-lengths)
|
|
|
|
// describes a process
|
|
|
|
// that needs to be repeated a variable number of times. The algorithm
|
|
|
|
// implemented here
|
|
|
|
// won't handle all cases but it was simpler to implement and it mitigates
|
|
|
|
// performance
|
|
|
|
// concerns because we know exactly how many passes it'll do.
|
|
|
|
//
|
|
|
|
// At the end of this function the child nodes would have the proper size
|
|
|
|
// assigned to them.
|
|
|
|
//
|
|
|
|
static void YGResolveFlexibleLength(
|
|
|
|
const YGNodeRef node,
|
|
|
|
YGCollectFlexItemsRowValues& collectedFlexItemsValues,
|
|
|
|
const YGFlexDirection mainAxis,
|
|
|
|
const YGFlexDirection crossAxis,
|
2018-04-01 18:27:06 -07:00
|
|
|
const float mainAxisownerSize,
|
2018-02-05 06:33:05 -08:00
|
|
|
const float availableInnerMainDim,
|
|
|
|
const float availableInnerCrossDim,
|
|
|
|
const float availableInnerWidth,
|
|
|
|
const float availableInnerHeight,
|
|
|
|
const bool flexBasisOverflows,
|
|
|
|
const YGMeasureMode measureModeCrossDim,
|
|
|
|
const bool performLayout,
|
|
|
|
const YGConfigRef config) {
|
2018-02-06 07:05:18 -08:00
|
|
|
const float originalFreeSpace = collectedFlexItemsValues.remainingFreeSpace;
|
2018-02-05 06:33:05 -08:00
|
|
|
// First pass: detect the flex items whose min/max constraints trigger
|
|
|
|
YGDistributeFreeSpaceFirstPass(
|
|
|
|
collectedFlexItemsValues,
|
|
|
|
mainAxis,
|
2018-04-01 18:27:06 -07:00
|
|
|
mainAxisownerSize,
|
2018-02-05 06:33:05 -08:00
|
|
|
availableInnerMainDim,
|
|
|
|
availableInnerWidth);
|
|
|
|
|
|
|
|
// Second pass: resolve the sizes of the flexible items
|
2018-02-06 07:05:18 -08:00
|
|
|
const float distributedFreeSpace = YGDistributeFreeSpaceSecondPass(
|
2018-02-05 06:33:05 -08:00
|
|
|
collectedFlexItemsValues,
|
|
|
|
node,
|
|
|
|
mainAxis,
|
|
|
|
crossAxis,
|
2018-04-01 18:27:06 -07:00
|
|
|
mainAxisownerSize,
|
2018-02-05 06:33:05 -08:00
|
|
|
availableInnerMainDim,
|
|
|
|
availableInnerCrossDim,
|
|
|
|
availableInnerWidth,
|
|
|
|
availableInnerHeight,
|
|
|
|
flexBasisOverflows,
|
|
|
|
measureModeCrossDim,
|
|
|
|
performLayout,
|
|
|
|
config);
|
2018-02-06 07:05:18 -08:00
|
|
|
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace =
|
|
|
|
originalFreeSpace - distributedFreeSpace;
|
2018-02-05 06:33:05 -08:00
|
|
|
}
|
|
|
|
|
2018-02-06 08:39:49 -08:00
|
|
|
static void YGJustifyMainAxis(
|
|
|
|
const YGNodeRef node,
|
|
|
|
YGCollectFlexItemsRowValues& collectedFlexItemsValues,
|
|
|
|
const uint32_t& startOfLineIndex,
|
|
|
|
const YGFlexDirection& mainAxis,
|
|
|
|
const YGFlexDirection& crossAxis,
|
|
|
|
const YGMeasureMode& measureModeMainDim,
|
|
|
|
const YGMeasureMode& measureModeCrossDim,
|
2018-04-01 18:27:06 -07:00
|
|
|
const float& mainAxisownerSize,
|
|
|
|
const float& ownerWidth,
|
2018-02-06 08:39:49 -08:00
|
|
|
const float& availableInnerMainDim,
|
|
|
|
const float& availableInnerCrossDim,
|
|
|
|
const float& availableInnerWidth,
|
|
|
|
const bool& performLayout) {
|
|
|
|
const YGStyle style = node->getStyle();
|
|
|
|
|
|
|
|
// If we are using "at most" rules in the main axis. Calculate the remaining
|
|
|
|
// space when constraint by the min size defined for the main axis.
|
|
|
|
if (measureModeMainDim == YGMeasureModeAtMost &&
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace > 0) {
|
|
|
|
if (style.minDimensions[dim[mainAxis]].unit != YGUnitUndefined &&
|
2018-04-01 18:27:06 -07:00
|
|
|
!YGResolveValue(style.minDimensions[dim[mainAxis]], mainAxisownerSize)
|
2018-03-15 12:29:02 -07:00
|
|
|
.isUndefined()) {
|
2018-03-01 04:00:35 -08:00
|
|
|
collectedFlexItemsValues.remainingFreeSpace = YGFloatMax(
|
2018-02-06 08:39:49 -08:00
|
|
|
0,
|
2018-03-14 04:17:07 -07:00
|
|
|
YGUnwrapFloatOptional(YGResolveValue(
|
2018-04-01 18:27:06 -07:00
|
|
|
style.minDimensions[dim[mainAxis]], mainAxisownerSize)) -
|
2018-02-06 08:39:49 -08:00
|
|
|
(availableInnerMainDim -
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace));
|
|
|
|
} else {
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int numberOfAutoMarginsOnCurrentLine = 0;
|
|
|
|
for (uint32_t i = startOfLineIndex;
|
|
|
|
i < collectedFlexItemsValues.endOfLineIndex;
|
|
|
|
i++) {
|
|
|
|
const YGNodeRef child = node->getChild(i);
|
2018-02-07 08:39:25 -08:00
|
|
|
if (child->getStyle().positionType == YGPositionTypeRelative) {
|
2018-02-06 08:39:49 -08:00
|
|
|
if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
|
|
|
|
numberOfAutoMarginsOnCurrentLine++;
|
|
|
|
}
|
|
|
|
if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
|
|
|
|
numberOfAutoMarginsOnCurrentLine++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// In order to position the elements in the main axis, we have two
|
|
|
|
// controls. The space between the beginning and the first element
|
|
|
|
// and the space between each two elements.
|
|
|
|
float leadingMainDim = 0;
|
|
|
|
float betweenMainDim = 0;
|
|
|
|
const YGJustify justifyContent = node->getStyle().justifyContent;
|
|
|
|
|
|
|
|
if (numberOfAutoMarginsOnCurrentLine == 0) {
|
|
|
|
switch (justifyContent) {
|
|
|
|
case YGJustifyCenter:
|
|
|
|
leadingMainDim = collectedFlexItemsValues.remainingFreeSpace / 2;
|
|
|
|
break;
|
|
|
|
case YGJustifyFlexEnd:
|
|
|
|
leadingMainDim = collectedFlexItemsValues.remainingFreeSpace;
|
|
|
|
break;
|
|
|
|
case YGJustifySpaceBetween:
|
|
|
|
if (collectedFlexItemsValues.itemsOnLine > 1) {
|
|
|
|
betweenMainDim =
|
2018-03-01 04:00:35 -08:00
|
|
|
YGFloatMax(collectedFlexItemsValues.remainingFreeSpace, 0) /
|
2018-02-06 08:39:49 -08:00
|
|
|
(collectedFlexItemsValues.itemsOnLine - 1);
|
|
|
|
} else {
|
|
|
|
betweenMainDim = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case YGJustifySpaceEvenly:
|
|
|
|
// Space is distributed evenly across all elements
|
|
|
|
betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
|
|
|
|
(collectedFlexItemsValues.itemsOnLine + 1);
|
|
|
|
leadingMainDim = betweenMainDim;
|
|
|
|
break;
|
|
|
|
case YGJustifySpaceAround:
|
|
|
|
// Space on the edges is half of the space between elements
|
|
|
|
betweenMainDim = collectedFlexItemsValues.remainingFreeSpace /
|
|
|
|
collectedFlexItemsValues.itemsOnLine;
|
|
|
|
leadingMainDim = betweenMainDim / 2;
|
|
|
|
break;
|
|
|
|
case YGJustifyFlexStart:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-04 07:55:37 -07:00
|
|
|
const float leadingPaddingAndBorderMain = YGUnwrapFloatOptional(
|
|
|
|
node->getLeadingPaddingAndBorder(mainAxis, ownerWidth));
|
2018-02-06 08:39:49 -08:00
|
|
|
collectedFlexItemsValues.mainDim =
|
|
|
|
leadingPaddingAndBorderMain + leadingMainDim;
|
|
|
|
collectedFlexItemsValues.crossDim = 0;
|
|
|
|
|
|
|
|
for (uint32_t i = startOfLineIndex;
|
|
|
|
i < collectedFlexItemsValues.endOfLineIndex;
|
|
|
|
i++) {
|
|
|
|
const YGNodeRef child = node->getChild(i);
|
|
|
|
const YGStyle childStyle = child->getStyle();
|
|
|
|
const YGLayout childLayout = child->getLayout();
|
|
|
|
if (childStyle.display == YGDisplayNone) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (childStyle.positionType == YGPositionTypeAbsolute &&
|
|
|
|
child->isLeadingPositionDefined(mainAxis)) {
|
|
|
|
if (performLayout) {
|
|
|
|
// In case the child is position absolute and has left/top being
|
|
|
|
// defined, we override the position to whatever the user said
|
|
|
|
// (and margin/border).
|
|
|
|
child->setLayoutPosition(
|
2018-04-04 07:55:42 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
child->getLeadingPosition(mainAxis, availableInnerMainDim)) +
|
2018-02-06 08:39:49 -08:00
|
|
|
node->getLeadingBorder(mainAxis) +
|
2018-04-04 07:55:49 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
child->getLeadingMargin(mainAxis, availableInnerWidth)),
|
2018-02-06 08:39:49 -08:00
|
|
|
pos[mainAxis]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Now that we placed the element, we need to update the variables.
|
|
|
|
// We need to do that only for relative elements. Absolute elements
|
|
|
|
// do not take part in that phase.
|
|
|
|
if (childStyle.positionType == YGPositionTypeRelative) {
|
|
|
|
if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
|
|
|
|
collectedFlexItemsValues.mainDim +=
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace /
|
|
|
|
numberOfAutoMarginsOnCurrentLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (performLayout) {
|
|
|
|
child->setLayoutPosition(
|
|
|
|
childLayout.position[pos[mainAxis]] +
|
|
|
|
collectedFlexItemsValues.mainDim,
|
|
|
|
pos[mainAxis]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (child->marginTrailingValue(mainAxis).unit == YGUnitAuto) {
|
|
|
|
collectedFlexItemsValues.mainDim +=
|
|
|
|
collectedFlexItemsValues.remainingFreeSpace /
|
|
|
|
numberOfAutoMarginsOnCurrentLine;
|
|
|
|
}
|
|
|
|
bool canSkipFlex =
|
|
|
|
!performLayout && measureModeCrossDim == YGMeasureModeExactly;
|
|
|
|
if (canSkipFlex) {
|
|
|
|
// If we skipped the flex step, then we can't rely on the
|
|
|
|
// measuredDims because
|
|
|
|
// they weren't computed. This means we can't call
|
|
|
|
// YGNodeDimWithMargin.
|
|
|
|
collectedFlexItemsValues.mainDim += betweenMainDim +
|
2018-04-04 07:55:54 -07:00
|
|
|
YGUnwrapFloatOptional(child->getMarginForAxis(
|
|
|
|
mainAxis, availableInnerWidth)) +
|
2018-04-04 07:55:39 -07:00
|
|
|
YGUnwrapFloatOptional(childLayout.computedFlexBasis);
|
2018-02-06 08:39:49 -08:00
|
|
|
collectedFlexItemsValues.crossDim = availableInnerCrossDim;
|
|
|
|
} else {
|
|
|
|
// The main dimension is the sum of all the elements dimension plus
|
|
|
|
// the spacing.
|
|
|
|
collectedFlexItemsValues.mainDim += betweenMainDim +
|
|
|
|
YGNodeDimWithMargin(child, mainAxis, availableInnerWidth);
|
|
|
|
|
|
|
|
// The cross dimension is the max of the elements dimension since
|
|
|
|
// there can only be one element in that cross dimension.
|
2018-03-01 04:00:35 -08:00
|
|
|
collectedFlexItemsValues.crossDim = YGFloatMax(
|
2018-02-06 08:39:49 -08:00
|
|
|
collectedFlexItemsValues.crossDim,
|
|
|
|
YGNodeDimWithMargin(child, crossAxis, availableInnerWidth));
|
|
|
|
}
|
|
|
|
} else if (performLayout) {
|
|
|
|
child->setLayoutPosition(
|
|
|
|
childLayout.position[pos[mainAxis]] +
|
|
|
|
node->getLeadingBorder(mainAxis) + leadingMainDim,
|
|
|
|
pos[mainAxis]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-04-04 07:55:37 -07:00
|
|
|
collectedFlexItemsValues.mainDim += YGUnwrapFloatOptional(
|
|
|
|
node->getTrailingPaddingAndBorder(mainAxis, ownerWidth));
|
2018-02-06 08:39:49 -08:00
|
|
|
}
|
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
//
|
2016-08-04 08:20:11 -07:00
|
|
|
// This is the main routine that implements a subset of the flexbox layout
|
|
|
|
// algorithm
|
2016-12-03 04:40:18 -08:00
|
|
|
// described in the W3C YG documentation: https://www.w3.org/TR/YG3-flexbox/.
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
//
|
|
|
|
// Limitations of this algorithm, compared to the full standard:
|
2016-08-04 08:20:11 -07:00
|
|
|
// * Display property is always assumed to be 'flex' except for Text nodes,
|
|
|
|
// which
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// are assumed to be 'inline-flex'.
|
2016-08-04 08:20:11 -07:00
|
|
|
// * The 'zIndex' property (or any form of z ordering) is not supported. Nodes
|
|
|
|
// are
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// stacked in document order.
|
2016-08-04 08:20:11 -07:00
|
|
|
// * The 'order' property is not supported. The order of flex items is always
|
|
|
|
// defined
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// by document order.
|
2016-08-04 08:20:11 -07:00
|
|
|
// * The 'visibility' property is always assumed to be 'visible'. Values of
|
|
|
|
// 'collapse'
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// and 'hidden' are not supported.
|
|
|
|
// * There is no support for forced breaks.
|
2016-08-04 08:20:11 -07:00
|
|
|
// * It does not support vertical inline directions (top-to-bottom or
|
|
|
|
// bottom-to-top text).
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
//
|
|
|
|
// Deviations from standard:
|
2016-08-04 08:20:11 -07:00
|
|
|
// * Section 4.5 of the spec indicates that all flex items have a default
|
|
|
|
// minimum
|
|
|
|
// main size. For text blocks, for example, this is the width of the widest
|
|
|
|
// word.
|
|
|
|
// Calculating the minimum width is expensive, so we forego it and assume a
|
|
|
|
// default
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// minimum main size of 0.
|
2016-08-04 08:20:11 -07:00
|
|
|
// * Min/Max sizes in the main axis are not honored when resolving flexible
|
|
|
|
// lengths.
|
|
|
|
// * The spec indicates that the default value for 'flexDirection' is 'row',
|
|
|
|
// but
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// the algorithm below assumes a default of 'column'.
|
|
|
|
//
|
|
|
|
// Input parameters:
|
|
|
|
// - node: current node to be sized and layed out
|
2016-08-04 08:20:11 -07:00
|
|
|
// - availableWidth & availableHeight: available size to be used for sizing
|
|
|
|
// the node
|
2016-12-02 05:47:43 -08:00
|
|
|
// or YGUndefined if the size is not available; interpretation depends on
|
2016-08-04 08:20:11 -07:00
|
|
|
// layout
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// flags
|
2018-04-01 18:27:06 -07:00
|
|
|
// - ownerDirection: the inline (text) direction within the owner
|
2016-08-04 08:20:11 -07:00
|
|
|
// (left-to-right or
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// right-to-left)
|
2016-08-04 08:20:11 -07:00
|
|
|
// - widthMeasureMode: indicates the sizing rules for the width (see below
|
|
|
|
// for explanation)
|
|
|
|
// - heightMeasureMode: indicates the sizing rules for the height (see below
|
|
|
|
// for explanation)
|
|
|
|
// - performLayout: specifies whether the caller is interested in just the
|
|
|
|
// dimensions
|
|
|
|
// of the node or it requires the entire node and its subtree to be layed
|
|
|
|
// out
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// (with final positions)
|
|
|
|
//
|
|
|
|
// Details:
|
2016-08-04 08:20:11 -07:00
|
|
|
// This routine is called recursively to lay out subtrees of flexbox
|
|
|
|
// elements. It uses the
|
|
|
|
// information in node.style, which is treated as a read-only input. It is
|
|
|
|
// responsible for
|
|
|
|
// setting the layout.direction and layout.measuredDimensions fields for the
|
|
|
|
// input node as well
|
|
|
|
// as the layout.position and layout.lineIndex fields for its child nodes.
|
|
|
|
// The
|
|
|
|
// layout.measuredDimensions field includes any border or padding for the
|
|
|
|
// node but does
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// not include margins.
|
|
|
|
//
|
2016-08-04 08:20:11 -07:00
|
|
|
// The spec describes four different layout modes: "fill available", "max
|
|
|
|
// content", "min
|
|
|
|
// content",
|
|
|
|
// and "fit content". Of these, we don't use "min content" because we don't
|
|
|
|
// support default
|
|
|
|
// minimum main sizes (see above for details). Each of our measure modes maps
|
|
|
|
// to a layout mode
|
2016-12-03 04:40:18 -08:00
|
|
|
// from the spec (https://www.w3.org/TR/YG3-sizing/#terms):
|
2016-12-02 05:47:43 -08:00
|
|
|
// - YGMeasureModeUndefined: max content
|
|
|
|
// - YGMeasureModeExactly: fill available
|
|
|
|
// - YGMeasureModeAtMost: fit content
|
2016-06-03 22:19:03 +01:00
|
|
|
//
|
2018-07-19 09:57:04 -07:00
|
|
|
// When calling YGNodelayoutImpl and YGLayoutNodeInternal, if the caller
|
|
|
|
// passes an available size of undefined then it must also pass a measure
|
|
|
|
// mode of YGMeasureModeUndefined in that dimension.
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
//
|
2018-07-19 09:57:04 -07:00
|
|
|
static void YGNodelayoutImpl(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const float availableWidth,
|
|
|
|
const float availableHeight,
|
|
|
|
const YGDirection ownerDirection,
|
|
|
|
const YGMeasureMode widthMeasureMode,
|
|
|
|
const YGMeasureMode heightMeasureMode,
|
|
|
|
const float ownerWidth,
|
|
|
|
const float ownerHeight,
|
|
|
|
const bool performLayout,
|
|
|
|
const YGConfigRef config) {
|
|
|
|
YGAssertWithNode(
|
|
|
|
node,
|
|
|
|
YGFloatIsUndefined(availableWidth)
|
|
|
|
? widthMeasureMode == YGMeasureModeUndefined
|
|
|
|
: true,
|
|
|
|
"availableWidth is indefinite so widthMeasureMode must be "
|
|
|
|
"YGMeasureModeUndefined");
|
|
|
|
YGAssertWithNode(
|
|
|
|
node,
|
|
|
|
YGFloatIsUndefined(availableHeight)
|
|
|
|
? heightMeasureMode == YGMeasureModeUndefined
|
|
|
|
: true,
|
|
|
|
"availableHeight is indefinite so heightMeasureMode must be "
|
|
|
|
"YGMeasureModeUndefined");
|
2016-06-03 22:19:03 +01:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// Set the resolved resolution in the node's layout.
|
2018-04-01 18:27:06 -07:00
|
|
|
const YGDirection direction = node->resolveDirection(ownerDirection);
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutDirection(direction);
|
2015-08-13 16:56:41 +08:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
const YGFlexDirection flexRowDirection =
|
|
|
|
YGResolveFlexDirection(YGFlexDirectionRow, direction);
|
2017-01-26 13:36:39 -08:00
|
|
|
const YGFlexDirection flexColumnDirection =
|
2017-03-10 06:05:53 -08:00
|
|
|
YGResolveFlexDirection(YGFlexDirectionColumn, direction);
|
2017-01-26 13:36:39 -08:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutMargin(
|
2018-04-04 07:55:49 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
node->getLeadingMargin(flexRowDirection, ownerWidth)),
|
|
|
|
YGEdgeStart);
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutMargin(
|
2018-04-04 07:55:51 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
node->getTrailingMargin(flexRowDirection, ownerWidth)),
|
|
|
|
YGEdgeEnd);
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutMargin(
|
2018-04-04 07:55:49 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
node->getLeadingMargin(flexColumnDirection, ownerWidth)),
|
|
|
|
YGEdgeTop);
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutMargin(
|
2018-04-04 07:55:51 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
node->getTrailingMargin(flexColumnDirection, ownerWidth)),
|
|
|
|
YGEdgeBottom);
|
2017-12-19 11:18:00 -08:00
|
|
|
|
2018-01-15 10:09:44 -08:00
|
|
|
node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), YGEdgeStart);
|
2018-01-15 10:09:46 -08:00
|
|
|
node->setLayoutBorder(node->getTrailingBorder(flexRowDirection), YGEdgeEnd);
|
2018-01-15 10:09:44 -08:00
|
|
|
node->setLayoutBorder(node->getLeadingBorder(flexColumnDirection), YGEdgeTop);
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutBorder(
|
2018-01-15 10:09:46 -08:00
|
|
|
node->getTrailingBorder(flexColumnDirection), YGEdgeBottom);
|
2017-12-19 11:18:00 -08:00
|
|
|
|
|
|
|
node->setLayoutPadding(
|
2018-04-04 07:55:30 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
node->getLeadingPadding(flexRowDirection, ownerWidth)),
|
|
|
|
YGEdgeStart);
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutPadding(
|
2018-04-04 07:55:34 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
node->getTrailingPadding(flexRowDirection, ownerWidth)),
|
|
|
|
YGEdgeEnd);
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutPadding(
|
2018-04-04 07:55:30 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
node->getLeadingPadding(flexColumnDirection, ownerWidth)),
|
|
|
|
YGEdgeTop);
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutPadding(
|
2018-04-04 07:55:34 -07:00
|
|
|
YGUnwrapFloatOptional(
|
|
|
|
node->getTrailingPadding(flexColumnDirection, ownerWidth)),
|
|
|
|
YGEdgeBottom);
|
2017-12-19 11:18:00 -08:00
|
|
|
|
|
|
|
if (node->getMeasure() != nullptr) {
|
2018-07-19 09:57:04 -07:00
|
|
|
YGNodeWithMeasureFuncSetMeasuredDimensions(
|
|
|
|
node,
|
|
|
|
availableWidth,
|
|
|
|
availableHeight,
|
|
|
|
widthMeasureMode,
|
|
|
|
heightMeasureMode,
|
|
|
|
ownerWidth,
|
|
|
|
ownerHeight);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-09 04:21:58 -08:00
|
|
|
const uint32_t childCount = YGNodeGetChildCount(node);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
if (childCount == 0) {
|
2018-07-19 09:57:04 -07:00
|
|
|
YGNodeEmptyContainerSetMeasuredDimensions(
|
|
|
|
node,
|
|
|
|
availableWidth,
|
|
|
|
availableHeight,
|
|
|
|
widthMeasureMode,
|
|
|
|
heightMeasureMode,
|
|
|
|
ownerWidth,
|
|
|
|
ownerHeight);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
// If we're not being asked to perform a full layout we can skip the algorithm
|
|
|
|
// if we already know the size
|
|
|
|
if (!performLayout &&
|
|
|
|
YGNodeFixedSizeSetMeasuredDimensions(
|
|
|
|
node,
|
|
|
|
availableWidth,
|
|
|
|
availableHeight,
|
|
|
|
widthMeasureMode,
|
|
|
|
heightMeasureMode,
|
|
|
|
ownerWidth,
|
|
|
|
ownerHeight)) {
|
2016-11-21 11:03:57 -08:00
|
|
|
return;
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
// At this point we know we're going to perform work. Ensure that each child
|
|
|
|
// has a mutable copy.
|
2018-01-08 02:48:32 -08:00
|
|
|
node->cloneChildrenIfNeeded();
|
2017-07-10 11:49:21 -07:00
|
|
|
// Reset layout flags, as they could have changed.
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutHadOverflow(false);
|
2017-07-10 11:49:21 -07:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// STEP 1: CALCULATE VALUES FOR REMAINDER OF ALGORITHM
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGFlexDirection mainAxis =
|
|
|
|
YGResolveFlexDirection(node->getStyle().flexDirection, direction);
|
2016-12-03 04:40:18 -08:00
|
|
|
const YGFlexDirection crossAxis = YGFlexDirectionCross(mainAxis, direction);
|
|
|
|
const bool isMainAxisRow = YGFlexDirectionIsRow(mainAxis);
|
2017-12-19 11:18:00 -08:00
|
|
|
const bool isNodeFlexWrap = node->getStyle().flexWrap != YGWrapNoWrap;
|
2015-09-24 11:56:18 -07:00
|
|
|
|
2018-04-01 18:27:06 -07:00
|
|
|
const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
|
|
|
|
const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth;
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
|
2018-04-04 07:55:37 -07:00
|
|
|
const float leadingPaddingAndBorderCross = YGUnwrapFloatOptional(
|
|
|
|
node->getLeadingPaddingAndBorder(crossAxis, ownerWidth));
|
2018-07-19 09:57:04 -07:00
|
|
|
const float paddingAndBorderAxisMain =
|
|
|
|
YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth);
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
const float paddingAndBorderAxisCross =
|
2018-04-01 18:27:06 -07:00
|
|
|
YGNodePaddingAndBorderForAxis(node, crossAxis, ownerWidth);
|
2016-06-03 22:19:03 +01:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
YGMeasureMode measureModeMainDim =
|
|
|
|
isMainAxisRow ? widthMeasureMode : heightMeasureMode;
|
|
|
|
YGMeasureMode measureModeCrossDim =
|
|
|
|
isMainAxisRow ? heightMeasureMode : widthMeasureMode;
|
2015-09-24 11:56:18 -07:00
|
|
|
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
const float paddingAndBorderAxisRow =
|
|
|
|
isMainAxisRow ? paddingAndBorderAxisMain : paddingAndBorderAxisCross;
|
|
|
|
const float paddingAndBorderAxisColumn =
|
|
|
|
isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain;
|
2016-12-23 10:15:50 -08:00
|
|
|
|
2018-04-04 07:55:54 -07:00
|
|
|
const float marginAxisRow = YGUnwrapFloatOptional(
|
|
|
|
node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
|
|
|
|
const float marginAxisColumn = YGUnwrapFloatOptional(
|
|
|
|
node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
|
2016-11-21 11:03:57 -08:00
|
|
|
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
const float minInnerWidth =
|
2018-07-19 09:57:04 -07:00
|
|
|
YGUnwrapFloatOptional(YGResolveValue(
|
|
|
|
node->getStyle().minDimensions[YGDimensionWidth], ownerWidth)) -
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
paddingAndBorderAxisRow;
|
|
|
|
const float maxInnerWidth =
|
2018-07-19 09:57:04 -07:00
|
|
|
YGUnwrapFloatOptional(YGResolveValue(
|
|
|
|
node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)) -
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
paddingAndBorderAxisRow;
|
|
|
|
const float minInnerHeight =
|
2018-07-19 09:57:04 -07:00
|
|
|
YGUnwrapFloatOptional(YGResolveValue(
|
|
|
|
node->getStyle().minDimensions[YGDimensionHeight], ownerHeight)) -
|
2017-11-24 07:06:16 -08:00
|
|
|
paddingAndBorderAxisColumn;
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
const float maxInnerHeight =
|
2018-03-14 04:17:07 -07:00
|
|
|
YGUnwrapFloatOptional(YGResolveValue(
|
2018-04-01 18:27:06 -07:00
|
|
|
node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight)) -
|
2017-11-24 07:06:16 -08:00
|
|
|
paddingAndBorderAxisColumn;
|
2018-01-16 09:31:21 -08:00
|
|
|
|
2016-12-21 11:37:32 -08:00
|
|
|
const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight;
|
|
|
|
const float maxInnerMainDim = isMainAxisRow ? maxInnerWidth : maxInnerHeight;
|
2016-12-23 10:15:50 -08:00
|
|
|
|
2018-01-15 10:09:40 -08:00
|
|
|
// STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS
|
|
|
|
|
|
|
|
float availableInnerWidth = YGNodeCalculateAvailableInnerDim(
|
2018-04-01 18:27:06 -07:00
|
|
|
node, YGFlexDirectionRow, availableWidth, ownerWidth);
|
2018-01-15 10:09:40 -08:00
|
|
|
float availableInnerHeight = YGNodeCalculateAvailableInnerDim(
|
2018-04-01 18:27:06 -07:00
|
|
|
node, YGFlexDirectionColumn, availableHeight, ownerHeight);
|
2018-01-15 10:09:40 -08:00
|
|
|
|
|
|
|
float availableInnerMainDim =
|
|
|
|
isMainAxisRow ? availableInnerWidth : availableInnerHeight;
|
|
|
|
const float availableInnerCrossDim =
|
|
|
|
isMainAxisRow ? availableInnerHeight : availableInnerWidth;
|
|
|
|
|
|
|
|
float totalOuterFlexBasis = 0;
|
|
|
|
|
|
|
|
// STEP 3: DETERMINE FLEX BASIS FOR EACH ITEM
|
|
|
|
|
|
|
|
YGNodeComputeFlexBasisForChildren(
|
|
|
|
node,
|
|
|
|
availableInnerWidth,
|
|
|
|
availableInnerHeight,
|
|
|
|
widthMeasureMode,
|
|
|
|
heightMeasureMode,
|
|
|
|
direction,
|
|
|
|
mainAxis,
|
|
|
|
config,
|
|
|
|
performLayout,
|
|
|
|
totalOuterFlexBasis);
|
|
|
|
|
2017-05-12 09:03:23 -07:00
|
|
|
const bool flexBasisOverflows = measureModeMainDim == YGMeasureModeUndefined
|
2018-02-05 06:32:59 -08:00
|
|
|
? false
|
|
|
|
: totalOuterFlexBasis > availableInnerMainDim;
|
|
|
|
if (isNodeFlexWrap && flexBasisOverflows &&
|
|
|
|
measureModeMainDim == YGMeasureModeAtMost) {
|
2017-02-20 07:16:58 -08:00
|
|
|
measureModeMainDim = YGMeasureModeExactly;
|
|
|
|
}
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// STEP 4: COLLECT FLEX ITEMS INTO FLEX LINES
|
2016-06-03 22:19:03 +01:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// Indexes of children that represent the first and last items in the line.
|
2016-08-02 08:06:55 -07:00
|
|
|
uint32_t startOfLineIndex = 0;
|
|
|
|
uint32_t endOfLineIndex = 0;
|
2016-06-03 22:19:03 +01:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// Number of lines.
|
2016-08-02 08:06:55 -07:00
|
|
|
uint32_t lineCount = 0;
|
2016-06-03 22:19:03 +01:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// Accumulated cross dimensions of all lines so far.
|
|
|
|
float totalLineCrossDim = 0;
|
|
|
|
|
|
|
|
// Max main dimension of all the lines.
|
|
|
|
float maxLineMainDim = 0;
|
2018-02-05 06:32:59 -08:00
|
|
|
YGCollectFlexItemsRowValues collectedFlexItemsValues;
|
|
|
|
for (; endOfLineIndex < childCount;
|
|
|
|
lineCount++, startOfLineIndex = endOfLineIndex) {
|
|
|
|
collectedFlexItemsValues = YGCalculateCollectFlexItemsRowValues(
|
|
|
|
node,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerDirection,
|
|
|
|
mainAxisownerSize,
|
2018-02-05 06:32:59 -08:00
|
|
|
availableInnerWidth,
|
|
|
|
availableInnerMainDim,
|
|
|
|
startOfLineIndex,
|
|
|
|
lineCount);
|
|
|
|
endOfLineIndex = collectedFlexItemsValues.endOfLineIndex;
|
2017-06-16 07:31:19 -07:00
|
|
|
|
2016-08-04 08:20:11 -07:00
|
|
|
// If we don't need to measure the cross axis, we can skip the entire flex
|
|
|
|
// step.
|
2018-02-05 06:32:59 -08:00
|
|
|
const bool canSkipFlex =
|
|
|
|
!performLayout && measureModeCrossDim == YGMeasureModeExactly;
|
2015-08-13 16:56:41 +08:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// STEP 5: RESOLVING FLEXIBLE LENGTHS ON MAIN AXIS
|
|
|
|
// Calculate the remaining available space that needs to be allocated.
|
|
|
|
// If the main dimension size isn't known, it is computed based on
|
|
|
|
// the line length, so there's no more space left to distribute.
|
2016-12-23 10:15:50 -08:00
|
|
|
|
2017-11-27 03:09:47 -08:00
|
|
|
bool sizeBasedOnContent = false;
|
2018-07-19 09:57:04 -07:00
|
|
|
// If we don't measure with exact main dimension we want to ensure we don't
|
|
|
|
// violate min and max
|
2017-02-28 16:27:18 -08:00
|
|
|
if (measureModeMainDim != YGMeasureModeExactly) {
|
2018-02-05 06:32:59 -08:00
|
|
|
if (!YGFloatIsUndefined(minInnerMainDim) &&
|
|
|
|
collectedFlexItemsValues.sizeConsumedOnCurrentLine <
|
|
|
|
minInnerMainDim) {
|
2016-12-21 11:37:32 -08:00
|
|
|
availableInnerMainDim = minInnerMainDim;
|
2018-02-05 06:32:59 -08:00
|
|
|
} else if (
|
|
|
|
!YGFloatIsUndefined(maxInnerMainDim) &&
|
|
|
|
collectedFlexItemsValues.sizeConsumedOnCurrentLine >
|
|
|
|
maxInnerMainDim) {
|
2016-12-21 11:37:32 -08:00
|
|
|
availableInnerMainDim = maxInnerMainDim;
|
2017-04-28 06:13:51 -07:00
|
|
|
} else {
|
2017-12-19 11:18:00 -08:00
|
|
|
if (!node->getConfig()->useLegacyStretchBehaviour &&
|
2018-03-01 04:00:35 -08:00
|
|
|
((YGFloatIsUndefined(
|
|
|
|
collectedFlexItemsValues.totalFlexGrowFactors) &&
|
|
|
|
collectedFlexItemsValues.totalFlexGrowFactors == 0) ||
|
|
|
|
(YGFloatIsUndefined(node->resolveFlexGrow()) &&
|
|
|
|
node->resolveFlexGrow() == 0))) {
|
2018-02-02 07:38:17 -08:00
|
|
|
// If we don't have any children to flex or we can't flex the node
|
|
|
|
// itself, space we've used is all space we need. Root node also
|
|
|
|
// should be shrunk to minimum
|
2018-02-05 06:32:59 -08:00
|
|
|
availableInnerMainDim =
|
|
|
|
collectedFlexItemsValues.sizeConsumedOnCurrentLine;
|
2017-04-28 06:13:51 -07:00
|
|
|
}
|
2018-02-02 07:38:17 -08:00
|
|
|
|
|
|
|
if (node->getConfig()->useLegacyStretchBehaviour) {
|
|
|
|
node->setLayoutDidUseLegacyFlag(true);
|
|
|
|
}
|
2017-12-19 11:18:00 -08:00
|
|
|
sizeBasedOnContent = !node->getConfig()->useLegacyStretchBehaviour;
|
2016-12-21 11:37:32 -08:00
|
|
|
}
|
|
|
|
}
|
2016-12-23 10:15:50 -08:00
|
|
|
|
2017-11-27 03:09:47 -08:00
|
|
|
if (!sizeBasedOnContent && !YGFloatIsUndefined(availableInnerMainDim)) {
|
2018-02-05 06:33:01 -08:00
|
|
|
collectedFlexItemsValues.remainingFreeSpace = availableInnerMainDim -
|
2018-02-05 06:32:59 -08:00
|
|
|
collectedFlexItemsValues.sizeConsumedOnCurrentLine;
|
|
|
|
} else if (collectedFlexItemsValues.sizeConsumedOnCurrentLine < 0) {
|
2018-07-19 09:57:04 -07:00
|
|
|
// availableInnerMainDim is indefinite which means the node is being sized
|
|
|
|
// based on its content. sizeConsumedOnCurrentLine is negative which means
|
|
|
|
// the node will allocate 0 points for its content. Consequently,
|
|
|
|
// remainingFreeSpace is 0 - sizeConsumedOnCurrentLine.
|
2018-02-05 06:33:01 -08:00
|
|
|
collectedFlexItemsValues.remainingFreeSpace =
|
|
|
|
-collectedFlexItemsValues.sizeConsumedOnCurrentLine;
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
2016-06-03 22:19:03 +01:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
if (!canSkipFlex) {
|
2018-02-05 06:33:05 -08:00
|
|
|
YGResolveFlexibleLength(
|
2018-02-05 06:33:03 -08:00
|
|
|
node,
|
2018-02-05 06:33:05 -08:00
|
|
|
collectedFlexItemsValues,
|
2018-02-05 06:33:03 -08:00
|
|
|
mainAxis,
|
|
|
|
crossAxis,
|
2018-04-01 18:27:06 -07:00
|
|
|
mainAxisownerSize,
|
2018-02-05 06:33:03 -08:00
|
|
|
availableInnerMainDim,
|
|
|
|
availableInnerCrossDim,
|
|
|
|
availableInnerWidth,
|
|
|
|
availableInnerHeight,
|
|
|
|
flexBasisOverflows,
|
|
|
|
measureModeCrossDim,
|
|
|
|
performLayout,
|
|
|
|
config);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2016-06-03 22:19:03 +01:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutHadOverflow(
|
2018-02-05 06:33:01 -08:00
|
|
|
node->getLayout().hadOverflow |
|
|
|
|
(collectedFlexItemsValues.remainingFreeSpace < 0));
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
|
|
|
|
// STEP 6: MAIN-AXIS JUSTIFICATION & CROSS-AXIS SIZE DETERMINATION
|
|
|
|
|
2016-08-04 08:20:11 -07:00
|
|
|
// At this point, all the children have their dimensions set in the main
|
|
|
|
// axis.
|
|
|
|
// Their dimensions are also set in the cross axis with the exception of
|
|
|
|
// items
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// that are aligned "stretch". We need to compute these stretch values and
|
|
|
|
// set the final positions.
|
2015-08-13 16:56:41 +08:00
|
|
|
|
2018-02-06 08:39:49 -08:00
|
|
|
YGJustifyMainAxis(
|
|
|
|
node,
|
|
|
|
collectedFlexItemsValues,
|
|
|
|
startOfLineIndex,
|
|
|
|
mainAxis,
|
|
|
|
crossAxis,
|
|
|
|
measureModeMainDim,
|
|
|
|
measureModeCrossDim,
|
2018-04-01 18:27:06 -07:00
|
|
|
mainAxisownerSize,
|
|
|
|
ownerWidth,
|
2018-02-06 08:39:49 -08:00
|
|
|
availableInnerMainDim,
|
|
|
|
availableInnerCrossDim,
|
|
|
|
availableInnerWidth,
|
|
|
|
performLayout);
|
2016-06-03 22:19:03 +01:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
float containerCrossAxis = availableInnerCrossDim;
|
2016-12-02 05:47:43 -08:00
|
|
|
if (measureModeCrossDim == YGMeasureModeUndefined ||
|
|
|
|
measureModeCrossDim == YGMeasureModeAtMost) {
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// Compute the cross axis from the max cross dimension of the children.
|
2018-02-06 08:39:49 -08:00
|
|
|
containerCrossAxis =
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
crossAxis,
|
|
|
|
collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross,
|
2018-04-01 18:27:06 -07:00
|
|
|
crossAxisownerSize,
|
|
|
|
ownerWidth) -
|
2018-02-06 08:39:49 -08:00
|
|
|
paddingAndBorderAxisCross;
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// If there's no flex wrap, the cross dimension is defined by the container.
|
2016-12-02 05:47:43 -08:00
|
|
|
if (!isNodeFlexWrap && measureModeCrossDim == YGMeasureModeExactly) {
|
2018-02-06 08:39:49 -08:00
|
|
|
collectedFlexItemsValues.crossDim = availableInnerCrossDim;
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2015-08-13 16:56:41 +08:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// Clamp to the min/max size specified on the container.
|
2018-02-06 08:39:49 -08:00
|
|
|
collectedFlexItemsValues.crossDim =
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
crossAxis,
|
|
|
|
collectedFlexItemsValues.crossDim + paddingAndBorderAxisCross,
|
2018-04-01 18:27:06 -07:00
|
|
|
crossAxisownerSize,
|
|
|
|
ownerWidth) -
|
2018-02-06 08:39:49 -08:00
|
|
|
paddingAndBorderAxisCross;
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
|
|
|
|
// STEP 7: CROSS-AXIS ALIGNMENT
|
|
|
|
// We can skip child alignment if we're just measuring the container.
|
|
|
|
if (performLayout) {
|
2016-08-22 06:58:13 -07:00
|
|
|
for (uint32_t i = startOfLineIndex; i < endOfLineIndex; i++) {
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGNodeRef child = node->getChild(i);
|
|
|
|
if (child->getStyle().display == YGDisplayNone) {
|
2017-02-06 09:31:22 -08:00
|
|
|
continue;
|
|
|
|
}
|
2017-12-19 11:18:00 -08:00
|
|
|
if (child->getStyle().positionType == YGPositionTypeAbsolute) {
|
2016-08-04 08:20:11 -07:00
|
|
|
// If the child is absolutely positioned and has a
|
2018-02-07 17:19:53 -08:00
|
|
|
// top/left/bottom/right set, override
|
|
|
|
// all the previously computed positions to set it correctly.
|
2018-01-11 04:47:38 -08:00
|
|
|
const bool isChildLeadingPosDefined =
|
|
|
|
child->isLeadingPositionDefined(crossAxis);
|
2017-11-01 06:13:23 -07:00
|
|
|
if (isChildLeadingPosDefined) {
|
2017-12-19 11:18:00 -08:00
|
|
|
child->setLayoutPosition(
|
2018-04-04 07:55:42 -07:00
|
|
|
YGUnwrapFloatOptional(child->getLeadingPosition(
|
|
|
|
crossAxis, availableInnerCrossDim)) +
|
2018-01-15 10:09:44 -08:00
|
|
|
node->getLeadingBorder(crossAxis) +
|
2018-04-04 07:55:49 -07:00
|
|
|
YGUnwrapFloatOptional(child->getLeadingMargin(
|
|
|
|
crossAxis, availableInnerWidth)),
|
2017-12-19 11:18:00 -08:00
|
|
|
pos[crossAxis]);
|
2017-11-01 06:13:23 -07:00
|
|
|
}
|
2018-07-19 09:57:04 -07:00
|
|
|
// If leading position is not defined or calculations result in Nan,
|
|
|
|
// default to border + margin
|
2017-12-19 11:18:00 -08:00
|
|
|
if (!isChildLeadingPosDefined ||
|
|
|
|
YGFloatIsUndefined(child->getLayout().position[pos[crossAxis]])) {
|
|
|
|
child->setLayoutPosition(
|
2018-01-15 10:09:44 -08:00
|
|
|
node->getLeadingBorder(crossAxis) +
|
2018-04-04 07:55:49 -07:00
|
|
|
YGUnwrapFloatOptional(child->getLeadingMargin(
|
|
|
|
crossAxis, availableInnerWidth)),
|
2017-12-19 11:18:00 -08:00
|
|
|
pos[crossAxis]);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
float leadingCrossDim = leadingPaddingAndBorderCross;
|
2015-08-13 16:56:41 +08:00
|
|
|
|
2018-04-01 18:27:06 -07:00
|
|
|
// For a relative children, we're either using alignItems (owner) or
|
2016-08-04 08:20:11 -07:00
|
|
|
// alignSelf (child) in order to determine the position in the cross
|
|
|
|
// axis
|
2016-12-03 04:40:18 -08:00
|
|
|
const YGAlign alignItem = YGNodeAlignItem(node, child);
|
2016-06-03 22:19:03 +01:00
|
|
|
|
2016-08-04 08:20:11 -07:00
|
|
|
// If the child uses align stretch, we need to lay it out one more
|
|
|
|
// time, this time
|
|
|
|
// forcing the cross-axis size to be the computed cross size for the
|
|
|
|
// current line.
|
2017-02-14 14:26:09 -08:00
|
|
|
if (alignItem == YGAlignStretch &&
|
2017-12-19 11:18:00 -08:00
|
|
|
child->marginLeadingValue(crossAxis).unit != YGUnitAuto &&
|
|
|
|
child->marginTrailingValue(crossAxis).unit != YGUnitAuto) {
|
2016-08-04 08:20:11 -07:00
|
|
|
// If the child defines a definite size for its cross axis, there's
|
|
|
|
// no need to stretch.
|
2018-07-19 09:57:04 -07:00
|
|
|
if (!YGNodeIsStyleDimDefined(
|
|
|
|
child, crossAxis, availableInnerCrossDim)) {
|
2017-12-19 11:18:00 -08:00
|
|
|
float childMainSize =
|
|
|
|
child->getLayout().measuredDimensions[dim[mainAxis]];
|
2017-02-16 07:39:14 -08:00
|
|
|
float childCrossSize =
|
2018-04-03 14:56:29 -07:00
|
|
|
!child->getStyle().aspectRatio.isUndefined()
|
2018-04-04 07:55:54 -07:00
|
|
|
? ((YGUnwrapFloatOptional(child->getMarginForAxis(
|
|
|
|
crossAxis, availableInnerWidth)) +
|
2018-04-03 14:56:29 -07:00
|
|
|
(isMainAxisRow ? childMainSize /
|
|
|
|
child->getStyle().aspectRatio.getValue()
|
|
|
|
: childMainSize *
|
|
|
|
child->getStyle().aspectRatio.getValue())))
|
2018-02-06 08:39:49 -08:00
|
|
|
: collectedFlexItemsValues.crossDim;
|
2017-02-16 07:39:14 -08:00
|
|
|
|
2018-04-04 07:55:54 -07:00
|
|
|
childMainSize += YGUnwrapFloatOptional(
|
|
|
|
child->getMarginForAxis(mainAxis, availableInnerWidth));
|
2017-02-16 07:39:14 -08:00
|
|
|
|
|
|
|
YGMeasureMode childMainMeasureMode = YGMeasureModeExactly;
|
|
|
|
YGMeasureMode childCrossMeasureMode = YGMeasureModeExactly;
|
2018-07-19 09:57:04 -07:00
|
|
|
YGConstrainMaxSizeForMode(
|
|
|
|
child,
|
|
|
|
mainAxis,
|
|
|
|
availableInnerMainDim,
|
|
|
|
availableInnerWidth,
|
|
|
|
&childMainMeasureMode,
|
|
|
|
&childMainSize);
|
|
|
|
YGConstrainMaxSizeForMode(
|
|
|
|
child,
|
|
|
|
crossAxis,
|
|
|
|
availableInnerCrossDim,
|
|
|
|
availableInnerWidth,
|
|
|
|
&childCrossMeasureMode,
|
|
|
|
&childCrossSize);
|
|
|
|
|
|
|
|
const float childWidth =
|
|
|
|
isMainAxisRow ? childMainSize : childCrossSize;
|
|
|
|
const float childHeight =
|
|
|
|
!isMainAxisRow ? childMainSize : childCrossSize;
|
2017-02-16 07:39:14 -08:00
|
|
|
|
|
|
|
const YGMeasureMode childWidthMeasureMode =
|
2017-12-19 11:18:00 -08:00
|
|
|
YGFloatIsUndefined(childWidth) ? YGMeasureModeUndefined
|
|
|
|
: YGMeasureModeExactly;
|
2017-02-16 07:39:14 -08:00
|
|
|
const YGMeasureMode childHeightMeasureMode =
|
2017-12-19 11:18:00 -08:00
|
|
|
YGFloatIsUndefined(childHeight) ? YGMeasureModeUndefined
|
|
|
|
: YGMeasureModeExactly;
|
|
|
|
|
|
|
|
YGLayoutNodeInternal(
|
|
|
|
child,
|
|
|
|
childWidth,
|
|
|
|
childHeight,
|
|
|
|
direction,
|
|
|
|
childWidthMeasureMode,
|
|
|
|
childHeightMeasureMode,
|
|
|
|
availableInnerWidth,
|
|
|
|
availableInnerHeight,
|
|
|
|
true,
|
|
|
|
"stretch",
|
|
|
|
config);
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
2017-02-14 14:26:09 -08:00
|
|
|
} else {
|
2017-12-19 11:18:00 -08:00
|
|
|
const float remainingCrossDim = containerCrossAxis -
|
|
|
|
YGNodeDimWithMargin(child, crossAxis, availableInnerWidth);
|
2015-08-13 16:56:41 +08:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
if (child->marginLeadingValue(crossAxis).unit == YGUnitAuto &&
|
|
|
|
child->marginTrailingValue(crossAxis).unit == YGUnitAuto) {
|
2018-03-01 04:00:35 -08:00
|
|
|
leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim / 2);
|
2017-12-19 11:18:00 -08:00
|
|
|
} else if (
|
|
|
|
child->marginTrailingValue(crossAxis).unit == YGUnitAuto) {
|
2017-02-14 14:26:09 -08:00
|
|
|
// No-Op
|
2017-12-19 11:18:00 -08:00
|
|
|
} else if (
|
|
|
|
child->marginLeadingValue(crossAxis).unit == YGUnitAuto) {
|
2018-03-01 04:00:35 -08:00
|
|
|
leadingCrossDim += YGFloatMax(0.0f, remainingCrossDim);
|
2017-02-14 14:26:09 -08:00
|
|
|
} else if (alignItem == YGAlignFlexStart) {
|
|
|
|
// No-Op
|
|
|
|
} else if (alignItem == YGAlignCenter) {
|
|
|
|
leadingCrossDim += remainingCrossDim / 2;
|
|
|
|
} else {
|
2015-08-13 16:56:41 +08:00
|
|
|
leadingCrossDim += remainingCrossDim;
|
|
|
|
}
|
|
|
|
}
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// And we apply the position
|
2017-12-19 11:18:00 -08:00
|
|
|
child->setLayoutPosition(
|
|
|
|
child->getLayout().position[pos[crossAxis]] + totalLineCrossDim +
|
|
|
|
leadingCrossDim,
|
|
|
|
pos[crossAxis]);
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-06 08:39:49 -08:00
|
|
|
totalLineCrossDim += collectedFlexItemsValues.crossDim;
|
2018-03-01 04:00:35 -08:00
|
|
|
maxLineMainDim =
|
|
|
|
YGFloatMax(maxLineMainDim, collectedFlexItemsValues.mainDim);
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// STEP 8: MULTI-LINE CONTENT ALIGNMENT
|
2017-02-23 08:25:16 -08:00
|
|
|
if (performLayout && (lineCount > 1 || YGIsBaselineLayout(node)) &&
|
2017-01-06 06:51:56 -08:00
|
|
|
!YGFloatIsUndefined(availableInnerCrossDim)) {
|
2018-07-19 09:57:04 -07:00
|
|
|
const float remainingAlignContentDim =
|
|
|
|
availableInnerCrossDim - totalLineCrossDim;
|
2015-08-13 16:56:41 +08:00
|
|
|
|
|
|
|
float crossDimLead = 0;
|
2015-09-24 11:56:18 -07:00
|
|
|
float currentLead = leadingPaddingAndBorderCross;
|
2015-08-13 16:56:41 +08:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
switch (node->getStyle().alignContent) {
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGAlignFlexEnd:
|
2016-10-18 10:01:16 -07:00
|
|
|
currentLead += remainingAlignContentDim;
|
|
|
|
break;
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGAlignCenter:
|
2016-10-18 10:01:16 -07:00
|
|
|
currentLead += remainingAlignContentDim / 2;
|
|
|
|
break;
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGAlignStretch:
|
2016-10-18 10:01:16 -07:00
|
|
|
if (availableInnerCrossDim > totalLineCrossDim) {
|
2017-02-11 08:32:48 -08:00
|
|
|
crossDimLead = remainingAlignContentDim / lineCount;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case YGAlignSpaceAround:
|
|
|
|
if (availableInnerCrossDim > totalLineCrossDim) {
|
|
|
|
currentLead += remainingAlignContentDim / (2 * lineCount);
|
|
|
|
if (lineCount > 1) {
|
|
|
|
crossDimLead = remainingAlignContentDim / lineCount;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
currentLead += remainingAlignContentDim / 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case YGAlignSpaceBetween:
|
|
|
|
if (availableInnerCrossDim > totalLineCrossDim && lineCount > 1) {
|
|
|
|
crossDimLead = remainingAlignContentDim / (lineCount - 1);
|
2016-10-18 10:01:16 -07:00
|
|
|
}
|
|
|
|
break;
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGAlignAuto:
|
|
|
|
case YGAlignFlexStart:
|
2017-01-06 06:51:56 -08:00
|
|
|
case YGAlignBaseline:
|
2016-10-18 10:01:16 -07:00
|
|
|
break;
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2016-08-02 08:06:55 -07:00
|
|
|
uint32_t endIndex = 0;
|
2016-08-22 06:58:13 -07:00
|
|
|
for (uint32_t i = 0; i < lineCount; i++) {
|
2017-02-16 07:39:14 -08:00
|
|
|
const uint32_t startIndex = endIndex;
|
2016-08-22 06:58:13 -07:00
|
|
|
uint32_t ii;
|
2015-08-13 16:56:41 +08:00
|
|
|
|
|
|
|
// compute the line's height and find the endIndex
|
|
|
|
float lineHeight = 0;
|
2017-01-06 06:51:56 -08:00
|
|
|
float maxAscentForCurrentLine = 0;
|
|
|
|
float maxDescentForCurrentLine = 0;
|
2016-08-22 06:58:13 -07:00
|
|
|
for (ii = startIndex; ii < childCount; ii++) {
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGNodeRef child = node->getChild(ii);
|
|
|
|
if (child->getStyle().display == YGDisplayNone) {
|
2017-02-06 09:31:22 -08:00
|
|
|
continue;
|
|
|
|
}
|
2017-12-19 11:18:00 -08:00
|
|
|
if (child->getStyle().positionType == YGPositionTypeRelative) {
|
|
|
|
if (child->getLineIndex() != i) {
|
2016-09-20 10:16:16 -07:00
|
|
|
break;
|
|
|
|
}
|
2016-12-03 04:40:18 -08:00
|
|
|
if (YGNodeIsLayoutDimDefined(child, crossAxis)) {
|
2018-03-01 04:00:35 -08:00
|
|
|
lineHeight = YGFloatMax(
|
2017-12-19 11:18:00 -08:00
|
|
|
lineHeight,
|
|
|
|
child->getLayout().measuredDimensions[dim[crossAxis]] +
|
2018-04-04 07:55:54 -07:00
|
|
|
YGUnwrapFloatOptional(child->getMarginForAxis(
|
|
|
|
crossAxis, availableInnerWidth)));
|
2016-09-20 10:16:16 -07:00
|
|
|
}
|
2017-01-06 06:51:56 -08:00
|
|
|
if (YGNodeAlignItem(node, child) == YGAlignBaseline) {
|
2018-01-11 04:47:45 -08:00
|
|
|
const float ascent = YGBaseline(child) +
|
2018-04-04 07:55:49 -07:00
|
|
|
YGUnwrapFloatOptional(child->getLeadingMargin(
|
|
|
|
YGFlexDirectionColumn, availableInnerWidth));
|
2017-01-06 06:51:56 -08:00
|
|
|
const float descent =
|
2017-12-19 11:18:00 -08:00
|
|
|
child->getLayout().measuredDimensions[YGDimensionHeight] +
|
2018-04-04 07:55:54 -07:00
|
|
|
YGUnwrapFloatOptional(child->getMarginForAxis(
|
|
|
|
YGFlexDirectionColumn, availableInnerWidth)) -
|
2017-12-19 11:18:00 -08:00
|
|
|
ascent;
|
2018-03-01 04:00:35 -08:00
|
|
|
maxAscentForCurrentLine =
|
|
|
|
YGFloatMax(maxAscentForCurrentLine, ascent);
|
|
|
|
maxDescentForCurrentLine =
|
|
|
|
YGFloatMax(maxDescentForCurrentLine, descent);
|
|
|
|
lineHeight = YGFloatMax(
|
|
|
|
lineHeight, maxAscentForCurrentLine + maxDescentForCurrentLine);
|
2017-01-06 06:51:56 -08:00
|
|
|
}
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
2016-08-22 06:58:13 -07:00
|
|
|
endIndex = ii;
|
2015-08-13 16:56:41 +08:00
|
|
|
lineHeight += crossDimLead;
|
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
if (performLayout) {
|
2016-08-22 06:58:13 -07:00
|
|
|
for (ii = startIndex; ii < endIndex; ii++) {
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGNodeRef child = node->getChild(ii);
|
|
|
|
if (child->getStyle().display == YGDisplayNone) {
|
2017-02-06 09:31:22 -08:00
|
|
|
continue;
|
|
|
|
}
|
2017-12-19 11:18:00 -08:00
|
|
|
if (child->getStyle().positionType == YGPositionTypeRelative) {
|
2016-12-03 04:40:18 -08:00
|
|
|
switch (YGNodeAlignItem(node, child)) {
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGAlignFlexStart: {
|
2017-12-19 11:18:00 -08:00
|
|
|
child->setLayoutPosition(
|
|
|
|
currentLead +
|
2018-04-04 07:55:49 -07:00
|
|
|
YGUnwrapFloatOptional(child->getLeadingMargin(
|
|
|
|
crossAxis, availableInnerWidth)),
|
2017-12-19 11:18:00 -08:00
|
|
|
pos[crossAxis]);
|
2016-09-20 10:16:16 -07:00
|
|
|
break;
|
2016-10-17 05:28:50 -07:00
|
|
|
}
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGAlignFlexEnd: {
|
2017-12-19 11:18:00 -08:00
|
|
|
child->setLayoutPosition(
|
Add feature to use percentage as value unit
Summary:
Adds the feature to use percentage as a value unit.
You can use the function ```YGPx(float)``` and ```YGPercent(float)``` for convenience.
I did some benchmarks:
```
Without Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.146683 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.490101 ms
Huge nested layout: median: 23.000000 ms, stddev: 0.928291 ms
Stack with flex: median: 0.000000 ms, stddev: 0.170587 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.143384 ms
Nested flex: median: 0.000000 ms, stddev: 0.477791 ms
Huge nested layout: median: 22.000000 ms, stddev: 2.129779 ms
With Percentage Feature - Release x86:
Stack with flex: median: 0.000000 ms, stddev: 0.132951 ms
Align stretch in undefined axis: median: 0.000000 ms, stddev: 0.136525 ms
Nested flex: median: 0.000000 ms, stddev: 0.489570 ms
Huge nested layout: median: 21.000000 ms, stddev: 1.390476 ms
Closes https://github.com/facebook/yoga/pull/258
Reviewed By: dshahidehpour
Differential Revision: D4361945
Pulled By: emilsjolander
fbshipit-source-id: a8f5bc63ad352eb9410d792729e56664468cd76a
2017-01-02 05:20:37 -08:00
|
|
|
currentLead + lineHeight -
|
2018-04-04 07:55:51 -07:00
|
|
|
YGUnwrapFloatOptional(child->getTrailingMargin(
|
|
|
|
crossAxis, availableInnerWidth)) -
|
2017-12-19 11:18:00 -08:00
|
|
|
child->getLayout().measuredDimensions[dim[crossAxis]],
|
|
|
|
pos[crossAxis]);
|
2016-09-20 10:16:16 -07:00
|
|
|
break;
|
2016-10-17 05:28:50 -07:00
|
|
|
}
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGAlignCenter: {
|
2017-12-19 11:18:00 -08:00
|
|
|
float childHeight =
|
|
|
|
child->getLayout().measuredDimensions[dim[crossAxis]];
|
|
|
|
|
|
|
|
child->setLayoutPosition(
|
|
|
|
currentLead + (lineHeight - childHeight) / 2,
|
|
|
|
pos[crossAxis]);
|
2016-09-20 10:16:16 -07:00
|
|
|
break;
|
2016-10-17 05:28:50 -07:00
|
|
|
}
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGAlignStretch: {
|
2017-12-19 11:18:00 -08:00
|
|
|
child->setLayoutPosition(
|
|
|
|
currentLead +
|
2018-04-04 07:55:49 -07:00
|
|
|
YGUnwrapFloatOptional(child->getLeadingMargin(
|
|
|
|
crossAxis, availableInnerWidth)),
|
2017-12-19 11:18:00 -08:00
|
|
|
pos[crossAxis]);
|
2017-02-14 09:16:59 -08:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
// Remeasure child with the line height as it as been only
|
|
|
|
// measured with the owners height yet.
|
|
|
|
if (!YGNodeIsStyleDimDefined(
|
|
|
|
child, crossAxis, availableInnerCrossDim)) {
|
2017-12-19 11:18:00 -08:00
|
|
|
const float childWidth = isMainAxisRow
|
|
|
|
? (child->getLayout()
|
|
|
|
.measuredDimensions[YGDimensionWidth] +
|
2018-04-04 07:55:54 -07:00
|
|
|
YGUnwrapFloatOptional(child->getMarginForAxis(
|
|
|
|
mainAxis, availableInnerWidth)))
|
2017-12-19 11:18:00 -08:00
|
|
|
: lineHeight;
|
|
|
|
|
|
|
|
const float childHeight = !isMainAxisRow
|
|
|
|
? (child->getLayout()
|
|
|
|
.measuredDimensions[YGDimensionHeight] +
|
2018-04-04 07:55:54 -07:00
|
|
|
YGUnwrapFloatOptional(child->getMarginForAxis(
|
|
|
|
crossAxis, availableInnerWidth)))
|
2017-12-19 11:18:00 -08:00
|
|
|
: lineHeight;
|
|
|
|
|
|
|
|
if (!(YGFloatsEqual(
|
|
|
|
childWidth,
|
|
|
|
child->getLayout()
|
|
|
|
.measuredDimensions[YGDimensionWidth]) &&
|
|
|
|
YGFloatsEqual(
|
|
|
|
childHeight,
|
|
|
|
child->getLayout()
|
|
|
|
.measuredDimensions[YGDimensionHeight]))) {
|
2018-07-19 09:57:04 -07:00
|
|
|
YGLayoutNodeInternal(
|
|
|
|
child,
|
|
|
|
childWidth,
|
|
|
|
childHeight,
|
|
|
|
direction,
|
|
|
|
YGMeasureModeExactly,
|
|
|
|
YGMeasureModeExactly,
|
|
|
|
availableInnerWidth,
|
|
|
|
availableInnerHeight,
|
|
|
|
true,
|
|
|
|
"multiline-stretch",
|
|
|
|
config);
|
2017-02-14 09:16:59 -08:00
|
|
|
}
|
|
|
|
}
|
2016-09-20 10:16:16 -07:00
|
|
|
break;
|
2016-10-17 05:28:50 -07:00
|
|
|
}
|
2017-01-06 06:51:56 -08:00
|
|
|
case YGAlignBaseline: {
|
2017-12-19 11:18:00 -08:00
|
|
|
child->setLayoutPosition(
|
2017-01-06 06:51:56 -08:00
|
|
|
currentLead + maxAscentForCurrentLine - YGBaseline(child) +
|
2018-04-04 07:55:42 -07:00
|
|
|
YGUnwrapFloatOptional(child->getLeadingPosition(
|
|
|
|
YGFlexDirectionColumn, availableInnerCrossDim)),
|
2017-12-19 11:18:00 -08:00
|
|
|
YGEdgeTop);
|
|
|
|
|
2017-01-06 06:51:56 -08:00
|
|
|
break;
|
|
|
|
}
|
2016-12-02 05:47:43 -08:00
|
|
|
case YGAlignAuto:
|
2017-02-11 08:32:48 -08:00
|
|
|
case YGAlignSpaceBetween:
|
|
|
|
case YGAlignSpaceAround:
|
2016-09-20 10:16:16 -07:00
|
|
|
break;
|
|
|
|
}
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
currentLead += lineHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// STEP 9: COMPUTING FINAL DIMENSIONS
|
2017-12-19 11:18:00 -08:00
|
|
|
|
|
|
|
node->setLayoutMeasuredDimension(
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
YGFlexDirectionRow,
|
|
|
|
availableWidth - marginAxisRow,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerWidth,
|
|
|
|
ownerWidth),
|
2017-12-19 11:18:00 -08:00
|
|
|
YGDimensionWidth);
|
|
|
|
|
|
|
|
node->setLayoutMeasuredDimension(
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
YGFlexDirectionColumn,
|
|
|
|
availableHeight - marginAxisColumn,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerHeight,
|
|
|
|
ownerWidth),
|
2017-12-19 11:18:00 -08:00
|
|
|
YGDimensionHeight);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
|
|
|
|
// If the user didn't specify a width or height for the node, set the
|
|
|
|
// dimensions based on the children.
|
2017-01-16 11:08:46 -08:00
|
|
|
if (measureModeMainDim == YGMeasureModeUndefined ||
|
2017-12-19 11:18:00 -08:00
|
|
|
(node->getStyle().overflow != YGOverflowScroll &&
|
|
|
|
measureModeMainDim == YGMeasureModeAtMost)) {
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// Clamp the size to the min/max size, if specified, and make sure it
|
|
|
|
// doesn't go below the padding and border amount.
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutMeasuredDimension(
|
|
|
|
YGNodeBoundAxis(
|
2018-04-01 18:27:06 -07:00
|
|
|
node, mainAxis, maxLineMainDim, mainAxisownerSize, ownerWidth),
|
2017-12-19 11:18:00 -08:00
|
|
|
dim[mainAxis]);
|
|
|
|
|
|
|
|
} else if (
|
|
|
|
measureModeMainDim == YGMeasureModeAtMost &&
|
|
|
|
node->getStyle().overflow == YGOverflowScroll) {
|
|
|
|
node->setLayoutMeasuredDimension(
|
2018-03-01 04:00:35 -08:00
|
|
|
YGFloatMax(
|
|
|
|
YGFloatMin(
|
2017-12-19 11:18:00 -08:00
|
|
|
availableInnerMainDim + paddingAndBorderAxisMain,
|
2018-04-04 07:55:28 -07:00
|
|
|
YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
|
|
|
|
node, mainAxis, maxLineMainDim, mainAxisownerSize))),
|
2017-12-19 11:18:00 -08:00
|
|
|
paddingAndBorderAxisMain),
|
|
|
|
dim[mainAxis]);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2015-08-13 16:56:41 +08:00
|
|
|
|
2017-01-16 11:08:46 -08:00
|
|
|
if (measureModeCrossDim == YGMeasureModeUndefined ||
|
2017-12-19 11:18:00 -08:00
|
|
|
(node->getStyle().overflow != YGOverflowScroll &&
|
|
|
|
measureModeCrossDim == YGMeasureModeAtMost)) {
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// Clamp the size to the min/max size, if specified, and make sure it
|
|
|
|
// doesn't go below the padding and border amount.
|
2017-12-19 11:18:00 -08:00
|
|
|
|
|
|
|
node->setLayoutMeasuredDimension(
|
|
|
|
YGNodeBoundAxis(
|
|
|
|
node,
|
|
|
|
crossAxis,
|
|
|
|
totalLineCrossDim + paddingAndBorderAxisCross,
|
2018-04-01 18:27:06 -07:00
|
|
|
crossAxisownerSize,
|
|
|
|
ownerWidth),
|
2017-12-19 11:18:00 -08:00
|
|
|
dim[crossAxis]);
|
|
|
|
|
|
|
|
} else if (
|
|
|
|
measureModeCrossDim == YGMeasureModeAtMost &&
|
|
|
|
node->getStyle().overflow == YGOverflowScroll) {
|
|
|
|
node->setLayoutMeasuredDimension(
|
2018-03-01 04:00:35 -08:00
|
|
|
YGFloatMax(
|
|
|
|
YGFloatMin(
|
2017-12-19 11:18:00 -08:00
|
|
|
availableInnerCrossDim + paddingAndBorderAxisCross,
|
2018-04-04 07:55:28 -07:00
|
|
|
YGUnwrapFloatOptional(YGNodeBoundAxisWithinMinAndMax(
|
2017-12-19 11:18:00 -08:00
|
|
|
node,
|
|
|
|
crossAxis,
|
|
|
|
totalLineCrossDim + paddingAndBorderAxisCross,
|
2018-04-04 07:55:28 -07:00
|
|
|
crossAxisownerSize))),
|
2017-12-19 11:18:00 -08:00
|
|
|
paddingAndBorderAxisCross),
|
|
|
|
dim[crossAxis]);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2016-06-03 22:19:03 +01:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
// As we only wrapped in normal direction yet, we need to reverse the
|
|
|
|
// positions on wrap-reverse.
|
2017-12-19 11:18:00 -08:00
|
|
|
if (performLayout && node->getStyle().flexWrap == YGWrapWrapReverse) {
|
2017-02-15 13:35:24 -08:00
|
|
|
for (uint32_t i = 0; i < childCount; i++) {
|
|
|
|
const YGNodeRef child = YGNodeGetChild(node, i);
|
2017-12-19 11:18:00 -08:00
|
|
|
if (child->getStyle().positionType == YGPositionTypeRelative) {
|
|
|
|
child->setLayoutPosition(
|
|
|
|
node->getLayout().measuredDimensions[dim[crossAxis]] -
|
|
|
|
child->getLayout().position[pos[crossAxis]] -
|
|
|
|
child->getLayout().measuredDimensions[dim[crossAxis]],
|
|
|
|
pos[crossAxis]);
|
2017-02-15 13:35:24 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-17 12:12:34 -07:00
|
|
|
if (performLayout) {
|
|
|
|
// STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN
|
2018-01-16 09:31:21 -08:00
|
|
|
for (auto child : node->getChildren()) {
|
|
|
|
if (child->getStyle().positionType != YGPositionTypeAbsolute) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
YGNodeAbsoluteLayoutChild(
|
|
|
|
node,
|
|
|
|
child,
|
|
|
|
availableInnerWidth,
|
|
|
|
isMainAxisRow ? measureModeMainDim : measureModeCrossDim,
|
|
|
|
availableInnerHeight,
|
|
|
|
direction,
|
|
|
|
config);
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
2015-09-24 11:56:18 -07:00
|
|
|
|
2016-10-17 12:12:34 -07:00
|
|
|
// STEP 11: SETTING TRAILING POSITIONS FOR CHILDREN
|
2018-07-19 09:57:04 -07:00
|
|
|
const bool needsMainTrailingPos = mainAxis == YGFlexDirectionRowReverse ||
|
|
|
|
mainAxis == YGFlexDirectionColumnReverse;
|
|
|
|
const bool needsCrossTrailingPos = crossAxis == YGFlexDirectionRowReverse ||
|
|
|
|
crossAxis == YGFlexDirectionColumnReverse;
|
2016-07-28 14:43:40 -07:00
|
|
|
|
|
|
|
// Set trailing position if necessary.
|
|
|
|
if (needsMainTrailingPos || needsCrossTrailingPos) {
|
2016-08-22 06:58:13 -07:00
|
|
|
for (uint32_t i = 0; i < childCount; i++) {
|
2017-12-19 11:18:00 -08:00
|
|
|
const YGNodeRef child = node->getChild(i);
|
|
|
|
if (child->getStyle().display == YGDisplayNone) {
|
2017-02-06 09:31:22 -08:00
|
|
|
continue;
|
|
|
|
}
|
2016-07-28 14:43:40 -07:00
|
|
|
if (needsMainTrailingPos) {
|
2016-12-03 04:40:18 -08:00
|
|
|
YGNodeSetChildTrailingPosition(node, child, mainAxis);
|
2016-07-28 14:43:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (needsCrossTrailingPos) {
|
2016-12-03 04:40:18 -08:00
|
|
|
YGNodeSetChildTrailingPosition(node, child, crossAxis);
|
2016-07-28 14:43:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2016-08-02 08:06:55 -07:00
|
|
|
uint32_t gDepth = 0;
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
bool gPrintTree = false;
|
|
|
|
bool gPrintChanges = false;
|
|
|
|
bool gPrintSkips = false;
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static const char* spacer =
|
|
|
|
" ";
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static const char* YGSpacer(const unsigned long level) {
|
2016-11-17 20:41:44 -08:00
|
|
|
const size_t spacerLen = strlen(spacer);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
if (level > spacerLen) {
|
2016-08-22 06:58:13 -07:00
|
|
|
return &spacer[0];
|
|
|
|
} else {
|
|
|
|
return &spacer[spacerLen - level];
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static const char* YGMeasureModeName(
|
|
|
|
const YGMeasureMode mode,
|
|
|
|
const bool performLayout) {
|
|
|
|
const char* kMeasureModeNames[YGMeasureModeCount] = {
|
|
|
|
"UNDEFINED", "EXACTLY", "AT_MOST"};
|
|
|
|
const char* kLayoutModeNames[YGMeasureModeCount] = {"LAY_UNDEFINED",
|
2016-12-02 05:47:43 -08:00
|
|
|
"LAY_EXACTLY",
|
|
|
|
"LAY_AT_"
|
|
|
|
"MOST"};
|
2016-06-03 22:19:03 +01:00
|
|
|
|
2016-12-02 05:47:43 -08:00
|
|
|
if (mode >= YGMeasureModeCount) {
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
return "";
|
|
|
|
}
|
2016-06-03 22:19:03 +01:00
|
|
|
|
2016-08-04 08:20:11 -07:00
|
|
|
return performLayout ? kLayoutModeNames[mode] : kMeasureModeNames[mode];
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static inline bool YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(
|
|
|
|
YGMeasureMode sizeMode,
|
|
|
|
float size,
|
|
|
|
float lastComputedSize) {
|
|
|
|
return sizeMode == YGMeasureModeExactly &&
|
|
|
|
YGFloatsEqual(size, lastComputedSize);
|
2016-10-25 07:33:58 -07:00
|
|
|
}
|
2016-06-03 15:38:08 +01:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static inline bool YGMeasureModeOldSizeIsUnspecifiedAndStillFits(
|
|
|
|
YGMeasureMode sizeMode,
|
|
|
|
float size,
|
|
|
|
YGMeasureMode lastSizeMode,
|
|
|
|
float lastComputedSize) {
|
|
|
|
return sizeMode == YGMeasureModeAtMost &&
|
|
|
|
lastSizeMode == YGMeasureModeUndefined &&
|
|
|
|
(size >= lastComputedSize || YGFloatsEqual(size, lastComputedSize));
|
2016-10-25 07:33:58 -07:00
|
|
|
}
|
2016-06-03 15:38:08 +01:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
|
|
|
|
YGMeasureMode sizeMode,
|
|
|
|
float size,
|
|
|
|
YGMeasureMode lastSizeMode,
|
|
|
|
float lastSize,
|
|
|
|
float lastComputedSize) {
|
2018-03-01 04:00:35 -08:00
|
|
|
return lastSizeMode == YGMeasureModeAtMost &&
|
|
|
|
sizeMode == YGMeasureModeAtMost && !YGFloatIsUndefined(lastSize) &&
|
|
|
|
!YGFloatIsUndefined(size) && !YGFloatIsUndefined(lastComputedSize) &&
|
|
|
|
lastSize > size &&
|
|
|
|
(lastComputedSize <= size || YGFloatsEqual(size, lastComputedSize));
|
2016-10-25 07:33:58 -07:00
|
|
|
}
|
2016-06-03 15:38:08 +01:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
float YGRoundValueToPixelGrid(
|
|
|
|
const float value,
|
|
|
|
const float pointScaleFactor,
|
|
|
|
const bool forceCeil,
|
|
|
|
const bool forceFloor) {
|
2017-05-26 10:56:33 -07:00
|
|
|
float scaledValue = value * pointScaleFactor;
|
2018-04-04 06:42:36 -07:00
|
|
|
float fractial = fmodf(scaledValue, 1.0f);
|
2017-05-15 06:18:24 -07:00
|
|
|
if (YGFloatsEqual(fractial, 0)) {
|
2017-07-26 19:22:03 -07:00
|
|
|
// First we check if the value is already rounded
|
2017-05-26 10:56:33 -07:00
|
|
|
scaledValue = scaledValue - fractial;
|
2018-04-04 06:42:36 -07:00
|
|
|
} else if (YGFloatsEqual(fractial, 1.0f)) {
|
|
|
|
scaledValue = scaledValue - fractial + 1.0f;
|
2017-05-26 10:56:33 -07:00
|
|
|
} else if (forceCeil) {
|
2017-07-26 19:22:03 -07:00
|
|
|
// Next we check if we need to use forced rounding
|
2017-08-23 02:40:04 -07:00
|
|
|
scaledValue = scaledValue - fractial + 1.0f;
|
2017-05-15 06:18:24 -07:00
|
|
|
} else if (forceFloor) {
|
2017-05-26 10:56:33 -07:00
|
|
|
scaledValue = scaledValue - fractial;
|
2017-05-15 06:18:24 -07:00
|
|
|
} else {
|
2017-07-26 19:22:03 -07:00
|
|
|
// Finally we just round the value
|
2017-11-21 10:10:30 -08:00
|
|
|
scaledValue = scaledValue - fractial +
|
2018-03-01 04:00:35 -08:00
|
|
|
(!YGFloatIsUndefined(fractial) &&
|
|
|
|
(fractial > 0.5f || YGFloatsEqual(fractial, 0.5f))
|
|
|
|
? 1.0f
|
|
|
|
: 0.0f);
|
2017-05-15 06:18:24 -07:00
|
|
|
}
|
2018-03-01 04:00:35 -08:00
|
|
|
return (YGFloatIsUndefined(scaledValue) ||
|
|
|
|
YGFloatIsUndefined(pointScaleFactor))
|
|
|
|
? YGUndefined
|
|
|
|
: scaledValue / pointScaleFactor;
|
2017-05-15 06:18:24 -07:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
bool YGNodeCanUseCachedMeasurement(
|
|
|
|
const YGMeasureMode widthMode,
|
|
|
|
const float width,
|
|
|
|
const YGMeasureMode heightMode,
|
|
|
|
const float height,
|
|
|
|
const YGMeasureMode lastWidthMode,
|
|
|
|
const float lastWidth,
|
|
|
|
const YGMeasureMode lastHeightMode,
|
|
|
|
const float lastHeight,
|
|
|
|
const float lastComputedWidth,
|
|
|
|
const float lastComputedHeight,
|
|
|
|
const float marginRow,
|
|
|
|
const float marginColumn,
|
|
|
|
const YGConfigRef config) {
|
2018-03-01 04:00:35 -08:00
|
|
|
if ((!YGFloatIsUndefined(lastComputedHeight) && lastComputedHeight < 0) ||
|
|
|
|
(!YGFloatIsUndefined(lastComputedWidth) && lastComputedWidth < 0)) {
|
2016-10-25 07:33:58 -07:00
|
|
|
return false;
|
|
|
|
}
|
2017-11-21 10:10:30 -08:00
|
|
|
bool useRoundedComparison =
|
|
|
|
config != nullptr && config->pointScaleFactor != 0;
|
2018-07-19 09:57:04 -07:00
|
|
|
const float effectiveWidth = useRoundedComparison
|
|
|
|
? YGRoundValueToPixelGrid(width, config->pointScaleFactor, false, false)
|
|
|
|
: width;
|
|
|
|
const float effectiveHeight = useRoundedComparison
|
|
|
|
? YGRoundValueToPixelGrid(height, config->pointScaleFactor, false, false)
|
|
|
|
: height;
|
|
|
|
const float effectiveLastWidth = useRoundedComparison
|
|
|
|
? YGRoundValueToPixelGrid(
|
|
|
|
lastWidth, config->pointScaleFactor, false, false)
|
|
|
|
: lastWidth;
|
|
|
|
const float effectiveLastHeight = useRoundedComparison
|
|
|
|
? YGRoundValueToPixelGrid(
|
|
|
|
lastHeight, config->pointScaleFactor, false, false)
|
|
|
|
: lastHeight;
|
|
|
|
|
|
|
|
const bool hasSameWidthSpec = lastWidthMode == widthMode &&
|
|
|
|
YGFloatsEqual(effectiveLastWidth, effectiveWidth);
|
|
|
|
const bool hasSameHeightSpec = lastHeightMode == heightMode &&
|
|
|
|
YGFloatsEqual(effectiveLastHeight, effectiveHeight);
|
2016-10-25 07:33:58 -07:00
|
|
|
|
|
|
|
const bool widthIsCompatible =
|
2018-07-19 09:57:04 -07:00
|
|
|
hasSameWidthSpec ||
|
|
|
|
YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(
|
|
|
|
widthMode, width - marginRow, lastComputedWidth) ||
|
|
|
|
YGMeasureModeOldSizeIsUnspecifiedAndStillFits(
|
|
|
|
widthMode, width - marginRow, lastWidthMode, lastComputedWidth) ||
|
2016-12-03 04:40:18 -08:00
|
|
|
YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
|
2018-07-19 09:57:04 -07:00
|
|
|
widthMode,
|
|
|
|
width - marginRow,
|
|
|
|
lastWidthMode,
|
|
|
|
lastWidth,
|
|
|
|
lastComputedWidth);
|
2016-10-25 07:33:58 -07:00
|
|
|
|
2016-11-09 11:23:21 -08:00
|
|
|
const bool heightIsCompatible =
|
2018-07-19 09:57:04 -07:00
|
|
|
hasSameHeightSpec ||
|
|
|
|
YGMeasureModeSizeIsExactAndMatchesOldMeasuredSize(
|
|
|
|
heightMode, height - marginColumn, lastComputedHeight) ||
|
|
|
|
YGMeasureModeOldSizeIsUnspecifiedAndStillFits(
|
|
|
|
heightMode,
|
|
|
|
height - marginColumn,
|
|
|
|
lastHeightMode,
|
|
|
|
lastComputedHeight) ||
|
2016-12-03 04:40:18 -08:00
|
|
|
YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
|
2018-07-19 09:57:04 -07:00
|
|
|
heightMode,
|
|
|
|
height - marginColumn,
|
|
|
|
lastHeightMode,
|
|
|
|
lastHeight,
|
|
|
|
lastComputedHeight);
|
2016-10-25 07:33:58 -07:00
|
|
|
|
|
|
|
return widthIsCompatible && heightIsCompatible;
|
2016-05-10 13:56:08 -07:00
|
|
|
}
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
|
|
|
|
//
|
2016-12-03 04:40:18 -08:00
|
|
|
// This is a wrapper around the YGNodelayoutImpl function. It determines
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// whether the layout request is redundant and can be skipped.
|
|
|
|
//
|
|
|
|
// Parameters:
|
2016-12-03 04:40:18 -08:00
|
|
|
// Input parameters are the same as YGNodelayoutImpl (see above)
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// Return parameter is true if layout was performed, false if skipped
|
|
|
|
//
|
2018-07-19 09:57:04 -07:00
|
|
|
bool YGLayoutNodeInternal(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const float availableWidth,
|
|
|
|
const float availableHeight,
|
|
|
|
const YGDirection ownerDirection,
|
|
|
|
const YGMeasureMode widthMeasureMode,
|
|
|
|
const YGMeasureMode heightMeasureMode,
|
|
|
|
const float ownerWidth,
|
|
|
|
const float ownerHeight,
|
|
|
|
const bool performLayout,
|
|
|
|
const char* reason,
|
|
|
|
const YGConfigRef config) {
|
2017-12-22 06:43:32 -08:00
|
|
|
YGLayout* layout = &node->getLayout();
|
2017-10-31 23:08:19 -07:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
gDepth++;
|
|
|
|
|
2016-08-22 06:58:13 -07:00
|
|
|
const bool needToVisitNode =
|
2017-12-19 11:18:00 -08:00
|
|
|
(node->isDirty() && layout->generationCount != gCurrentGenerationCount) ||
|
2018-04-01 18:27:06 -07:00
|
|
|
layout->lastOwnerDirection != ownerDirection;
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
|
|
|
|
if (needToVisitNode) {
|
|
|
|
// Invalidate the cached results.
|
2016-07-25 06:31:32 -07:00
|
|
|
layout->nextCachedMeasurementsIndex = 0;
|
2018-07-19 09:57:04 -07:00
|
|
|
layout->cachedLayout.widthMeasureMode = (YGMeasureMode)-1;
|
|
|
|
layout->cachedLayout.heightMeasureMode = (YGMeasureMode)-1;
|
2016-10-25 07:33:58 -07:00
|
|
|
layout->cachedLayout.computedWidth = -1;
|
|
|
|
layout->cachedLayout.computedHeight = -1;
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
|
|
|
|
2017-11-21 10:10:30 -08:00
|
|
|
YGCachedMeasurement* cachedResults = nullptr;
|
2017-04-28 03:57:13 -07:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// Determine whether the results are already cached. We maintain a separate
|
2016-08-04 08:20:11 -07:00
|
|
|
// cache for layouts and measurements. A layout operation modifies the
|
2017-04-28 03:57:13 -07:00
|
|
|
// positions
|
|
|
|
// and dimensions for nodes in the subtree. The algorithm assumes that each
|
|
|
|
// node
|
|
|
|
// gets layed out a maximum of one time per tree layout, but multiple
|
|
|
|
// measurements
|
|
|
|
// may be required to resolve all of the flex dimensions.
|
|
|
|
// We handle nodes with measure functions specially here because they are the
|
|
|
|
// most
|
|
|
|
// expensive to measure, so it's worth avoiding redundant measurements if at
|
|
|
|
// all possible.
|
2017-12-19 11:18:00 -08:00
|
|
|
if (node->getMeasure() != nullptr) {
|
2018-04-04 07:55:54 -07:00
|
|
|
const float marginAxisRow = YGUnwrapFloatOptional(
|
|
|
|
node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
|
|
|
|
const float marginAxisColumn = YGUnwrapFloatOptional(
|
|
|
|
node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
|
2017-04-27 13:02:55 -07:00
|
|
|
|
2017-04-28 03:57:13 -07:00
|
|
|
// First, try to use the layout cache.
|
2018-07-19 09:57:04 -07:00
|
|
|
if (YGNodeCanUseCachedMeasurement(
|
|
|
|
widthMeasureMode,
|
|
|
|
availableWidth,
|
|
|
|
heightMeasureMode,
|
|
|
|
availableHeight,
|
|
|
|
layout->cachedLayout.widthMeasureMode,
|
|
|
|
layout->cachedLayout.availableWidth,
|
|
|
|
layout->cachedLayout.heightMeasureMode,
|
|
|
|
layout->cachedLayout.availableHeight,
|
|
|
|
layout->cachedLayout.computedWidth,
|
|
|
|
layout->cachedLayout.computedHeight,
|
|
|
|
marginAxisRow,
|
|
|
|
marginAxisColumn,
|
|
|
|
config)) {
|
2017-04-28 03:57:13 -07:00
|
|
|
cachedResults = &layout->cachedLayout;
|
|
|
|
} else {
|
|
|
|
// Try to use the measurement cache.
|
|
|
|
for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
|
2018-07-19 09:57:04 -07:00
|
|
|
if (YGNodeCanUseCachedMeasurement(
|
|
|
|
widthMeasureMode,
|
|
|
|
availableWidth,
|
|
|
|
heightMeasureMode,
|
|
|
|
availableHeight,
|
|
|
|
layout->cachedMeasurements[i].widthMeasureMode,
|
|
|
|
layout->cachedMeasurements[i].availableWidth,
|
|
|
|
layout->cachedMeasurements[i].heightMeasureMode,
|
|
|
|
layout->cachedMeasurements[i].availableHeight,
|
|
|
|
layout->cachedMeasurements[i].computedWidth,
|
|
|
|
layout->cachedMeasurements[i].computedHeight,
|
|
|
|
marginAxisRow,
|
|
|
|
marginAxisColumn,
|
|
|
|
config)) {
|
2017-04-28 03:57:13 -07:00
|
|
|
cachedResults = &layout->cachedMeasurements[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (performLayout) {
|
|
|
|
if (YGFloatsEqual(layout->cachedLayout.availableWidth, availableWidth) &&
|
|
|
|
YGFloatsEqual(layout->cachedLayout.availableHeight, availableHeight) &&
|
|
|
|
layout->cachedLayout.widthMeasureMode == widthMeasureMode &&
|
|
|
|
layout->cachedLayout.heightMeasureMode == heightMeasureMode) {
|
|
|
|
cachedResults = &layout->cachedLayout;
|
|
|
|
}
|
|
|
|
} else {
|
2016-08-02 08:06:55 -07:00
|
|
|
for (uint32_t i = 0; i < layout->nextCachedMeasurementsIndex; i++) {
|
2018-07-19 09:57:04 -07:00
|
|
|
if (YGFloatsEqual(
|
|
|
|
layout->cachedMeasurements[i].availableWidth, availableWidth) &&
|
|
|
|
YGFloatsEqual(
|
|
|
|
layout->cachedMeasurements[i].availableHeight, availableHeight) &&
|
2017-04-28 03:57:13 -07:00
|
|
|
layout->cachedMeasurements[i].widthMeasureMode == widthMeasureMode &&
|
2018-07-19 09:57:04 -07:00
|
|
|
layout->cachedMeasurements[i].heightMeasureMode ==
|
|
|
|
heightMeasureMode) {
|
2016-07-25 06:31:32 -07:00
|
|
|
cachedResults = &layout->cachedMeasurements[i];
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
break;
|
|
|
|
}
|
2016-03-25 22:37:00 +01:00
|
|
|
}
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2016-03-25 22:37:00 +01:00
|
|
|
|
2017-11-21 10:10:30 -08:00
|
|
|
if (!needToVisitNode && cachedResults != nullptr) {
|
2016-12-02 05:47:43 -08:00
|
|
|
layout->measuredDimensions[YGDimensionWidth] = cachedResults->computedWidth;
|
2018-07-19 09:57:04 -07:00
|
|
|
layout->measuredDimensions[YGDimensionHeight] =
|
|
|
|
cachedResults->computedHeight;
|
2015-08-13 16:56:41 +08:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
if (gPrintChanges && gPrintSkips) {
|
2018-07-19 09:57:04 -07:00
|
|
|
YGLog(
|
|
|
|
node,
|
|
|
|
YGLogLevelVerbose,
|
|
|
|
"%s%d.{[skipped] ",
|
|
|
|
YGSpacer(gDepth),
|
|
|
|
gDepth);
|
2017-12-19 11:18:00 -08:00
|
|
|
if (node->getPrintFunc() != nullptr) {
|
|
|
|
node->getPrintFunc()(node);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2017-11-21 10:10:30 -08:00
|
|
|
YGLog(
|
|
|
|
node,
|
|
|
|
YGLogLevelVerbose,
|
|
|
|
"wm: %s, hm: %s, aw: %f ah: %f => d: (%f, %f) %s\n",
|
|
|
|
YGMeasureModeName(widthMeasureMode, performLayout),
|
|
|
|
YGMeasureModeName(heightMeasureMode, performLayout),
|
|
|
|
availableWidth,
|
|
|
|
availableHeight,
|
|
|
|
cachedResults->computedWidth,
|
|
|
|
cachedResults->computedHeight,
|
|
|
|
reason);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (gPrintChanges) {
|
2017-11-21 10:10:30 -08:00
|
|
|
YGLog(
|
|
|
|
node,
|
|
|
|
YGLogLevelVerbose,
|
|
|
|
"%s%d.{%s",
|
|
|
|
YGSpacer(gDepth),
|
|
|
|
gDepth,
|
|
|
|
needToVisitNode ? "*" : "");
|
2017-12-19 11:18:00 -08:00
|
|
|
if (node->getPrintFunc() != nullptr) {
|
|
|
|
node->getPrintFunc()(node);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2017-11-21 10:10:30 -08:00
|
|
|
YGLog(
|
|
|
|
node,
|
|
|
|
YGLogLevelVerbose,
|
|
|
|
"wm: %s, hm: %s, aw: %f ah: %f %s\n",
|
|
|
|
YGMeasureModeName(widthMeasureMode, performLayout),
|
|
|
|
YGMeasureModeName(heightMeasureMode, performLayout),
|
|
|
|
availableWidth,
|
|
|
|
availableHeight,
|
|
|
|
reason);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
YGNodelayoutImpl(
|
|
|
|
node,
|
|
|
|
availableWidth,
|
|
|
|
availableHeight,
|
|
|
|
ownerDirection,
|
|
|
|
widthMeasureMode,
|
|
|
|
heightMeasureMode,
|
|
|
|
ownerWidth,
|
|
|
|
ownerHeight,
|
|
|
|
performLayout,
|
|
|
|
config);
|
2016-06-03 22:19:03 +01:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
if (gPrintChanges) {
|
2017-11-21 10:10:30 -08:00
|
|
|
YGLog(
|
|
|
|
node,
|
|
|
|
YGLogLevelVerbose,
|
|
|
|
"%s%d.}%s",
|
|
|
|
YGSpacer(gDepth),
|
|
|
|
gDepth,
|
|
|
|
needToVisitNode ? "*" : "");
|
2017-12-19 11:18:00 -08:00
|
|
|
if (node->getPrintFunc() != nullptr) {
|
|
|
|
node->getPrintFunc()(node);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2017-11-21 10:10:30 -08:00
|
|
|
YGLog(
|
|
|
|
node,
|
|
|
|
YGLogLevelVerbose,
|
|
|
|
"wm: %s, hm: %s, d: (%f, %f) %s\n",
|
|
|
|
YGMeasureModeName(widthMeasureMode, performLayout),
|
|
|
|
YGMeasureModeName(heightMeasureMode, performLayout),
|
|
|
|
layout->measuredDimensions[YGDimensionWidth],
|
|
|
|
layout->measuredDimensions[YGDimensionHeight],
|
|
|
|
reason);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
|
|
|
|
2018-04-01 18:27:06 -07:00
|
|
|
layout->lastOwnerDirection = ownerDirection;
|
2016-06-03 22:19:03 +01:00
|
|
|
|
2017-11-21 10:10:30 -08:00
|
|
|
if (cachedResults == nullptr) {
|
2016-12-03 04:40:18 -08:00
|
|
|
if (layout->nextCachedMeasurementsIndex == YG_MAX_CACHED_RESULT_COUNT) {
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
if (gPrintChanges) {
|
2017-11-16 05:15:59 -08:00
|
|
|
YGLog(node, YGLogLevelVerbose, "Out of cache entries!\n");
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2016-07-25 06:31:32 -07:00
|
|
|
layout->nextCachedMeasurementsIndex = 0;
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
YGCachedMeasurement* newCacheEntry;
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
if (performLayout) {
|
|
|
|
// Use the single layout cache entry.
|
2016-09-20 10:16:13 -07:00
|
|
|
newCacheEntry = &layout->cachedLayout;
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
} else {
|
|
|
|
// Allocate a new measurement cache entry.
|
2018-07-19 09:57:04 -07:00
|
|
|
newCacheEntry =
|
|
|
|
&layout->cachedMeasurements[layout->nextCachedMeasurementsIndex];
|
2016-07-25 06:31:32 -07:00
|
|
|
layout->nextCachedMeasurementsIndex++;
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2016-06-03 22:19:03 +01:00
|
|
|
|
2016-07-25 06:31:32 -07:00
|
|
|
newCacheEntry->availableWidth = availableWidth;
|
|
|
|
newCacheEntry->availableHeight = availableHeight;
|
|
|
|
newCacheEntry->widthMeasureMode = widthMeasureMode;
|
|
|
|
newCacheEntry->heightMeasureMode = heightMeasureMode;
|
2018-07-19 09:57:04 -07:00
|
|
|
newCacheEntry->computedWidth =
|
|
|
|
layout->measuredDimensions[YGDimensionWidth];
|
|
|
|
newCacheEntry->computedHeight =
|
|
|
|
layout->measuredDimensions[YGDimensionHeight];
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
2016-06-03 22:19:03 +01:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
if (performLayout) {
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutDimension(
|
|
|
|
node->getLayout().measuredDimensions[YGDimensionWidth],
|
|
|
|
YGDimensionWidth);
|
|
|
|
node->setLayoutDimension(
|
|
|
|
node->getLayout().measuredDimensions[YGDimensionHeight],
|
|
|
|
YGDimensionHeight);
|
|
|
|
|
|
|
|
node->setHasNewLayout(true);
|
|
|
|
node->setDirty(false);
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gDepth--;
|
2016-07-25 06:31:32 -07:00
|
|
|
layout->generationCount = gCurrentGenerationCount;
|
2017-11-21 10:10:30 -08:00
|
|
|
return (needToVisitNode || cachedResults == nullptr);
|
2015-08-13 16:56:41 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGConfigSetPointScaleFactor(
|
|
|
|
const YGConfigRef config,
|
|
|
|
const float pixelsInPoint) {
|
|
|
|
YGAssertWithConfig(
|
|
|
|
config,
|
|
|
|
pixelsInPoint >= 0.0f,
|
|
|
|
"Scale factor should not be less than zero");
|
2017-05-03 09:22:35 -07:00
|
|
|
|
2017-02-24 09:45:31 -08:00
|
|
|
// We store points for Pixel as we will use it for rounding
|
2017-03-03 10:16:41 -08:00
|
|
|
if (pixelsInPoint == 0.0f) {
|
2017-02-24 09:45:31 -08:00
|
|
|
// Zero is used to skip rounding
|
2017-03-09 07:21:23 -08:00
|
|
|
config->pointScaleFactor = 0.0f;
|
2017-02-24 09:45:31 -08:00
|
|
|
} else {
|
2017-05-26 10:56:33 -07:00
|
|
|
config->pointScaleFactor = pixelsInPoint;
|
2017-02-24 09:45:31 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static void YGRoundToPixelGrid(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const float pointScaleFactor,
|
|
|
|
const float absoluteLeft,
|
|
|
|
const float absoluteTop) {
|
2017-03-09 07:21:23 -08:00
|
|
|
if (pointScaleFactor == 0.0f) {
|
2017-02-24 09:45:31 -08:00
|
|
|
return;
|
|
|
|
}
|
New round-to-pixel-grid algorithm that fixes possible subpixel gaps between sibling nodes
Summary:
This diff introduces new, little bit sophisticated round-to-pixel-grid algorithm.
**Motivation:**
Previous simple and straightforward solution works in most cases but sometimes produce the not-so-great result. A while ago Nick Lockwood described this problem and proposed the solution in RN's RCTShadowView class:
For example, say you have the following structure:
// +--------+---------+--------+
// | |+-------+| |
// | || || |
// | |+-------+| |
// +--------+---------+--------+
Say the screen width is 320 pts so the three big views will get the following x bounds from our layout system:
{0, 106.667}, {106.667, 213.333}, {213.333, 320}
Assuming screen scale is 2, these numbers must be rounded to the nearest 0.5 to fit the pixel grid:
{0, 106.5}, {106.5, 213.5}, {213.5, 320}
You'll notice that the three widths are 106.5, 107, 106.5.
This is great for the parent views but it gets trickier when we consider rounding for the subview. When we go to round the bounds for the subview in the middle, it's relative bounds are {0, 106.667} which gets rounded to {0, 106.5}. This will cause the subview to be one pixel smaller than it should be. This is why we need to pass in the absolute position in order to do the rounding relative to the screen's grid rather than the view's grid. After passing in the absolutePosition of {106.667, y}, we do the following calculations:
absoluteLeft = round(absolutePosition.x + viewPosition.left) = round(106.667 + 0) = 106.5
absoluteRight = round(absolutePosition.x + viewPosition.left + viewSize.width) + round(106.667 + 0 + 106.667) = 213.5
width = 213.5 - 106.5 = 107
You'll notice that this is the same width we calculated for the parent view because we've taken its position into account.
I believe this is awesome. I also believe that we have to decouple this logic from RN and put it into awesome Yoga. So I did it in this diff.
**Fun fact:**
The original implementation of this algorithm in RN had (and still have) a bug, which was found by Dustin dshahidehpour and fixed in D4133643. Therefore that diff was unlanded because it broke something unrelated inside RN text engine. I will fix that problem in RN later.
**Why do we need to change test methodology?**
Because the way we receive layout metrics from Chrome browser actually directly related to rounding problem. Previously we used `offsetHeight` and `offsetWidth` properties of the DOM node, which contain naively rounded values from `computedStyle` or `getBoundingClientRect`. (Which is we are trying to fix!) So, I added the new function that computes node size using two-step-rounding approach, conceptually similar to one that implemented in Yoga. Note: Chrome browser performs rounding layout as part of rendering process and actual values that can ve computed by counting actual pixel are different from these natively rounded ones.
**Why do some tests now have different desired values?**
These changes actually prove that my approach is correct and more useful for actual view rendering goals. So, let's take a look at test with changed values `rounding_fractial_input_3`:
Previously: 64+25+24=114 (Incorrect!)
Now: 65+24+25=114 (Correct!)
Previously: 64+25+24=114 (Incorrect!)
Now: 65+24+25=114 (Correct!)
Reviewed By: emilsjolander
Differential Revision: D4941266
fbshipit-source-id: 07500f5cc93c628219500e9e07291438e9d5d36c
2017-04-25 17:29:27 -07:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
const float nodeLeft = node->getLayout().position[YGEdgeLeft];
|
|
|
|
const float nodeTop = node->getLayout().position[YGEdgeTop];
|
2017-02-24 09:45:31 -08:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
const float nodeWidth = node->getLayout().dimensions[YGDimensionWidth];
|
|
|
|
const float nodeHeight = node->getLayout().dimensions[YGDimensionHeight];
|
2017-03-01 07:10:00 -08:00
|
|
|
|
New round-to-pixel-grid algorithm that fixes possible subpixel gaps between sibling nodes
Summary:
This diff introduces new, little bit sophisticated round-to-pixel-grid algorithm.
**Motivation:**
Previous simple and straightforward solution works in most cases but sometimes produce the not-so-great result. A while ago Nick Lockwood described this problem and proposed the solution in RN's RCTShadowView class:
For example, say you have the following structure:
// +--------+---------+--------+
// | |+-------+| |
// | || || |
// | |+-------+| |
// +--------+---------+--------+
Say the screen width is 320 pts so the three big views will get the following x bounds from our layout system:
{0, 106.667}, {106.667, 213.333}, {213.333, 320}
Assuming screen scale is 2, these numbers must be rounded to the nearest 0.5 to fit the pixel grid:
{0, 106.5}, {106.5, 213.5}, {213.5, 320}
You'll notice that the three widths are 106.5, 107, 106.5.
This is great for the parent views but it gets trickier when we consider rounding for the subview. When we go to round the bounds for the subview in the middle, it's relative bounds are {0, 106.667} which gets rounded to {0, 106.5}. This will cause the subview to be one pixel smaller than it should be. This is why we need to pass in the absolute position in order to do the rounding relative to the screen's grid rather than the view's grid. After passing in the absolutePosition of {106.667, y}, we do the following calculations:
absoluteLeft = round(absolutePosition.x + viewPosition.left) = round(106.667 + 0) = 106.5
absoluteRight = round(absolutePosition.x + viewPosition.left + viewSize.width) + round(106.667 + 0 + 106.667) = 213.5
width = 213.5 - 106.5 = 107
You'll notice that this is the same width we calculated for the parent view because we've taken its position into account.
I believe this is awesome. I also believe that we have to decouple this logic from RN and put it into awesome Yoga. So I did it in this diff.
**Fun fact:**
The original implementation of this algorithm in RN had (and still have) a bug, which was found by Dustin dshahidehpour and fixed in D4133643. Therefore that diff was unlanded because it broke something unrelated inside RN text engine. I will fix that problem in RN later.
**Why do we need to change test methodology?**
Because the way we receive layout metrics from Chrome browser actually directly related to rounding problem. Previously we used `offsetHeight` and `offsetWidth` properties of the DOM node, which contain naively rounded values from `computedStyle` or `getBoundingClientRect`. (Which is we are trying to fix!) So, I added the new function that computes node size using two-step-rounding approach, conceptually similar to one that implemented in Yoga. Note: Chrome browser performs rounding layout as part of rendering process and actual values that can ve computed by counting actual pixel are different from these natively rounded ones.
**Why do some tests now have different desired values?**
These changes actually prove that my approach is correct and more useful for actual view rendering goals. So, let's take a look at test with changed values `rounding_fractial_input_3`:
Previously: 64+25+24=114 (Incorrect!)
Now: 65+24+25=114 (Correct!)
Previously: 64+25+24=114 (Incorrect!)
Now: 65+24+25=114 (Correct!)
Reviewed By: emilsjolander
Differential Revision: D4941266
fbshipit-source-id: 07500f5cc93c628219500e9e07291438e9d5d36c
2017-04-25 17:29:27 -07:00
|
|
|
const float absoluteNodeLeft = absoluteLeft + nodeLeft;
|
|
|
|
const float absoluteNodeTop = absoluteTop + nodeTop;
|
2017-03-01 07:10:00 -08:00
|
|
|
|
New round-to-pixel-grid algorithm that fixes possible subpixel gaps between sibling nodes
Summary:
This diff introduces new, little bit sophisticated round-to-pixel-grid algorithm.
**Motivation:**
Previous simple and straightforward solution works in most cases but sometimes produce the not-so-great result. A while ago Nick Lockwood described this problem and proposed the solution in RN's RCTShadowView class:
For example, say you have the following structure:
// +--------+---------+--------+
// | |+-------+| |
// | || || |
// | |+-------+| |
// +--------+---------+--------+
Say the screen width is 320 pts so the three big views will get the following x bounds from our layout system:
{0, 106.667}, {106.667, 213.333}, {213.333, 320}
Assuming screen scale is 2, these numbers must be rounded to the nearest 0.5 to fit the pixel grid:
{0, 106.5}, {106.5, 213.5}, {213.5, 320}
You'll notice that the three widths are 106.5, 107, 106.5.
This is great for the parent views but it gets trickier when we consider rounding for the subview. When we go to round the bounds for the subview in the middle, it's relative bounds are {0, 106.667} which gets rounded to {0, 106.5}. This will cause the subview to be one pixel smaller than it should be. This is why we need to pass in the absolute position in order to do the rounding relative to the screen's grid rather than the view's grid. After passing in the absolutePosition of {106.667, y}, we do the following calculations:
absoluteLeft = round(absolutePosition.x + viewPosition.left) = round(106.667 + 0) = 106.5
absoluteRight = round(absolutePosition.x + viewPosition.left + viewSize.width) + round(106.667 + 0 + 106.667) = 213.5
width = 213.5 - 106.5 = 107
You'll notice that this is the same width we calculated for the parent view because we've taken its position into account.
I believe this is awesome. I also believe that we have to decouple this logic from RN and put it into awesome Yoga. So I did it in this diff.
**Fun fact:**
The original implementation of this algorithm in RN had (and still have) a bug, which was found by Dustin dshahidehpour and fixed in D4133643. Therefore that diff was unlanded because it broke something unrelated inside RN text engine. I will fix that problem in RN later.
**Why do we need to change test methodology?**
Because the way we receive layout metrics from Chrome browser actually directly related to rounding problem. Previously we used `offsetHeight` and `offsetWidth` properties of the DOM node, which contain naively rounded values from `computedStyle` or `getBoundingClientRect`. (Which is we are trying to fix!) So, I added the new function that computes node size using two-step-rounding approach, conceptually similar to one that implemented in Yoga. Note: Chrome browser performs rounding layout as part of rendering process and actual values that can ve computed by counting actual pixel are different from these natively rounded ones.
**Why do some tests now have different desired values?**
These changes actually prove that my approach is correct and more useful for actual view rendering goals. So, let's take a look at test with changed values `rounding_fractial_input_3`:
Previously: 64+25+24=114 (Incorrect!)
Now: 65+24+25=114 (Correct!)
Previously: 64+25+24=114 (Incorrect!)
Now: 65+24+25=114 (Correct!)
Reviewed By: emilsjolander
Differential Revision: D4941266
fbshipit-source-id: 07500f5cc93c628219500e9e07291438e9d5d36c
2017-04-25 17:29:27 -07:00
|
|
|
const float absoluteNodeRight = absoluteNodeLeft + nodeWidth;
|
|
|
|
const float absoluteNodeBottom = absoluteNodeTop + nodeHeight;
|
2017-03-01 07:10:00 -08:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
// If a node has a custom measure function we never want to round down its
|
|
|
|
// size as this could lead to unwanted text truncation.
|
2017-12-19 11:18:00 -08:00
|
|
|
const bool textRounding = node->getNodeType() == YGNodeTypeText;
|
|
|
|
|
|
|
|
node->setLayoutPosition(
|
|
|
|
YGRoundValueToPixelGrid(nodeLeft, pointScaleFactor, false, textRounding),
|
|
|
|
YGEdgeLeft);
|
2017-04-30 03:03:43 -07:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutPosition(
|
|
|
|
YGRoundValueToPixelGrid(nodeTop, pointScaleFactor, false, textRounding),
|
|
|
|
YGEdgeTop);
|
New round-to-pixel-grid algorithm that fixes possible subpixel gaps between sibling nodes
Summary:
This diff introduces new, little bit sophisticated round-to-pixel-grid algorithm.
**Motivation:**
Previous simple and straightforward solution works in most cases but sometimes produce the not-so-great result. A while ago Nick Lockwood described this problem and proposed the solution in RN's RCTShadowView class:
For example, say you have the following structure:
// +--------+---------+--------+
// | |+-------+| |
// | || || |
// | |+-------+| |
// +--------+---------+--------+
Say the screen width is 320 pts so the three big views will get the following x bounds from our layout system:
{0, 106.667}, {106.667, 213.333}, {213.333, 320}
Assuming screen scale is 2, these numbers must be rounded to the nearest 0.5 to fit the pixel grid:
{0, 106.5}, {106.5, 213.5}, {213.5, 320}
You'll notice that the three widths are 106.5, 107, 106.5.
This is great for the parent views but it gets trickier when we consider rounding for the subview. When we go to round the bounds for the subview in the middle, it's relative bounds are {0, 106.667} which gets rounded to {0, 106.5}. This will cause the subview to be one pixel smaller than it should be. This is why we need to pass in the absolute position in order to do the rounding relative to the screen's grid rather than the view's grid. After passing in the absolutePosition of {106.667, y}, we do the following calculations:
absoluteLeft = round(absolutePosition.x + viewPosition.left) = round(106.667 + 0) = 106.5
absoluteRight = round(absolutePosition.x + viewPosition.left + viewSize.width) + round(106.667 + 0 + 106.667) = 213.5
width = 213.5 - 106.5 = 107
You'll notice that this is the same width we calculated for the parent view because we've taken its position into account.
I believe this is awesome. I also believe that we have to decouple this logic from RN and put it into awesome Yoga. So I did it in this diff.
**Fun fact:**
The original implementation of this algorithm in RN had (and still have) a bug, which was found by Dustin dshahidehpour and fixed in D4133643. Therefore that diff was unlanded because it broke something unrelated inside RN text engine. I will fix that problem in RN later.
**Why do we need to change test methodology?**
Because the way we receive layout metrics from Chrome browser actually directly related to rounding problem. Previously we used `offsetHeight` and `offsetWidth` properties of the DOM node, which contain naively rounded values from `computedStyle` or `getBoundingClientRect`. (Which is we are trying to fix!) So, I added the new function that computes node size using two-step-rounding approach, conceptually similar to one that implemented in Yoga. Note: Chrome browser performs rounding layout as part of rendering process and actual values that can ve computed by counting actual pixel are different from these natively rounded ones.
**Why do some tests now have different desired values?**
These changes actually prove that my approach is correct and more useful for actual view rendering goals. So, let's take a look at test with changed values `rounding_fractial_input_3`:
Previously: 64+25+24=114 (Incorrect!)
Now: 65+24+25=114 (Correct!)
Previously: 64+25+24=114 (Incorrect!)
Now: 65+24+25=114 (Correct!)
Reviewed By: emilsjolander
Differential Revision: D4941266
fbshipit-source-id: 07500f5cc93c628219500e9e07291438e9d5d36c
2017-04-25 17:29:27 -07:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
// We multiply dimension by scale factor and if the result is close to the
|
|
|
|
// whole number, we don't have any fraction To verify if the result is close
|
|
|
|
// to whole number we want to check both floor and ceil numbers
|
|
|
|
const bool hasFractionalWidth =
|
|
|
|
!YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 0) &&
|
|
|
|
!YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 1.0);
|
|
|
|
const bool hasFractionalHeight =
|
|
|
|
!YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 0) &&
|
|
|
|
!YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 1.0);
|
2017-06-10 05:30:17 -07:00
|
|
|
|
2017-12-19 11:18:00 -08:00
|
|
|
node->setLayoutDimension(
|
|
|
|
YGRoundValueToPixelGrid(
|
|
|
|
absoluteNodeRight,
|
|
|
|
pointScaleFactor,
|
|
|
|
(textRounding && hasFractionalWidth),
|
|
|
|
(textRounding && !hasFractionalWidth)) -
|
|
|
|
YGRoundValueToPixelGrid(
|
|
|
|
absoluteNodeLeft, pointScaleFactor, false, textRounding),
|
|
|
|
YGDimensionWidth);
|
|
|
|
|
|
|
|
node->setLayoutDimension(
|
|
|
|
YGRoundValueToPixelGrid(
|
|
|
|
absoluteNodeBottom,
|
|
|
|
pointScaleFactor,
|
|
|
|
(textRounding && hasFractionalHeight),
|
|
|
|
(textRounding && !hasFractionalHeight)) -
|
|
|
|
YGRoundValueToPixelGrid(
|
|
|
|
absoluteNodeTop, pointScaleFactor, false, textRounding),
|
|
|
|
YGDimensionHeight);
|
|
|
|
|
2018-01-09 04:21:58 -08:00
|
|
|
const uint32_t childCount = YGNodeGetChildCount(node);
|
2016-11-22 05:33:36 -08:00
|
|
|
for (uint32_t i = 0; i < childCount; i++) {
|
2018-03-01 04:00:35 -08:00
|
|
|
YGRoundToPixelGrid(
|
|
|
|
YGNodeGetChild(node, i),
|
|
|
|
pointScaleFactor,
|
|
|
|
absoluteNodeLeft,
|
|
|
|
absoluteNodeTop);
|
2016-11-22 05:33:36 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-01 04:00:35 -08:00
|
|
|
void YGNodeCalculateLayout(
|
|
|
|
const YGNodeRef node,
|
2018-04-01 18:27:06 -07:00
|
|
|
const float ownerWidth,
|
|
|
|
const float ownerHeight,
|
|
|
|
const YGDirection ownerDirection) {
|
2016-08-04 08:20:11 -07:00
|
|
|
// Increment the generation count. This will force the recursive routine to
|
|
|
|
// visit
|
|
|
|
// all dirty nodes at least once. Subsequent visits will be skipped if the
|
|
|
|
// input
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
// parameters don't change.
|
|
|
|
gCurrentGenerationCount++;
|
2017-12-19 11:18:00 -08:00
|
|
|
node->resolveDimension();
|
2017-02-28 08:10:34 -08:00
|
|
|
float width = YGUndefined;
|
|
|
|
YGMeasureMode widthMeasureMode = YGMeasureModeUndefined;
|
2018-04-01 18:27:06 -07:00
|
|
|
if (YGNodeIsStyleDimDefined(node, YGFlexDirectionRow, ownerWidth)) {
|
2018-04-04 07:55:54 -07:00
|
|
|
width = YGUnwrapFloatOptional(
|
|
|
|
YGResolveValue(
|
|
|
|
node->getResolvedDimension(dim[YGFlexDirectionRow]), ownerWidth) +
|
|
|
|
node->getMarginForAxis(YGFlexDirectionRow, ownerWidth));
|
2016-12-02 05:47:43 -08:00
|
|
|
widthMeasureMode = YGMeasureModeExactly;
|
2018-03-14 04:17:07 -07:00
|
|
|
} else if (!YGResolveValue(
|
2018-04-01 18:27:06 -07:00
|
|
|
node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth)
|
2018-03-15 12:29:02 -07:00
|
|
|
.isUndefined()) {
|
2018-03-14 04:17:07 -07:00
|
|
|
width = YGUnwrapFloatOptional(YGResolveValue(
|
2018-04-01 18:27:06 -07:00
|
|
|
node->getStyle().maxDimensions[YGDimensionWidth], ownerWidth));
|
2016-12-02 05:47:43 -08:00
|
|
|
widthMeasureMode = YGMeasureModeAtMost;
|
2017-03-01 07:10:00 -08:00
|
|
|
} else {
|
2018-04-01 18:27:06 -07:00
|
|
|
width = ownerWidth;
|
2018-03-01 04:00:35 -08:00
|
|
|
widthMeasureMode = YGFloatIsUndefined(width) ? YGMeasureModeUndefined
|
|
|
|
: YGMeasureModeExactly;
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
2016-06-03 22:19:03 +01:00
|
|
|
|
2017-02-28 08:10:34 -08:00
|
|
|
float height = YGUndefined;
|
|
|
|
YGMeasureMode heightMeasureMode = YGMeasureModeUndefined;
|
2018-04-01 18:27:06 -07:00
|
|
|
if (YGNodeIsStyleDimDefined(node, YGFlexDirectionColumn, ownerHeight)) {
|
2018-04-04 07:55:54 -07:00
|
|
|
height = YGUnwrapFloatOptional(
|
|
|
|
YGResolveValue(
|
|
|
|
node->getResolvedDimension(dim[YGFlexDirectionColumn]),
|
|
|
|
ownerHeight) +
|
|
|
|
node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth));
|
2016-12-02 05:47:43 -08:00
|
|
|
heightMeasureMode = YGMeasureModeExactly;
|
2018-03-15 12:29:02 -07:00
|
|
|
} else if (!YGResolveValue(
|
|
|
|
node->getStyle().maxDimensions[YGDimensionHeight],
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerHeight)
|
2018-03-15 12:29:02 -07:00
|
|
|
.isUndefined()) {
|
2018-07-19 09:57:04 -07:00
|
|
|
height = YGUnwrapFloatOptional(YGResolveValue(
|
|
|
|
node->getStyle().maxDimensions[YGDimensionHeight], ownerHeight));
|
2016-12-02 05:47:43 -08:00
|
|
|
heightMeasureMode = YGMeasureModeAtMost;
|
2017-03-01 07:10:00 -08:00
|
|
|
} else {
|
2018-04-01 18:27:06 -07:00
|
|
|
height = ownerHeight;
|
2018-03-01 04:00:35 -08:00
|
|
|
heightMeasureMode = YGFloatIsUndefined(height) ? YGMeasureModeUndefined
|
|
|
|
: YGMeasureModeExactly;
|
2016-07-02 11:22:57 +01:00
|
|
|
}
|
2017-12-19 11:18:00 -08:00
|
|
|
if (YGLayoutNodeInternal(
|
|
|
|
node,
|
|
|
|
width,
|
|
|
|
height,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerDirection,
|
2017-12-19 11:18:00 -08:00
|
|
|
widthMeasureMode,
|
|
|
|
heightMeasureMode,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerWidth,
|
|
|
|
ownerHeight,
|
2017-12-19 11:18:00 -08:00
|
|
|
true,
|
|
|
|
"initial",
|
|
|
|
node->getConfig())) {
|
2018-01-11 04:47:48 -08:00
|
|
|
node->setPosition(
|
2018-04-01 18:27:06 -07:00
|
|
|
node->getLayout().direction, ownerWidth, ownerHeight, ownerWidth);
|
2017-12-19 11:18:00 -08:00
|
|
|
YGRoundToPixelGrid(node, node->getConfig()->pointScaleFactor, 0.0f, 0.0f);
|
2016-11-22 05:33:36 -08:00
|
|
|
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
if (gPrintTree) {
|
2017-11-21 10:10:30 -08:00
|
|
|
YGNodePrint(
|
|
|
|
node,
|
|
|
|
(YGPrintOptions)(
|
|
|
|
YGPrintOptionsLayout | YGPrintOptionsChildren |
|
|
|
|
YGPrintOptionsStyle));
|
Alter layout engine to conform closer to W3C spec
The primary goals of this change are:
- Better conformance to the W3C flexbox standard (https://www.w3.org/TR/css-flexbox-1/)
and a clear articulation of the areas where it deviates from the spec.
- Support for flex-shrink.
- Conformance with layout effects of "overflow: hidden".
Specifically, here are the limitations of this implementation as compared to the W3C
flexbox standard (this is also documented in Layout.js):
- Display property is always assumed to be 'flex' except for Text nodes, which
are assumed to be 'inline-flex'.
- The 'zIndex' property (or any form of z ordering) is not supported. Nodes are
stacked in document order.
- The 'order' property is not supported. The order of flex items is always defined
by document order.
- The 'visibility' property is always assumed to be 'visible'. Values of 'collapse'
and 'hidden' are not supported.
- The 'wrap' property supports only 'nowrap' (which is the default) or 'wrap'. The
rarely-used 'wrap-reverse' is not supported.
- Rather than allowing arbitrary combinations of flexGrow, flexShrink and
flexBasis, this algorithm supports only the three most common combinations:
- flex: 0 is equiavlent to flex: 0 0 auto
- flex: n (where n is a positive value) is equivalent to flex: n 0 0
- flex: -1 (or any negative value) is equivalent to flex: 0 1 auto
- Margins cannot be specified as 'auto'. They must be specified in terms of pixel
values, and the default value is 0.
- The 'baseline' value is not supported for alignItems and alignSelf properties.
- Values of width, maxWidth, minWidth, height, maxHeight and minHeight must be
specified as pixel values, not as percentages.
- There is no support for calculation of dimensions based on intrinsic aspect ratios
(e.g. images).
- There is no support for forced breaks.
- It does not support vertical inline directions (top-to-bottom or bottom-to-top text).
And here is how the implementation deviates from the standard (this is also documented in
Layout.js):
- Section 4.5 of the spec indicates that all flex items have a default minimum
main size. For text blocks, for example, this is the width of the widest word.
Calculating the minimum width is expensive, so we forego it and assume a default
minimum main size of 0.
- Min/Max sizes in the main axis are not honored when resolving flexible lengths.
- The spec indicates that the default value for 'flexDirection' is 'row', but
the algorithm below assumes a default of 'column'.
2016-04-26 16:35:46 -07:00
|
|
|
}
|
|
|
|
}
|
2018-02-02 07:38:17 -08:00
|
|
|
|
|
|
|
// We want to get rid off `useLegacyStretchBehaviour` from YGConfig. But we
|
|
|
|
// aren't sure whether client's of yoga have gotten rid off this flag or not.
|
|
|
|
// So logging this in YGLayout would help to find out the call sites depending
|
|
|
|
// on this flag. This check would be removed once we are sure no one is
|
2018-02-09 06:14:36 -08:00
|
|
|
// dependent on this flag anymore. The flag
|
|
|
|
// `shouldDiffLayoutWithoutLegacyStretchBehaviour` in YGConfig will help to
|
|
|
|
// run experiments.
|
|
|
|
if (node->getConfig()->shouldDiffLayoutWithoutLegacyStretchBehaviour &&
|
|
|
|
node->didUseLegacyFlag()) {
|
2018-02-02 07:38:17 -08:00
|
|
|
const YGNodeRef originalNode = YGNodeDeepClone(node);
|
|
|
|
originalNode->resolveDimension();
|
|
|
|
// Recursively mark nodes as dirty
|
|
|
|
originalNode->markDirtyAndPropogateDownwards();
|
|
|
|
gCurrentGenerationCount++;
|
|
|
|
// Rerun the layout, and calculate the diff
|
|
|
|
originalNode->setAndPropogateUseLegacyFlag(false);
|
|
|
|
if (YGLayoutNodeInternal(
|
|
|
|
originalNode,
|
|
|
|
width,
|
|
|
|
height,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerDirection,
|
2018-02-02 07:38:17 -08:00
|
|
|
widthMeasureMode,
|
|
|
|
heightMeasureMode,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerWidth,
|
|
|
|
ownerHeight,
|
2018-02-02 07:38:17 -08:00
|
|
|
true,
|
|
|
|
"initial",
|
|
|
|
originalNode->getConfig())) {
|
|
|
|
originalNode->setPosition(
|
|
|
|
originalNode->getLayout().direction,
|
2018-04-01 18:27:06 -07:00
|
|
|
ownerWidth,
|
|
|
|
ownerHeight,
|
|
|
|
ownerWidth);
|
2018-02-02 07:38:17 -08:00
|
|
|
YGRoundToPixelGrid(
|
|
|
|
originalNode,
|
|
|
|
originalNode->getConfig()->pointScaleFactor,
|
|
|
|
0.0f,
|
|
|
|
0.0f);
|
|
|
|
|
|
|
|
// Set whether the two layouts are different or not.
|
|
|
|
node->setLayoutDoesLegacyFlagAffectsLayout(
|
|
|
|
!originalNode->isLayoutTreeEqualToNode(*node));
|
|
|
|
|
|
|
|
if (gPrintTree) {
|
|
|
|
YGNodePrint(
|
|
|
|
originalNode,
|
|
|
|
(YGPrintOptions)(
|
|
|
|
YGPrintOptionsLayout | YGPrintOptionsChildren |
|
|
|
|
YGPrintOptionsStyle));
|
|
|
|
}
|
|
|
|
}
|
2018-02-09 04:47:49 -08:00
|
|
|
YGConfigFreeRecursive(originalNode);
|
2018-02-02 07:38:17 -08:00
|
|
|
YGNodeFreeRecursive(originalNode);
|
|
|
|
}
|
2016-03-25 22:37:00 +01:00
|
|
|
}
|
2016-10-07 12:31:06 -07:00
|
|
|
|
2017-05-03 09:22:35 -07:00
|
|
|
void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) {
|
2017-11-21 10:10:30 -08:00
|
|
|
if (logger != nullptr) {
|
2017-05-03 09:22:35 -07:00
|
|
|
config->logger = logger;
|
2017-04-03 09:34:42 -07:00
|
|
|
} else {
|
|
|
|
#ifdef ANDROID
|
2017-05-03 09:22:35 -07:00
|
|
|
config->logger = &YGAndroidLog;
|
2017-04-03 09:34:42 -07:00
|
|
|
#else
|
2017-05-03 09:22:35 -07:00
|
|
|
config->logger = &YGDefaultLog;
|
2017-04-03 09:34:42 -07:00
|
|
|
#endif
|
|
|
|
}
|
2016-10-19 11:01:24 -07:00
|
|
|
}
|
|
|
|
|
2018-03-14 08:37:55 -07:00
|
|
|
void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
|
|
|
|
const YGConfigRef config,
|
|
|
|
const bool shouldDiffLayout) {
|
|
|
|
config->shouldDiffLayoutWithoutLegacyStretchBehaviour = shouldDiffLayout;
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static void YGVLog(
|
|
|
|
const YGConfigRef config,
|
|
|
|
const YGNodeRef node,
|
|
|
|
YGLogLevel level,
|
|
|
|
const char* format,
|
|
|
|
va_list args) {
|
|
|
|
const YGConfigRef logConfig =
|
|
|
|
config != nullptr ? config : YGConfigGetDefault();
|
2017-05-03 09:22:35 -07:00
|
|
|
logConfig->logger(logConfig, node, level, format, args);
|
|
|
|
|
|
|
|
if (level == YGLogLevelFatal) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGLogWithConfig(
|
|
|
|
const YGConfigRef config,
|
|
|
|
YGLogLevel level,
|
|
|
|
const char* format,
|
|
|
|
...) {
|
2017-05-03 09:22:35 -07:00
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
2017-11-21 10:10:30 -08:00
|
|
|
YGVLog(config, nullptr, level, format, args);
|
2017-05-03 09:22:35 -07:00
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGLog(const YGNodeRef node, YGLogLevel level, const char* format, ...) {
|
2016-11-09 09:45:37 -08:00
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
2017-12-19 11:18:00 -08:00
|
|
|
YGVLog(
|
|
|
|
node == nullptr ? nullptr : node->getConfig(), node, level, format, args);
|
2016-11-09 09:45:37 -08:00
|
|
|
va_end(args);
|
|
|
|
}
|
2016-11-14 03:27:33 -08:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGAssert(const bool condition, const char* message) {
|
2017-05-03 09:22:35 -07:00
|
|
|
if (!condition) {
|
2017-11-21 10:10:30 -08:00
|
|
|
YGLog(nullptr, YGLogLevelFatal, "%s\n", message);
|
2017-05-03 09:22:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGAssertWithNode(
|
|
|
|
const YGNodeRef node,
|
|
|
|
const bool condition,
|
|
|
|
const char* message) {
|
2017-05-03 09:22:35 -07:00
|
|
|
if (!condition) {
|
|
|
|
YGLog(node, YGLogLevelFatal, "%s\n", message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGAssertWithConfig(
|
|
|
|
const YGConfigRef config,
|
|
|
|
const bool condition,
|
|
|
|
const char* message) {
|
2017-05-03 09:22:35 -07:00
|
|
|
if (!condition) {
|
|
|
|
YGLogWithConfig(config, YGLogLevelFatal, "%s\n", message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGConfigSetExperimentalFeatureEnabled(
|
|
|
|
const YGConfigRef config,
|
|
|
|
const YGExperimentalFeature feature,
|
|
|
|
const bool enabled) {
|
2017-03-01 09:19:55 -08:00
|
|
|
config->experimentalFeatures[feature] = enabled;
|
2016-11-14 03:27:33 -08:00
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
inline bool YGConfigIsExperimentalFeatureEnabled(
|
|
|
|
const YGConfigRef config,
|
|
|
|
const YGExperimentalFeature feature) {
|
2017-03-01 09:19:55 -08:00
|
|
|
return config->experimentalFeatures[feature];
|
2016-11-14 03:27:33 -08:00
|
|
|
}
|
2016-11-15 20:20:09 -08:00
|
|
|
|
2017-03-03 10:47:42 -08:00
|
|
|
void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled) {
|
|
|
|
config->useWebDefaults = enabled;
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGConfigSetUseLegacyStretchBehaviour(
|
|
|
|
const YGConfigRef config,
|
|
|
|
const bool useLegacyStretchBehaviour) {
|
2017-04-28 06:13:51 -07:00
|
|
|
config->useLegacyStretchBehaviour = useLegacyStretchBehaviour;
|
|
|
|
}
|
|
|
|
|
2017-03-03 10:47:42 -08:00
|
|
|
bool YGConfigGetUseWebDefaults(const YGConfigRef config) {
|
|
|
|
return config->useWebDefaults;
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGConfigSetContext(const YGConfigRef config, void* context) {
|
2017-05-03 09:22:35 -07:00
|
|
|
config->context = context;
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void* YGConfigGetContext(const YGConfigRef config) {
|
2017-05-03 09:22:35 -07:00
|
|
|
return config->context;
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGConfigSetCloneNodeFunc(
|
|
|
|
const YGConfigRef config,
|
|
|
|
const YGCloneNodeFunc callback) {
|
Persistent Yoga
Summary:
This is meant to show a possible route format for a persistent form of Yoga. Where previous layouts can remain intact while still taking advantage of incremental layout by reusing previous subtrees.
```c
YGNodeRef YGNodeClone(const YGNodeRef node);
```
The core of this functionality is a new API to clone an existing node. This makes a new detached node with all the same values as the previous one. Conceptually this makes the original node "frozen" from that point on. It's now immutable. (This is not yet enforced at runtime in this PR but something we should add.)
Since the original is frozen, we reuse the children set from the original node. Their parent pointers still point back to the original tree though.
The cloned node is still mutable. It can have its styles updated, and nodes can be inserted or deleted. If an insertion/deletion happens on a cloned node whose children were reused, it'll first shallow clone its children automatically.
As a convenience I also added an API to clear all children:
```c
void YGNodeRemoveAllChildren(const YGNodeRef node);
```
During insert/delete, or as a result of layout a set of reused children may need to be first cloned. A kind of copy-on-write. When that happens, the host may want to respond. E.g. by updating the `context` such as by cloning any wrapper objects and attaching them to the new node.
```c
typedef void (*YGNodeClonedFunc)(YGNodeRef oldNode,
YGNodeRef newNode,
YGNodeRef parent,
int childIndex);
void YGConfigSetNodeClonedFunc(YGConfigRef config,
YGNodeClonedFunc callback);
```
This PR doesn't change any existing semantics for trees that are not first cloned.
It's possible for a single node to exist in two trees at once and be used by multiple threads. Therefore it's not safe to recursively free a whole tree when you use persistence. To solve this, any user of the library has to manually manage ref counting or tracing GC. E.g. by replicating the tree structure in a wrapper.
In a follow up we could consider moving ref counting into Yoga.
Closes https://github.com/facebook/yoga/pull/636
Reviewed By: emilsjolander
Differential Revision: D5941921
Pulled By: sebmarkbage
fbshipit-source-id: c8e93421824c112d09c4773bed4e3141b6491ccf
2017-10-17 01:02:04 -07:00
|
|
|
config->cloneNodeCallback = callback;
|
|
|
|
}
|
2018-03-25 13:56:13 -07:00
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
static void YGTraverseChildrenPreOrder(
|
|
|
|
const YGVector& children,
|
|
|
|
const std::function<void(YGNodeRef node)>& f) {
|
2018-03-25 13:56:13 -07:00
|
|
|
for (YGNodeRef node : children) {
|
|
|
|
f(node);
|
|
|
|
YGTraverseChildrenPreOrder(node->getChildren(), f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 09:57:04 -07:00
|
|
|
void YGTraversePreOrder(
|
|
|
|
YGNodeRef const node,
|
|
|
|
std::function<void(YGNodeRef node)>&& f) {
|
2018-03-25 13:56:13 -07:00
|
|
|
if (!node) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
f(node);
|
|
|
|
YGTraverseChildrenPreOrder(node->getChildren(), f);
|
|
|
|
}
|