mirror of
https://github.com/status-im/react-native.git
synced 2025-01-29 10:45:04 +00:00
9f7cedbe14
Reviewed By: emilsjolander Differential Revision: D6856812 fbshipit-source-id: e4724d80702cc75c1894e348e137b24e663573d2
351 lines
12 KiB
C++
351 lines
12 KiB
C++
/**
|
|
* Copyright (c) 2014-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
#pragma once
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cmath>
|
|
#include <vector>
|
|
|
|
#include "Yoga.h"
|
|
|
|
using YGVector = std::vector<YGNodeRef>;
|
|
|
|
YG_EXTERN_C_BEGIN
|
|
|
|
WIN_EXPORT float YGRoundValueToPixelGrid(const float value,
|
|
const float pointScaleFactor,
|
|
const bool forceCeil,
|
|
const bool forceFloor);
|
|
|
|
YG_EXTERN_C_END
|
|
|
|
extern const std::array<YGEdge, 4> trailing;
|
|
extern const std::array<YGEdge, 4> leading;
|
|
extern bool YGValueEqual(const YGValue a, const YGValue b);
|
|
extern const YGValue YGValueUndefined;
|
|
extern const YGValue YGValueAuto;
|
|
extern const YGValue YGValueZero;
|
|
|
|
template <std::size_t size>
|
|
bool YGValueArrayEqual(
|
|
const std::array<YGValue, size> val1,
|
|
const std::array<YGValue, size> val2) {
|
|
bool areEqual = true;
|
|
for (uint32_t i = 0; i < size && areEqual; ++i) {
|
|
areEqual = YGValueEqual(val1[i], val2[i]);
|
|
}
|
|
return areEqual;
|
|
}
|
|
|
|
struct YGCachedMeasurement {
|
|
float availableWidth;
|
|
float availableHeight;
|
|
YGMeasureMode widthMeasureMode;
|
|
YGMeasureMode heightMeasureMode;
|
|
|
|
float computedWidth;
|
|
float computedHeight;
|
|
|
|
bool operator==(YGCachedMeasurement measurement) const {
|
|
bool isEqual = widthMeasureMode == measurement.widthMeasureMode &&
|
|
heightMeasureMode == measurement.heightMeasureMode;
|
|
|
|
if (!std::isnan(availableWidth) ||
|
|
!std::isnan(measurement.availableWidth)) {
|
|
isEqual = isEqual && availableWidth == measurement.availableWidth;
|
|
}
|
|
if (!std::isnan(availableHeight) ||
|
|
!std::isnan(measurement.availableHeight)) {
|
|
isEqual = isEqual && availableHeight == measurement.availableHeight;
|
|
}
|
|
if (!std::isnan(computedWidth) || !std::isnan(measurement.computedWidth)) {
|
|
isEqual = isEqual && computedWidth == measurement.computedWidth;
|
|
}
|
|
if (!std::isnan(
|
|
computedHeight || !std::isnan(measurement.computedHeight))) {
|
|
isEqual = isEqual && computedHeight == measurement.computedHeight;
|
|
}
|
|
|
|
return availableWidth == measurement.availableWidth &&
|
|
availableHeight == measurement.availableHeight &&
|
|
widthMeasureMode == measurement.widthMeasureMode &&
|
|
heightMeasureMode == measurement.heightMeasureMode &&
|
|
computedWidth == measurement.computedWidth &&
|
|
computedHeight == measurement.computedHeight;
|
|
}
|
|
};
|
|
|
|
// This value was chosen based on empiracle data. Even the most complicated
|
|
// layouts should not require more than 16 entries to fit within the cache.
|
|
#define YG_MAX_CACHED_RESULT_COUNT 16
|
|
|
|
struct YGLayout {
|
|
std::array<float, 4> position;
|
|
std::array<float, 2> dimensions;
|
|
std::array<float, 6> margin;
|
|
std::array<float, 6> border;
|
|
std::array<float, 6> padding;
|
|
YGDirection direction;
|
|
|
|
uint32_t computedFlexBasisGeneration;
|
|
float computedFlexBasis;
|
|
bool hadOverflow;
|
|
|
|
// Instead of recomputing the entire layout every single time, we
|
|
// cache some information to break early when nothing changed
|
|
uint32_t generationCount;
|
|
YGDirection lastParentDirection;
|
|
|
|
uint32_t nextCachedMeasurementsIndex;
|
|
YGCachedMeasurement cachedMeasurements[YG_MAX_CACHED_RESULT_COUNT];
|
|
std::array<float, 2> measuredDimensions;
|
|
|
|
YGCachedMeasurement cachedLayout;
|
|
bool didUseLegacyFlag;
|
|
bool doesLegacyStretchFlagAffectsLayout;
|
|
|
|
bool operator==(YGLayout layout) const {
|
|
bool isEqual = position == layout.position &&
|
|
dimensions == layout.dimensions && margin == layout.margin &&
|
|
border == layout.border && padding == layout.padding &&
|
|
direction == layout.direction && hadOverflow == layout.hadOverflow &&
|
|
lastParentDirection == layout.lastParentDirection &&
|
|
nextCachedMeasurementsIndex == layout.nextCachedMeasurementsIndex &&
|
|
cachedLayout == layout.cachedLayout;
|
|
|
|
for (uint32_t i = 0; i < YG_MAX_CACHED_RESULT_COUNT && isEqual; ++i) {
|
|
isEqual =
|
|
isEqual && cachedMeasurements[i] == layout.cachedMeasurements[i];
|
|
}
|
|
|
|
if (!YGFloatIsUndefined(computedFlexBasis) ||
|
|
!YGFloatIsUndefined(layout.computedFlexBasis)) {
|
|
isEqual = isEqual && (computedFlexBasis == layout.computedFlexBasis);
|
|
}
|
|
if (!YGFloatIsUndefined(measuredDimensions[0]) ||
|
|
!YGFloatIsUndefined(layout.measuredDimensions[0])) {
|
|
isEqual =
|
|
isEqual && (measuredDimensions[0] == layout.measuredDimensions[0]);
|
|
}
|
|
if (!YGFloatIsUndefined(measuredDimensions[1]) ||
|
|
!YGFloatIsUndefined(layout.measuredDimensions[1])) {
|
|
isEqual =
|
|
isEqual && (measuredDimensions[1] == layout.measuredDimensions[1]);
|
|
}
|
|
|
|
return isEqual;
|
|
}
|
|
|
|
bool operator!=(YGLayout layout) const {
|
|
return !(*this == layout);
|
|
}
|
|
};
|
|
|
|
struct YGStyle {
|
|
YGDirection direction;
|
|
YGFlexDirection flexDirection;
|
|
YGJustify justifyContent;
|
|
YGAlign alignContent;
|
|
YGAlign alignItems;
|
|
YGAlign alignSelf;
|
|
YGPositionType positionType;
|
|
YGWrap flexWrap;
|
|
YGOverflow overflow;
|
|
YGDisplay display;
|
|
float flex;
|
|
float flexGrow;
|
|
float flexShrink;
|
|
YGValue flexBasis;
|
|
std::array<YGValue, YGEdgeCount> margin;
|
|
std::array<YGValue, YGEdgeCount> position;
|
|
std::array<YGValue, YGEdgeCount> padding;
|
|
std::array<YGValue, YGEdgeCount> border;
|
|
std::array<YGValue, 2> dimensions;
|
|
std::array<YGValue, 2> minDimensions;
|
|
std::array<YGValue, 2> maxDimensions;
|
|
|
|
// Yoga specific properties, not compatible with flexbox specification
|
|
float aspectRatio;
|
|
bool operator==(YGStyle style) {
|
|
bool areNonFloatValuesEqual = direction == style.direction &&
|
|
flexDirection == style.flexDirection &&
|
|
justifyContent == style.justifyContent &&
|
|
alignContent == style.alignContent && alignItems == style.alignItems &&
|
|
alignSelf == style.alignSelf && positionType == style.positionType &&
|
|
flexWrap == style.flexWrap && overflow == style.overflow &&
|
|
display == style.display && YGValueEqual(flexBasis, style.flexBasis) &&
|
|
YGValueArrayEqual(margin, style.margin) &&
|
|
YGValueArrayEqual(position, style.position) &&
|
|
YGValueArrayEqual(padding, style.padding) &&
|
|
YGValueArrayEqual(border, style.border) &&
|
|
YGValueArrayEqual(dimensions, style.dimensions) &&
|
|
YGValueArrayEqual(minDimensions, style.minDimensions) &&
|
|
YGValueArrayEqual(maxDimensions, style.maxDimensions);
|
|
|
|
if (!(std::isnan(flex) && std::isnan(style.flex))) {
|
|
areNonFloatValuesEqual = areNonFloatValuesEqual && flex == style.flex;
|
|
}
|
|
|
|
if (!(std::isnan(flexGrow) && std::isnan(style.flexGrow))) {
|
|
areNonFloatValuesEqual =
|
|
areNonFloatValuesEqual && flexGrow == style.flexGrow;
|
|
}
|
|
|
|
if (!(std::isnan(flexShrink) && std::isnan(style.flexShrink))) {
|
|
areNonFloatValuesEqual =
|
|
areNonFloatValuesEqual && flexShrink == style.flexShrink;
|
|
}
|
|
|
|
if (!(std::isnan(aspectRatio) && std::isnan(style.aspectRatio))) {
|
|
areNonFloatValuesEqual =
|
|
areNonFloatValuesEqual && aspectRatio == style.aspectRatio;
|
|
}
|
|
|
|
return areNonFloatValuesEqual;
|
|
}
|
|
|
|
bool operator!=(YGStyle style) {
|
|
return !(*this == style);
|
|
}
|
|
};
|
|
|
|
struct YGConfig {
|
|
bool experimentalFeatures[YGExperimentalFeatureCount + 1];
|
|
bool useWebDefaults;
|
|
bool useLegacyStretchBehaviour;
|
|
float pointScaleFactor;
|
|
YGLogger logger;
|
|
YGNodeClonedFunc cloneNodeCallback;
|
|
void* context;
|
|
};
|
|
|
|
#define YG_UNDEFINED_VALUES \
|
|
{ .value = YGUndefined, .unit = YGUnitUndefined }
|
|
|
|
#define YG_AUTO_VALUES \
|
|
{ .value = YGUndefined, .unit = YGUnitAuto }
|
|
|
|
#define YG_DEFAULT_EDGE_VALUES_UNIT \
|
|
{ \
|
|
[YGEdgeLeft] = YG_UNDEFINED_VALUES, [YGEdgeTop] = YG_UNDEFINED_VALUES, \
|
|
[YGEdgeRight] = YG_UNDEFINED_VALUES, [YGEdgeBottom] = YG_UNDEFINED_VALUES, \
|
|
[YGEdgeStart] = YG_UNDEFINED_VALUES, [YGEdgeEnd] = YG_UNDEFINED_VALUES, \
|
|
[YGEdgeHorizontal] = YG_UNDEFINED_VALUES, \
|
|
[YGEdgeVertical] = YG_UNDEFINED_VALUES, [YGEdgeAll] = YG_UNDEFINED_VALUES, \
|
|
}
|
|
|
|
#define YG_DEFAULT_DIMENSION_VALUES \
|
|
{ [YGDimensionWidth] = YGUndefined, [YGDimensionHeight] = YGUndefined, }
|
|
|
|
#define YG_DEFAULT_DIMENSION_VALUES_UNIT \
|
|
{ \
|
|
[YGDimensionWidth] = YG_UNDEFINED_VALUES, \
|
|
[YGDimensionHeight] = YG_UNDEFINED_VALUES, \
|
|
}
|
|
|
|
#define YG_DEFAULT_DIMENSION_VALUES_AUTO_UNIT \
|
|
{ [YGDimensionWidth] = YG_AUTO_VALUES, [YGDimensionHeight] = YG_AUTO_VALUES, }
|
|
|
|
static const float kDefaultFlexGrow = 0.0f;
|
|
static const float kDefaultFlexShrink = 0.0f;
|
|
static const float kWebDefaultFlexShrink = 1.0f;
|
|
|
|
static const YGStyle gYGNodeStyleDefaults = {
|
|
.direction = YGDirectionInherit,
|
|
.flexDirection = YGFlexDirectionColumn,
|
|
.justifyContent = YGJustifyFlexStart,
|
|
.alignContent = YGAlignFlexStart,
|
|
.alignItems = YGAlignStretch,
|
|
.alignSelf = YGAlignAuto,
|
|
.positionType = YGPositionTypeRelative,
|
|
.flexWrap = YGWrapNoWrap,
|
|
.overflow = YGOverflowVisible,
|
|
.display = YGDisplayFlex,
|
|
.flex = YGUndefined,
|
|
.flexGrow = YGUndefined,
|
|
.flexShrink = YGUndefined,
|
|
.flexBasis = YG_AUTO_VALUES,
|
|
.margin = {{YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES}},
|
|
.position = {{YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES}},
|
|
.padding = {{YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES}},
|
|
.border = {{YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES,
|
|
YG_UNDEFINED_VALUES}},
|
|
.dimensions = {{YG_AUTO_VALUES, YG_AUTO_VALUES}},
|
|
.minDimensions = {{YG_UNDEFINED_VALUES, YG_UNDEFINED_VALUES}},
|
|
.maxDimensions = {{YG_UNDEFINED_VALUES, YG_UNDEFINED_VALUES}},
|
|
.aspectRatio = YGUndefined,
|
|
};
|
|
|
|
static const YGLayout gYGNodeLayoutDefaults = {
|
|
.position = {},
|
|
.dimensions = {{YGUndefined, YGUndefined}},
|
|
.margin = {},
|
|
.border = {},
|
|
.padding = {},
|
|
.direction = YGDirectionInherit,
|
|
.computedFlexBasisGeneration = 0,
|
|
.computedFlexBasis = YGUndefined,
|
|
.hadOverflow = false,
|
|
.generationCount = 0,
|
|
.lastParentDirection = (YGDirection)-1,
|
|
.nextCachedMeasurementsIndex = 0,
|
|
.cachedMeasurements = {},
|
|
.measuredDimensions = {{YGUndefined, YGUndefined}},
|
|
.cachedLayout =
|
|
{
|
|
.availableWidth = 0,
|
|
.availableHeight = 0,
|
|
.widthMeasureMode = (YGMeasureMode)-1,
|
|
.heightMeasureMode = (YGMeasureMode)-1,
|
|
.computedWidth = -1,
|
|
.computedHeight = -1,
|
|
},
|
|
.didUseLegacyFlag = false,
|
|
.doesLegacyStretchFlagAffectsLayout = false,
|
|
};
|
|
|
|
extern bool YGFloatsEqual(const float a, const float b);
|
|
extern bool YGValueEqual(const YGValue a, const YGValue b);
|
|
extern const YGValue* YGComputedEdgeValue(
|
|
const std::array<YGValue, YGEdgeCount>& edges,
|
|
const YGEdge edge,
|
|
const YGValue* const defaultValue);
|