update yoga to cbf6495d66a7a8066d1354daa14d3bb1af19f6ef

This commit is contained in:
王劲鹏 2021-04-20 10:18:06 +08:00 committed by osborn
parent 5ba5f5ce6c
commit 8d04d41b19
20 changed files with 609 additions and 588 deletions

View File

@ -123,7 +123,7 @@ HEADERS += \
widget/flex/FlexLayout.h \ widget/flex/FlexLayout.h \
widget/flex/FlexLayoutConfig.h \ widget/flex/FlexLayoutConfig.h \
widget/flex/FlexLayoutService.h \ widget/flex/FlexLayoutService.h \
yoga/Bitfield.h \ yoga/BitUtils.h \
yoga/CompactValue.h \ yoga/CompactValue.h \
yoga/Utils.h \ yoga/Utils.h \
yoga/YGConfig.h \ yoga/YGConfig.h \

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <cstdio>
#include <cstdint>
#include "YGEnums.h"
namespace facebook {
namespace yoga {
namespace detail {
constexpr size_t log2ceilFn(size_t n) {
return n < 1 ? 0 : (1 + log2ceilFn(n / 2));
}
constexpr int mask(size_t bitWidth, size_t index) {
return ((1 << bitWidth) - 1) << index;
}
// The number of bits necessary to represent enums defined with YG_ENUM_SEQ_DECL
template <typename Enum>
constexpr size_t bitWidthFn() {
static_assert(
enums::count<Enum>() > 0, "Enums must have at least one entries");
return log2ceilFn(enums::count<Enum>() - 1);
}
template <typename Enum>
constexpr Enum getEnumData(int flags, size_t index) {
return static_cast<Enum>((flags & mask(bitWidthFn<Enum>(), index)) >> index);
}
template <typename Enum>
void setEnumData(uint32_t& flags, size_t index, int newValue) {
flags = (flags & ~mask(bitWidthFn<Enum>(), index)) |
((newValue << index) & (mask(bitWidthFn<Enum>(), index)));
}
template <typename Enum>
void setEnumData(uint8_t& flags, size_t index, int newValue) {
flags = (flags & ~static_cast<uint8_t>(mask(bitWidthFn<Enum>(), index))) |
((newValue << index) &
(static_cast<uint8_t>(mask(bitWidthFn<Enum>(), index))));
}
constexpr bool getBooleanData(int flags, size_t index) {
return (flags >> index) & 1;
}
inline void setBooleanData(uint8_t& flags, size_t index, bool value) {
if (value) {
flags |= 1 << index;
} else {
flags &= ~(1 << index);
}
}
} // namespace detail
} // namespace yoga
} // namespace facebook

View File

@ -1,145 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <cstddef>
#include <limits>
#include <type_traits>
#include <yoga/YGEnums.h>
namespace facebook {
namespace yoga {
namespace detail {
constexpr size_t log2ceil(size_t n) {
return n < 1 ? 0 : (1 + log2ceil(n / 2));
}
// The number of bits necessary to represent enums defined with YG_ENUM_SEQ_DECL
template <typename Enum>
constexpr size_t bitWidth() {
static_assert(
enums::count<Enum>() > 0, "Enums must have at least one entries");
return log2ceil(enums::count<Enum>() - 1);
}
// Number of bits needed for a boolean
template <>
constexpr size_t bitWidth<bool>() {
return 1;
}
template <typename U, typename... Ts>
struct BitTraits {};
template <typename U>
struct BitTraits<U> {
// Base cases
static constexpr size_t width(size_t) { return 0; }
static constexpr size_t shift(size_t) { return 0; }
};
template <typename U, typename T, typename... Ts>
struct BitTraits<U, T, Ts...> {
using Rest = BitTraits<U, Ts...>;
static constexpr size_t width(size_t idx) {
return idx == 0 ? bitWidth<T>() : Rest::width(idx - 1);
}
static constexpr size_t shift(size_t idx) {
return idx == 0 ? Rest::width(0) + Rest::shift(0) : Rest::shift(idx - 1);
}
static constexpr U mask(size_t idx) {
return ((U{1} << width(idx)) - 1) << shift(idx);
}
};
template <size_t Idx, typename T, typename... Ts>
struct IndexedType {
using Type = typename IndexedType<Idx - 1, Ts...>::Type;
};
template <typename T, typename... Ts>
struct IndexedType<0, T, Ts...> {
using Type = T;
};
} // namespace detail
template <typename Storage, typename... Fields>
class Bitfield {
static_assert(
std::is_integral<Storage>::value,
"Bitfield needs an integral storage type");
static_assert(
std::is_unsigned<Storage>::value,
"Bitfield needs an unsigned storage type");
static_assert(sizeof...(Fields) > 0, "Bitfield needs at least one member");
using BitTraits = detail::BitTraits<Storage, Fields...>;
#if !defined(_MSC_VER) || _MSC_VER > 1914
static_assert(
BitTraits::shift(0) + BitTraits::width(0) <=
std::numeric_limits<Storage>::digits,
"Specified storage type is too narrow to hold all types");
#endif
template <size_t Idx>
using TypeAt = typename detail::IndexedType<Idx, Fields...>::Type;
template <size_t Idx, typename Value, typename... Values>
static constexpr Storage initStorage(Value value, Values... values) {
return ((value << BitTraits::shift(Idx)) & BitTraits::mask(Idx)) |
initStorage<Idx + 1, Values...>(values...);
}
template <size_t Idx>
static constexpr Storage initStorage() {
return Storage{0};
}
Storage storage_ = 0;
public:
template <size_t Idx>
class Ref {
Bitfield& bitfield_;
public:
Ref(Bitfield& bitfield) : bitfield_(bitfield) {}
Ref& operator=(TypeAt<Idx> value) {
bitfield_.storage_ = (bitfield_.storage_ & ~BitTraits::mask(Idx)) |
((value << BitTraits::shift(Idx)) & BitTraits::mask(Idx));
return *this;
}
operator TypeAt<Idx>() const {
return const_cast<const Bitfield&>(bitfield_).at<Idx>();
}
};
constexpr Bitfield() = default;
constexpr Bitfield(Fields... values) : storage_{initStorage<0>(values...)} {}
template <size_t Idx>
constexpr TypeAt<Idx> at() const {
return static_cast<TypeAt<Idx>>(
(storage_ & BitTraits::mask(Idx)) >> BitTraits::shift(Idx));
}
template <size_t Idx>
Ref<Idx> at() {
return {*this};
}
};
} // namespace yoga
} // namespace facebook

View File

@ -125,8 +125,8 @@ public:
data.repr &= ~PERCENT_BIT; data.repr &= ~PERCENT_BIT;
data.repr += BIAS; data.repr += BIAS;
return YGValue{data.value, return YGValue{
payload_.repr & 0x40000000 ? YGUnitPercent : YGUnitPoint}; data.value, payload_.repr & 0x40000000 ? YGUnitPercent : YGUnitPoint};
} }
bool isUndefined() const noexcept { bool isUndefined() const noexcept {

View File

@ -6,6 +6,7 @@
*/ */
#include "Utils.h" #include "Utils.h"
#include <stdexcept>
using namespace facebook; using namespace facebook;
@ -52,6 +53,13 @@ bool YGFloatsEqual(const float a, const float b) {
return yoga::isUndefined(a) && yoga::isUndefined(b); return yoga::isUndefined(a) && yoga::isUndefined(b);
} }
bool YGDoubleEqual(const double a, const double b) {
if (!yoga::isUndefined(a) && !yoga::isUndefined(b)) {
return fabs(a - b) < 0.0001;
}
return yoga::isUndefined(a) && yoga::isUndefined(b);
}
float YGFloatSanitize(const float val) { float YGFloatSanitize(const float val) {
return yoga::isUndefined(val) ? 0 : val; return yoga::isUndefined(val) ? 0 : val;
} }
@ -65,3 +73,7 @@ YGFloatOptional YGFloatOptionalMax(YGFloatOptional op1, YGFloatOptional op2) {
} }
return op1.isUndefined() ? op2 : op1; return op1.isUndefined() ? op2 : op1;
} }
void throwLogicalErrorWithMessage(const char* message) {
throw std::logic_error(message);
}

View File

@ -64,6 +64,8 @@ inline bool YGValueEqual(
// difference between two floats is less than 0.0001f or both are undefined. // difference between two floats is less than 0.0001f or both are undefined.
bool YGFloatsEqual(const float a, const float b); bool YGFloatsEqual(const float a, const float b);
bool YGDoubleEqual(const double a, const double b);
float YGFloatMax(const float a, const float b); float YGFloatMax(const float a, const float b);
YGFloatOptional YGFloatOptionalMax( YGFloatOptional YGFloatOptionalMax(
@ -141,3 +143,5 @@ inline YGFloatOptional YGResolveValueMargin(
const float ownerSize) { const float ownerSize) {
return value.isAuto() ? YGFloatOptional{0} : YGResolveValue(value, ownerSize); return value.isAuto() ? YGFloatOptional{0} : YGResolveValue(value, ownerSize);
} }
void throwLogicalErrorWithMessage(const char* message);

View File

@ -179,6 +179,8 @@ const char* YGOverflowToString(const YGOverflow value) {
const char* YGPositionTypeToString(const YGPositionType value) { const char* YGPositionTypeToString(const YGPositionType value) {
switch (value) { switch (value) {
case YGPositionTypeStatic:
return "static";
case YGPositionTypeRelative: case YGPositionTypeRelative:
return "relative"; return "relative";
case YGPositionTypeAbsolute: case YGPositionTypeAbsolute:

View File

@ -128,7 +128,11 @@ YG_ENUM_SEQ_DECL(
YGOverflowHidden, YGOverflowHidden,
YGOverflowScroll) YGOverflowScroll)
YG_ENUM_SEQ_DECL(YGPositionType, YGPositionTypeRelative, YGPositionTypeAbsolute) YG_ENUM_SEQ_DECL(
YGPositionType,
YGPositionTypeStatic,
YGPositionTypeRelative,
YGPositionTypeAbsolute)
YG_ENUM_DECL( YG_ENUM_DECL(
YGPrintOptions, YGPrintOptions,

View File

@ -6,10 +6,12 @@
*/ */
#pragma once #pragma once
#include "Bitfield.h" #include "BitUtils.h"
#include "YGFloatOptional.h" #include "YGFloatOptional.h"
#include "Yoga-internal.h" #include "Yoga-internal.h"
using namespace facebook::yoga;
struct YGLayout { struct YGLayout {
std::array<float, 4> position = {}; std::array<float, 4> position = {};
std::array<float, 2> dimensions = {{YGUndefined, YGUndefined}}; std::array<float, 2> dimensions = {{YGUndefined, YGUndefined}};
@ -18,12 +20,14 @@ struct YGLayout {
std::array<float, 4> padding = {}; std::array<float, 4> padding = {};
private: private:
static constexpr size_t directionIdx = 0; static constexpr size_t directionOffset = 0;
static constexpr size_t didUseLegacyFlagIdx = 1; static constexpr size_t didUseLegacyFlagOffset =
static constexpr size_t doesLegacyStretchFlagAffectsLayoutIdx = 2; directionOffset + facebook::yoga::detail::bitWidthFn<YGDirection>();
static constexpr size_t hadOverflowIdx = 3; static constexpr size_t doesLegacyStretchFlagAffectsLayoutOffset =
facebook::yoga::Bitfield<uint8_t, YGDirection, bool, bool, bool> flags_ = didUseLegacyFlagOffset + 1;
{YGDirectionInherit, false, false, false}; static constexpr size_t hadOverflowOffset =
doesLegacyStretchFlagAffectsLayoutOffset + 1;
uint8_t flags = 0;
public: public:
uint32_t computedFlexBasisGeneration = 0; uint32_t computedFlexBasisGeneration = 0;
@ -32,7 +36,7 @@ public:
// Instead of recomputing the entire layout every single time, we cache some // Instead of recomputing the entire layout every single time, we cache some
// information to break early when nothing changed // information to break early when nothing changed
uint32_t generationCount = 0; uint32_t generationCount = 0;
YGDirection lastOwnerDirection = (YGDirection) -1; YGDirection lastOwnerDirection = YGDirectionInherit;
uint32_t nextCachedMeasurementsIndex = 0; uint32_t nextCachedMeasurementsIndex = 0;
std::array<YGCachedMeasurement, YG_MAX_CACHED_RESULT_COUNT> std::array<YGCachedMeasurement, YG_MAX_CACHED_RESULT_COUNT>
@ -41,27 +45,41 @@ public:
YGCachedMeasurement cachedLayout = YGCachedMeasurement(); YGCachedMeasurement cachedLayout = YGCachedMeasurement();
YGDirection direction() const { return flags_.at<directionIdx>(); } YGDirection direction() const {
decltype(flags_)::Ref<directionIdx> direction() { return facebook::yoga::detail::getEnumData<YGDirection>(
return flags_.at<directionIdx>(); flags, directionOffset);
} }
bool didUseLegacyFlag() const { return flags_.at<didUseLegacyFlagIdx>(); } void setDirection(YGDirection direction) {
decltype(flags_)::Ref<didUseLegacyFlagIdx> didUseLegacyFlag() { facebook::yoga::detail::setEnumData<YGDirection>(
return flags_.at<didUseLegacyFlagIdx>(); flags, directionOffset, direction);
}
bool didUseLegacyFlag() const {
return facebook::yoga::detail::getBooleanData(
flags, didUseLegacyFlagOffset);
}
void setDidUseLegacyFlag(bool val) {
facebook::yoga::detail::setBooleanData(flags, didUseLegacyFlagOffset, val);
} }
bool doesLegacyStretchFlagAffectsLayout() const { bool doesLegacyStretchFlagAffectsLayout() const {
return flags_.at<doesLegacyStretchFlagAffectsLayoutIdx>(); return facebook::yoga::detail::getBooleanData(
} flags, doesLegacyStretchFlagAffectsLayoutOffset);
decltype(flags_)::Ref<doesLegacyStretchFlagAffectsLayoutIdx>
doesLegacyStretchFlagAffectsLayout() {
return flags_.at<doesLegacyStretchFlagAffectsLayoutIdx>();
} }
bool hadOverflow() const { return flags_.at<hadOverflowIdx>(); } void setDoesLegacyStretchFlagAffectsLayout(bool val) {
decltype(flags_)::Ref<hadOverflowIdx> hadOverflow() { facebook::yoga::detail::setBooleanData(
return flags_.at<hadOverflowIdx>(); flags, doesLegacyStretchFlagAffectsLayoutOffset, val);
}
bool hadOverflow() const {
return facebook::yoga::detail::getBooleanData(flags, hadOverflowOffset);
}
void setHadOverflow(bool hadOverflow) {
facebook::yoga::detail::setBooleanData(
flags, hadOverflowOffset, hadOverflow);
} }
bool operator==(YGLayout layout) const; bool operator==(YGLayout layout) const;

View File

@ -16,7 +16,7 @@ using facebook::yoga::detail::CompactValue;
YGNode::YGNode(YGNode&& node) { YGNode::YGNode(YGNode&& node) {
context_ = node.context_; context_ = node.context_;
flags_ = node.flags_; flags = node.flags;
measure_ = node.measure_; measure_ = node.measure_;
baseline_ = node.baseline_; baseline_ = node.baseline_;
print_ = node.print_; print_ = node.print_;
@ -29,7 +29,7 @@ YGNode::YGNode(YGNode&& node) {
config_ = node.config_; config_ = node.config_;
resolvedDimensions_ = node.resolvedDimensions_; resolvedDimensions_ = node.resolvedDimensions_;
for (auto c : children_) { for (auto c : children_) {
c->setOwner(c); c->setOwner(this);
} }
} }
@ -42,7 +42,7 @@ YGNode::YGNode(const YGNode& node, YGConfigRef config) : YGNode{node} {
void YGNode::print(void* printContext) { void YGNode::print(void* printContext) {
if (print_.noContext != nullptr) { if (print_.noContext != nullptr) {
if (flags_.at<printUsesContext_>()) { if (facebook::yoga::detail::getBooleanData(flags, printUsesContext_)) {
print_.withContext(this, printContext); print_.withContext(this, printContext);
} else { } else {
print_.noContext(this); print_.noContext(this);
@ -50,89 +50,111 @@ void YGNode::print(void* printContext) {
} }
} }
CompactValue YGNode::computeEdgeValueForRow(
const YGStyle::Edges& edges,
YGEdge rowEdge,
YGEdge edge,
CompactValue defaultValue) {
if (!edges[rowEdge].isUndefined()) {
return edges[rowEdge];
} else if (!edges[edge].isUndefined()) {
return edges[edge];
} else if (!edges[YGEdgeHorizontal].isUndefined()) {
return edges[YGEdgeHorizontal];
} else if (!edges[YGEdgeAll].isUndefined()) {
return edges[YGEdgeAll];
} else {
return defaultValue;
}
}
CompactValue YGNode::computeEdgeValueForColumn(
const YGStyle::Edges& edges,
YGEdge edge,
CompactValue defaultValue) {
if (!edges[edge].isUndefined()) {
return edges[edge];
} else if (!edges[YGEdgeVertical].isUndefined()) {
return edges[YGEdgeVertical];
} else if (!edges[YGEdgeAll].isUndefined()) {
return edges[YGEdgeAll];
} else {
return defaultValue;
}
}
YGFloatOptional YGNode::getLeadingPosition( YGFloatOptional YGNode::getLeadingPosition(
const YGFlexDirection axis, const YGFlexDirection axis,
const float axisSize) const { const float axisSize) const {
if (YGFlexDirectionIsRow(axis)) { auto leadingPosition = YGFlexDirectionIsRow(axis)
auto leadingPosition = YGComputedEdgeValue( ? computeEdgeValueForRow(
style_.position(), YGEdgeStart, CompactValue::ofUndefined()); style_.position(),
if (!leadingPosition.isUndefined()) { YGEdgeStart,
return YGResolveValue(leadingPosition, axisSize); leading[axis],
} CompactValue::ofZero())
} : computeEdgeValueForColumn(
style_.position(), leading[axis], CompactValue::ofZero());
auto leadingPosition = YGComputedEdgeValue( return YGResolveValue(leadingPosition, axisSize);
style_.position(), leading[axis], CompactValue::ofUndefined());
return leadingPosition.isUndefined()
? YGFloatOptional{0}
: YGResolveValue(leadingPosition, axisSize);
} }
YGFloatOptional YGNode::getTrailingPosition( YGFloatOptional YGNode::getTrailingPosition(
const YGFlexDirection axis, const YGFlexDirection axis,
const float axisSize) const { const float axisSize) const {
if (YGFlexDirectionIsRow(axis)) { auto trailingPosition = YGFlexDirectionIsRow(axis)
auto trailingPosition = YGComputedEdgeValue( ? computeEdgeValueForRow(
style_.position(), YGEdgeEnd, CompactValue::ofUndefined()); style_.position(),
if (!trailingPosition.isUndefined()) { YGEdgeEnd,
return YGResolveValue(trailingPosition, axisSize); trailing[axis],
} CompactValue::ofZero())
} : computeEdgeValueForColumn(
style_.position(), trailing[axis], CompactValue::ofZero());
auto trailingPosition = YGComputedEdgeValue( return YGResolveValue(trailingPosition, axisSize);
style_.position(), trailing[axis], CompactValue::ofUndefined());
return trailingPosition.isUndefined()
? YGFloatOptional{0}
: YGResolveValue(trailingPosition, axisSize);
} }
bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const { bool YGNode::isLeadingPositionDefined(const YGFlexDirection axis) const {
return (YGFlexDirectionIsRow(axis) && auto leadingPosition = YGFlexDirectionIsRow(axis)
!YGComputedEdgeValue( ? computeEdgeValueForRow(
style_.position(), YGEdgeStart, CompactValue::ofUndefined()) style_.position(),
.isUndefined()) || YGEdgeStart,
!YGComputedEdgeValue( leading[axis],
style_.position(), leading[axis], CompactValue::ofUndefined()) CompactValue::ofUndefined())
.isUndefined(); : computeEdgeValueForColumn(
style_.position(), leading[axis], CompactValue::ofUndefined());
return !leadingPosition.isUndefined();
} }
bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) const { bool YGNode::isTrailingPosDefined(const YGFlexDirection axis) const {
return (YGFlexDirectionIsRow(axis) && auto trailingPosition = YGFlexDirectionIsRow(axis)
!YGComputedEdgeValue( ? computeEdgeValueForRow(
style_.position(), YGEdgeEnd, CompactValue::ofUndefined()) style_.position(),
.isUndefined()) || YGEdgeEnd,
!YGComputedEdgeValue( trailing[axis],
style_.position(), trailing[axis], CompactValue::ofUndefined()) CompactValue::ofUndefined())
.isUndefined(); : computeEdgeValueForColumn(
style_.position(), trailing[axis], CompactValue::ofUndefined());
return !trailingPosition.isUndefined();
} }
YGFloatOptional YGNode::getLeadingMargin( YGFloatOptional YGNode::getLeadingMargin(
const YGFlexDirection axis, const YGFlexDirection axis,
const float widthSize) const { const float widthSize) const {
if (YGFlexDirectionIsRow(axis) && auto leadingMargin = YGFlexDirectionIsRow(axis)
!style_.margin()[YGEdgeStart].isUndefined()) { ? computeEdgeValueForRow(
return YGResolveValueMargin(style_.margin()[YGEdgeStart], widthSize); style_.margin(), YGEdgeStart, leading[axis], CompactValue::ofZero())
} : computeEdgeValueForColumn(
style_.margin(), leading[axis], CompactValue::ofZero());
return YGResolveValueMargin( return YGResolveValueMargin(leadingMargin, widthSize);
YGComputedEdgeValue(
style_.margin(), leading[axis], CompactValue::ofZero()),
widthSize);
} }
YGFloatOptional YGNode::getTrailingMargin( YGFloatOptional YGNode::getTrailingMargin(
const YGFlexDirection axis, const YGFlexDirection axis,
const float widthSize) const { const float widthSize) const {
if (YGFlexDirectionIsRow(axis) && !style_.margin()[YGEdgeEnd].isUndefined()) { auto trailingMargin = YGFlexDirectionIsRow(axis)
return YGResolveValueMargin(style_.margin()[YGEdgeEnd], widthSize); ? computeEdgeValueForRow(
} style_.margin(), YGEdgeEnd, trailing[axis], CompactValue::ofZero())
: computeEdgeValueForColumn(
return YGResolveValueMargin( style_.margin(), trailing[axis], CompactValue::ofZero());
YGComputedEdgeValue( return YGResolveValueMargin(trailingMargin, widthSize);
style_.margin(), trailing[axis], CompactValue::ofZero()),
widthSize);
} }
YGFloatOptional YGNode::getMarginForAxis( YGFloatOptional YGNode::getMarginForAxis(
@ -147,15 +169,14 @@ YGSize YGNode::measure(
float height, float height,
YGMeasureMode heightMode, YGMeasureMode heightMode,
void* layoutContext) { void* layoutContext) {
return facebook::yoga::detail::getBooleanData(flags, measureUsesContext_)
return flags_.at<measureUsesContext_>()
? measure_.withContext( ? measure_.withContext(
this, width, widthMode, height, heightMode, layoutContext) this, width, widthMode, height, heightMode, layoutContext)
: measure_.noContext(this, width, widthMode, height, heightMode); : measure_.noContext(this, width, widthMode, height, heightMode);
} }
float YGNode::baseline(float width, float height, void* layoutContext) { float YGNode::baseline(float width, float height, void* layoutContext) {
return flags_.at<baselineUsesContext_>() return facebook::yoga::detail::getBooleanData(flags, baselineUsesContext_)
? baseline_.withContext(this, width, height, layoutContext) ? baseline_.withContext(this, width, height, layoutContext)
: baseline_.noContext(this, width, height); : baseline_.noContext(this, width, height);
} }
@ -166,7 +187,7 @@ void YGNode::setMeasureFunc(decltype(YGNode::measure_) measureFunc) {
if (measureFunc.noContext == nullptr) { if (measureFunc.noContext == nullptr) {
// TODO: t18095186 Move nodeType to opt-in function and mark appropriate // TODO: t18095186 Move nodeType to opt-in function and mark appropriate
// places in Litho // places in Litho
flags_.at<nodeType_>() = YGNodeTypeDefault; setNodeType(YGNodeTypeDefault);
} else { } else {
YGAssertWithNode( YGAssertWithNode(
this, this,
@ -182,14 +203,14 @@ void YGNode::setMeasureFunc(decltype(YGNode::measure_) measureFunc) {
} }
void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) { void YGNode::setMeasureFunc(YGMeasureFunc measureFunc) {
flags_.at<measureUsesContext_>() = false; facebook::yoga::detail::setBooleanData(flags, measureUsesContext_, false);
decltype(YGNode::measure_) m; decltype(YGNode::measure_) m;
m.noContext = measureFunc; m.noContext = measureFunc;
setMeasureFunc(m); setMeasureFunc(m);
} }
YOGA_EXPORT void YGNode::setMeasureFunc(MeasureWithContextFn measureFunc) { YOGA_EXPORT void YGNode::setMeasureFunc(MeasureWithContextFn measureFunc) {
flags_.at<measureUsesContext_>() = true; facebook::yoga::detail::setBooleanData(flags, measureUsesContext_, true);
decltype(YGNode::measure_) m; decltype(YGNode::measure_) m;
m.withContext = measureFunc; m.withContext = measureFunc;
setMeasureFunc(m); setMeasureFunc(m);
@ -208,10 +229,10 @@ void YGNode::insertChild(YGNodeRef child, uint32_t index) {
} }
void YGNode::setDirty(bool isDirty) { void YGNode::setDirty(bool isDirty) {
if (isDirty == flags_.at<isDirty_>()) { if (isDirty == facebook::yoga::detail::getBooleanData(flags, isDirty_)) {
return; return;
} }
flags_.at<isDirty_>() = isDirty; facebook::yoga::detail::setBooleanData(flags, isDirty_, isDirty);
if (isDirty && dirtied_) { if (isDirty && dirtied_) {
dirtied_(this); dirtied_(this);
} }
@ -232,7 +253,7 @@ void YGNode::removeChild(uint32_t index) {
} }
void YGNode::setLayoutDirection(YGDirection direction) { void YGNode::setLayoutDirection(YGDirection direction) {
layout_.direction() = direction; layout_.setDirection(direction);
} }
void YGNode::setLayoutMargin(float margin, int index) { void YGNode::setLayoutMargin(float margin, int index) {
@ -270,7 +291,7 @@ void YGNode::setLayoutMeasuredDimension(float measuredDimension, int index) {
} }
void YGNode::setLayoutHadOverflow(bool hadOverflow) { void YGNode::setLayoutHadOverflow(bool hadOverflow) {
layout_.hadOverflow() = hadOverflow; layout_.setHadOverflow(hadOverflow);
} }
void YGNode::setLayoutDimension(float dimension, int index) { void YGNode::setLayoutDimension(float dimension, int index) {
@ -307,6 +328,9 @@ void YGNode::setPosition(
const YGFlexDirection crossAxis = const YGFlexDirection crossAxis =
YGFlexDirectionCross(mainAxis, directionRespectingRoot); YGFlexDirectionCross(mainAxis, directionRespectingRoot);
// Here we should check for `YGPositionTypeStatic` and in this case zero inset
// properties (left, right, top, bottom, begin, end).
// https://www.w3.org/TR/css-position-3/#valdef-position-static
const YGFloatOptional relativePositionMain = const YGFloatOptional relativePositionMain =
relativePosition(mainAxis, mainSize); relativePosition(mainAxis, mainSize);
const YGFloatOptional relativePositionCross = const YGFloatOptional relativePositionCross =
@ -351,7 +375,9 @@ YGValue YGNode::resolveFlexBasisPtr() const {
return flexBasis; return flexBasis;
} }
if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) { if (!style_.flex().isUndefined() && style_.flex().unwrap() > 0.0f) {
return flags_.at<useWebDefaults_>() ? YGValueAuto : YGValueZero; return facebook::yoga::detail::getBooleanData(flags, useWebDefaults_)
? YGValueAuto
: YGValueZero;
} }
return YGValueAuto; return YGValueAuto;
} }
@ -390,7 +416,7 @@ void YGNode::cloneChildrenIfNeeded(void* cloneContext) {
} }
void YGNode::markDirtyAndPropogate() { void YGNode::markDirtyAndPropogate() {
if (!flags_.at<isDirty_>()) { if (!facebook::yoga::detail::getBooleanData(flags, isDirty_)) {
setDirty(true); setDirty(true);
setLayoutComputedFlexBasis(YGFloatOptional()); setLayoutComputedFlexBasis(YGFloatOptional());
if (owner_) { if (owner_) {
@ -400,7 +426,7 @@ void YGNode::markDirtyAndPropogate() {
} }
void YGNode::markDirtyAndPropogateDownwards() { void YGNode::markDirtyAndPropogateDownwards() {
flags_.at<isDirty_>() = true; facebook::yoga::detail::setBooleanData(flags, isDirty_, true);
for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) { for_each(children_.begin(), children_.end(), [](YGNodeRef childNode) {
childNode->markDirtyAndPropogateDownwards(); childNode->markDirtyAndPropogateDownwards();
}); });
@ -427,83 +453,64 @@ float YGNode::resolveFlexShrink() const {
if (!style_.flexShrink().isUndefined()) { if (!style_.flexShrink().isUndefined()) {
return style_.flexShrink().unwrap(); return style_.flexShrink().unwrap();
} }
if (!flags_.at<useWebDefaults_>() && !style_.flex().isUndefined() && if (!facebook::yoga::detail::getBooleanData(flags, useWebDefaults_) &&
style_.flex().unwrap() < 0.0f) { !style_.flex().isUndefined() && style_.flex().unwrap() < 0.0f) {
return -style_.flex().unwrap(); return -style_.flex().unwrap();
} }
return flags_.at<useWebDefaults_>() ? kWebDefaultFlexShrink return facebook::yoga::detail::getBooleanData(flags, useWebDefaults_)
: kDefaultFlexShrink; ? kWebDefaultFlexShrink
: kDefaultFlexShrink;
} }
bool YGNode::isNodeFlexible() { bool YGNode::isNodeFlexible() {
return ( return (
(style_.positionType() == YGPositionTypeRelative) && (style_.positionType() != YGPositionTypeAbsolute) &&
(resolveFlexGrow() != 0 || resolveFlexShrink() != 0)); (resolveFlexGrow() != 0 || resolveFlexShrink() != 0));
} }
float YGNode::getLeadingBorder(const YGFlexDirection axis) const { float YGNode::getLeadingBorder(const YGFlexDirection axis) const {
YGValue leadingBorder; YGValue leadingBorder = YGFlexDirectionIsRow(axis)
if (YGFlexDirectionIsRow(axis) && ? computeEdgeValueForRow(
!style_.border()[YGEdgeStart].isUndefined()) { style_.border(), YGEdgeStart, leading[axis], CompactValue::ofZero())
leadingBorder = style_.border()[YGEdgeStart]; : computeEdgeValueForColumn(
if (leadingBorder.value >= 0) { style_.border(), leading[axis], CompactValue::ofZero());
return leadingBorder.value; return fmaxf(leadingBorder.value, 0.0f);
}
}
leadingBorder = YGComputedEdgeValue(
style_.border(), leading[axis], CompactValue::ofZero());
return YGFloatMax(leadingBorder.value, 0.0f);
} }
float YGNode::getTrailingBorder(const YGFlexDirection flexDirection) const { float YGNode::getTrailingBorder(const YGFlexDirection axis) const {
YGValue trailingBorder; YGValue trailingBorder = YGFlexDirectionIsRow(axis)
if (YGFlexDirectionIsRow(flexDirection) && ? computeEdgeValueForRow(
!style_.border()[YGEdgeEnd].isUndefined()) { style_.border(), YGEdgeEnd, trailing[axis], CompactValue::ofZero())
trailingBorder = style_.border()[YGEdgeEnd]; : computeEdgeValueForColumn(
if (trailingBorder.value >= 0.0f) { style_.border(), trailing[axis], CompactValue::ofZero());
return trailingBorder.value; return fmaxf(trailingBorder.value, 0.0f);
}
}
trailingBorder = YGComputedEdgeValue(
style_.border(), trailing[flexDirection], CompactValue::ofZero());
return YGFloatMax(trailingBorder.value, 0.0f);
} }
YGFloatOptional YGNode::getLeadingPadding( YGFloatOptional YGNode::getLeadingPadding(
const YGFlexDirection axis, const YGFlexDirection axis,
const float widthSize) const { const float widthSize) const {
const YGFloatOptional paddingEdgeStart = auto leadingPadding = YGFlexDirectionIsRow(axis)
YGResolveValue(style_.padding()[YGEdgeStart], widthSize); ? computeEdgeValueForRow(
if (YGFlexDirectionIsRow(axis) && style_.padding(),
!style_.padding()[YGEdgeStart].isUndefined() && YGEdgeStart,
!paddingEdgeStart.isUndefined() && paddingEdgeStart.unwrap() >= 0.0f) { leading[axis],
return paddingEdgeStart; CompactValue::ofZero())
} : computeEdgeValueForColumn(
style_.padding(), leading[axis], CompactValue::ofZero());
YGFloatOptional resolvedValue = YGResolveValue( return YGFloatOptionalMax(
YGComputedEdgeValue( YGResolveValue(leadingPadding, widthSize), YGFloatOptional(0.0f));
style_.padding(), leading[axis], CompactValue::ofZero()),
widthSize);
return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
} }
YGFloatOptional YGNode::getTrailingPadding( YGFloatOptional YGNode::getTrailingPadding(
const YGFlexDirection axis, const YGFlexDirection axis,
const float widthSize) const { const float widthSize) const {
const YGFloatOptional paddingEdgeEnd = auto trailingPadding = YGFlexDirectionIsRow(axis)
YGResolveValue(style_.padding()[YGEdgeEnd], widthSize); ? computeEdgeValueForRow(
if (YGFlexDirectionIsRow(axis) && paddingEdgeEnd >= YGFloatOptional{0.0f}) { style_.padding(), YGEdgeEnd, trailing[axis], CompactValue::ofZero())
return paddingEdgeEnd; : computeEdgeValueForColumn(
} style_.padding(), trailing[axis], CompactValue::ofZero());
return YGFloatOptionalMax(
YGFloatOptional resolvedValue = YGResolveValue( YGResolveValue(trailingPadding, widthSize), YGFloatOptional(0.0f));
YGComputedEdgeValue(
style_.padding(), trailing[axis], CompactValue::ofZero()),
widthSize);
return YGFloatOptionalMax(resolvedValue, YGFloatOptional(0.0f));
} }
YGFloatOptional YGNode::getLeadingPaddingAndBorder( YGFloatOptional YGNode::getLeadingPaddingAndBorder(
@ -536,11 +543,11 @@ bool YGNode::didUseLegacyFlag() {
void YGNode::setLayoutDoesLegacyFlagAffectsLayout( void YGNode::setLayoutDoesLegacyFlagAffectsLayout(
bool doesLegacyFlagAffectsLayout) { bool doesLegacyFlagAffectsLayout) {
layout_.doesLegacyStretchFlagAffectsLayout() = doesLegacyFlagAffectsLayout; layout_.setDoesLegacyStretchFlagAffectsLayout(doesLegacyFlagAffectsLayout);
} }
void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) { void YGNode::setLayoutDidUseLegacyFlag(bool didUseLegacyFlag) {
layout_.didUseLegacyFlag() = didUseLegacyFlag; layout_.setDidUseLegacyFlag(didUseLegacyFlag);
} }
bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const { bool YGNode::isLayoutTreeEqualToNode(const YGNode& node) const {
@ -577,7 +584,8 @@ void YGNode::reset() {
clearChildren(); clearChildren();
auto webDefaults = flags_.at<useWebDefaults_>(); auto webDefaults =
facebook::yoga::detail::getBooleanData(flags, useWebDefaults_);
*this = YGNode{getConfig()}; *this = YGNode{getConfig()};
if (webDefaults) { if (webDefaults) {
useWebDefaults(); useWebDefaults();

View File

@ -6,9 +6,12 @@
*/ */
#pragma once #pragma once
#ifdef __cplusplus
#include <cstdint> #include <cstdint>
#include <stdio.h> #include <stdio.h>
#include "Bitfield.h" #include "BitUtils.h"
#include "CompactValue.h" #include "CompactValue.h"
#include "YGConfig.h" #include "YGConfig.h"
#include "YGLayout.h" #include "YGLayout.h"
@ -35,10 +38,7 @@ private:
static constexpr size_t useWebDefaults_ = 7; static constexpr size_t useWebDefaults_ = 7;
void* context_ = nullptr; void* context_ = nullptr;
using Flags = facebook::yoga:: uint8_t flags = 1;
Bitfield<uint8_t, bool, bool, bool, YGNodeType, bool, bool, bool, bool>;
Flags flags_ =
{true, false, false, YGNodeTypeDefault, false, false, false, false};
uint8_t reserved_ = 0; uint8_t reserved_ = 0;
union { union {
YGMeasureFunc noContext; YGMeasureFunc noContext;
@ -70,13 +70,13 @@ private:
void setBaselineFunc(decltype(baseline_)); void setBaselineFunc(decltype(baseline_));
void useWebDefaults() { void useWebDefaults() {
flags_.at<useWebDefaults_>() = true; facebook::yoga::detail::setBooleanData(flags, useWebDefaults_, true);
style_.flexDirection() = YGFlexDirectionRow; style_.flexDirection() = YGFlexDirectionRow;
style_.alignContent() = YGAlignStretch; style_.alignContent() = YGAlignStretch;
} }
// DANGER DANGER DANGER! // DANGER DANGER DANGER!
// If the the node assigned to has children, we'd either have to deallocate // If the node assigned to has children, we'd either have to deallocate
// them (potentially incorrect) or ignore them (danger of leaks). Only ever // them (potentially incorrect) or ignore them (danger of leaks). Only ever
// use this after checking that there are no children. // use this after checking that there are no children.
// DO NOT CHANGE THE VISIBILITY OF THIS METHOD! // DO NOT CHANGE THE VISIBILITY OF THIS METHOD!
@ -114,9 +114,13 @@ public:
void print(void*); void print(void*);
bool getHasNewLayout() const { return flags_.at<hasNewLayout_>(); } bool getHasNewLayout() const {
return facebook::yoga::detail::getBooleanData(flags, hasNewLayout_);
}
YGNodeType getNodeType() const { return flags_.at<nodeType_>(); } YGNodeType getNodeType() const {
return facebook::yoga::detail::getEnumData<YGNodeType>(flags, nodeType_);
}
bool hasMeasureFunc() const noexcept { return measure_.noContext != nullptr; } bool hasMeasureFunc() const noexcept { return measure_.noContext != nullptr; }
@ -142,7 +146,9 @@ public:
uint32_t getLineIndex() const { return lineIndex_; } uint32_t getLineIndex() const { return lineIndex_; }
bool isReferenceBaseline() { return flags_.at<isReferenceBaseline_>(); } bool isReferenceBaseline() {
return facebook::yoga::detail::getBooleanData(flags, isReferenceBaseline_);
}
// returns the YGNodeRef that owns this YGNode. An owner is used to identify // returns the YGNodeRef that owns this YGNode. An owner is used to identify
// the YogaTree that a YGNode belongs to. This method will return the parent // the YogaTree that a YGNode belongs to. This method will return the parent
@ -175,7 +181,9 @@ public:
YGConfigRef getConfig() const { return config_; } YGConfigRef getConfig() const { return config_; }
bool isDirty() const { return flags_.at<isDirty_>(); } bool isDirty() const {
return facebook::yoga::detail::getBooleanData(flags, isDirty_);
}
std::array<YGValue, 2> getResolvedDimensions() const { std::array<YGValue, 2> getResolvedDimensions() const {
return resolvedDimensions_; return resolvedDimensions_;
@ -185,6 +193,17 @@ public:
return resolvedDimensions_[index]; return resolvedDimensions_[index];
} }
static CompactValue computeEdgeValueForColumn(
const YGStyle::Edges& edges,
YGEdge edge,
CompactValue defaultValue);
static CompactValue computeEdgeValueForRow(
const YGStyle::Edges& edges,
YGEdge rowEdge,
YGEdge edge,
CompactValue defaultValue);
// Methods related to positions, margin, padding and border // Methods related to positions, margin, padding and border
YGFloatOptional getLeadingPosition( YGFloatOptional getLeadingPosition(
const YGFlexDirection axis, const YGFlexDirection axis,
@ -223,19 +242,22 @@ public:
void setPrintFunc(YGPrintFunc printFunc) { void setPrintFunc(YGPrintFunc printFunc) {
print_.noContext = printFunc; print_.noContext = printFunc;
flags_.at<printUsesContext_>() = false; facebook::yoga::detail::setBooleanData(flags, printUsesContext_, false);
} }
void setPrintFunc(PrintWithContextFn printFunc) { void setPrintFunc(PrintWithContextFn printFunc) {
print_.withContext = printFunc; print_.withContext = printFunc;
flags_.at<printUsesContext_>() = true; facebook::yoga::detail::setBooleanData(flags, printUsesContext_, true);
} }
void setPrintFunc(std::nullptr_t) { setPrintFunc(YGPrintFunc{nullptr}); } void setPrintFunc(std::nullptr_t) { setPrintFunc(YGPrintFunc{nullptr}); }
void setHasNewLayout(bool hasNewLayout) { void setHasNewLayout(bool hasNewLayout) {
flags_.at<hasNewLayout_>() = hasNewLayout; facebook::yoga::detail::setBooleanData(flags, hasNewLayout_, hasNewLayout);
} }
void setNodeType(YGNodeType nodeType) { flags_.at<nodeType_>() = nodeType; } void setNodeType(YGNodeType nodeType) {
return facebook::yoga::detail::setEnumData<YGNodeType>(
flags, nodeType_, nodeType);
}
void setMeasureFunc(YGMeasureFunc measureFunc); void setMeasureFunc(YGMeasureFunc measureFunc);
void setMeasureFunc(MeasureWithContextFn); void setMeasureFunc(MeasureWithContextFn);
@ -244,11 +266,11 @@ public:
} }
void setBaselineFunc(YGBaselineFunc baseLineFunc) { void setBaselineFunc(YGBaselineFunc baseLineFunc) {
flags_.at<baselineUsesContext_>() = false; facebook::yoga::detail::setBooleanData(flags, baselineUsesContext_, false);
baseline_.noContext = baseLineFunc; baseline_.noContext = baseLineFunc;
} }
void setBaselineFunc(BaselineWithContextFn baseLineFunc) { void setBaselineFunc(BaselineWithContextFn baseLineFunc) {
flags_.at<baselineUsesContext_>() = true; facebook::yoga::detail::setBooleanData(flags, baselineUsesContext_, true);
baseline_.withContext = baseLineFunc; baseline_.withContext = baseLineFunc;
} }
void setBaselineFunc(std::nullptr_t) { void setBaselineFunc(std::nullptr_t) {
@ -264,7 +286,8 @@ public:
void setLineIndex(uint32_t lineIndex) { lineIndex_ = lineIndex; } void setLineIndex(uint32_t lineIndex) { lineIndex_ = lineIndex; }
void setIsReferenceBaseline(bool isReferenceBaseline) { void setIsReferenceBaseline(bool isReferenceBaseline) {
flags_.at<isReferenceBaseline_>() = isReferenceBaseline; facebook::yoga::detail::setBooleanData(
flags, isReferenceBaseline_, isReferenceBaseline);
} }
void setOwner(YGNodeRef owner) { owner_ = owner; } void setOwner(YGNodeRef owner) { owner_ = owner; }
@ -321,3 +344,5 @@ public:
bool isLayoutTreeEqualToNode(const YGNode& node) const; bool isLayoutTreeEqualToNode(const YGNode& node) const;
void reset(); void reset();
}; };
#endif

View File

@ -104,10 +104,13 @@ static void appendEdgeIfNotUndefined(
const string& str, const string& str,
const YGStyle::Edges& edges, const YGStyle::Edges& edges,
const YGEdge edge) { const YGEdge edge) {
appendNumberIfNotUndefined( // TODO: this doesn't take RTL / YGEdgeStart / YGEdgeEnd into account
base, auto value = (edge == YGEdgeLeft || edge == YGEdgeRight)
str, ? YGNode::computeEdgeValueForRow(
YGComputedEdgeValue(edges, edge, detail::CompactValue::ofUndefined())); edges, edge, edge, detail::CompactValue::ofUndefined())
: YGNode::computeEdgeValueForColumn(
edges, edge, detail::CompactValue::ofUndefined());
appendNumberIfNotUndefined(base, str, value);
} }
void YGNodeToString( void YGNodeToString(

View File

@ -6,16 +6,19 @@
*/ */
#pragma once #pragma once
#ifdef __cplusplus
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
#include "Bitfield.h"
#include "CompactValue.h" #include "CompactValue.h"
#include "YGEnums.h" #include "YGEnums.h"
#include "YGFloatOptional.h" #include "YGFloatOptional.h"
#include "Yoga-internal.h" #include "Yoga-internal.h"
#include "Yoga.h" #include "Yoga.h"
#include "BitUtils.h"
class YOGA_EXPORT YGStyle { class YOGA_EXPORT YGStyle {
template <typename Enum> template <typename Enum>
@ -27,6 +30,19 @@ public:
using Dimensions = Values<YGDimension>; using Dimensions = Values<YGDimension>;
using Edges = Values<YGEdge>; using Edges = Values<YGEdge>;
template <typename T>
struct BitfieldRef {
YGStyle& style;
size_t offset;
operator T() const {
return facebook::yoga::detail::getEnumData<T>(style.flags, offset);
}
BitfieldRef<T>& operator=(T x) {
facebook::yoga::detail::setEnumData<T>(style.flags, offset, x);
return *this;
}
};
template <typename T, T YGStyle::*Prop> template <typename T, T YGStyle::*Prop>
struct Ref { struct Ref {
YGStyle& style; YGStyle& style;
@ -60,43 +76,35 @@ public:
CompactValue operator[](Idx idx) const { return (style.*Prop)[idx]; } CompactValue operator[](Idx idx) const { return (style.*Prop)[idx]; }
}; };
YGStyle() = default; YGStyle() {
alignContent() = YGAlignFlexStart;
alignItems() = YGAlignStretch;
}
~YGStyle() = default; ~YGStyle() = default;
private: private:
static constexpr size_t directionIdx = 0; static constexpr size_t directionOffset = 0;
static constexpr size_t flexDirectionIdx = 1; static constexpr size_t flexdirectionOffset =
static constexpr size_t justifyContentIdx = 2; directionOffset + facebook::yoga::detail::bitWidthFn<YGDirection>();
static constexpr size_t alignContentIdx = 3; static constexpr size_t justifyContentOffset = flexdirectionOffset +
static constexpr size_t alignItemsIdx = 4; facebook::yoga::detail::bitWidthFn<YGFlexDirection>();
static constexpr size_t alignSelfIdx = 5; static constexpr size_t alignContentOffset =
static constexpr size_t positionTypeIdx = 6; justifyContentOffset + facebook::yoga::detail::bitWidthFn<YGJustify>();
static constexpr size_t flexWrapIdx = 7; static constexpr size_t alignItemsOffset =
static constexpr size_t overflowIdx = 8; alignContentOffset + facebook::yoga::detail::bitWidthFn<YGAlign>();
static constexpr size_t displayIdx = 9; static constexpr size_t alignSelfOffset =
using Flags = facebook::yoga::Bitfield< alignItemsOffset + facebook::yoga::detail::bitWidthFn<YGAlign>();
uint32_t, static constexpr size_t positionTypeOffset =
YGDirection, alignSelfOffset + facebook::yoga::detail::bitWidthFn<YGAlign>();
YGFlexDirection, static constexpr size_t flexWrapOffset =
YGJustify, positionTypeOffset + facebook::yoga::detail::bitWidthFn<YGPositionType>();
YGAlign, static constexpr size_t overflowOffset =
YGAlign, flexWrapOffset + facebook::yoga::detail::bitWidthFn<YGWrap>();
YGAlign, static constexpr size_t displayOffset =
YGPositionType, overflowOffset + facebook::yoga::detail::bitWidthFn<YGOverflow>();
YGWrap,
YGOverflow, uint32_t flags = 0;
YGDisplay>;
Flags flags_ = {YGDirectionInherit,
YGFlexDirectionColumn,
YGJustifyFlexStart,
YGAlignFlexStart,
YGAlignStretch,
YGAlignAuto,
YGPositionTypeRelative,
YGWrapNoWrap,
YGOverflowVisible,
YGDisplayFlex};
YGFloatOptional flex_ = {}; YGFloatOptional flex_ = {};
YGFloatOptional flexGrow_ = {}; YGFloatOptional flexGrow_ = {};
YGFloatOptional flexShrink_ = {}; YGFloatOptional flexShrink_ = {};
@ -115,45 +123,68 @@ public:
// for library users needing a type // for library users needing a type
using ValueRepr = std::remove_reference<decltype(margin_[0])>::type; using ValueRepr = std::remove_reference<decltype(margin_[0])>::type;
YGDirection direction() const { return flags_.at<directionIdx>(); } YGDirection direction() const {
Flags::Ref<directionIdx> direction() { return flags_.at<directionIdx>(); } return facebook::yoga::detail::getEnumData<YGDirection>(
flags, directionOffset);
}
BitfieldRef<YGDirection> direction() { return {*this, directionOffset}; }
YGFlexDirection flexDirection() const { YGFlexDirection flexDirection() const {
return flags_.at<flexDirectionIdx>(); return facebook::yoga::detail::getEnumData<YGFlexDirection>(
flags, flexdirectionOffset);
} }
Flags::Ref<flexDirectionIdx> flexDirection() { BitfieldRef<YGFlexDirection> flexDirection() {
return flags_.at<flexDirectionIdx>(); return {*this, flexdirectionOffset};
} }
YGJustify justifyContent() const { return flags_.at<justifyContentIdx>(); } YGJustify justifyContent() const {
Flags::Ref<justifyContentIdx> justifyContent() { return facebook::yoga::detail::getEnumData<YGJustify>(
return flags_.at<justifyContentIdx>(); flags, justifyContentOffset);
}
BitfieldRef<YGJustify> justifyContent() {
return {*this, justifyContentOffset};
} }
YGAlign alignContent() const { return flags_.at<alignContentIdx>(); } YGAlign alignContent() const {
Flags::Ref<alignContentIdx> alignContent() { return facebook::yoga::detail::getEnumData<YGAlign>(
return flags_.at<alignContentIdx>(); flags, alignContentOffset);
}
BitfieldRef<YGAlign> alignContent() { return {*this, alignContentOffset}; }
YGAlign alignItems() const {
return facebook::yoga::detail::getEnumData<YGAlign>(
flags, alignItemsOffset);
}
BitfieldRef<YGAlign> alignItems() { return {*this, alignItemsOffset}; }
YGAlign alignSelf() const {
return facebook::yoga::detail::getEnumData<YGAlign>(flags, alignSelfOffset);
}
BitfieldRef<YGAlign> alignSelf() { return {*this, alignSelfOffset}; }
YGPositionType positionType() const {
return facebook::yoga::detail::getEnumData<YGPositionType>(
flags, positionTypeOffset);
}
BitfieldRef<YGPositionType> positionType() {
return {*this, positionTypeOffset};
} }
YGAlign alignItems() const { return flags_.at<alignItemsIdx>(); } YGWrap flexWrap() const {
Flags::Ref<alignItemsIdx> alignItems() { return flags_.at<alignItemsIdx>(); } return facebook::yoga::detail::getEnumData<YGWrap>(flags, flexWrapOffset);
YGAlign alignSelf() const { return flags_.at<alignSelfIdx>(); }
Flags::Ref<alignSelfIdx> alignSelf() { return flags_.at<alignSelfIdx>(); }
YGPositionType positionType() const { return flags_.at<positionTypeIdx>(); }
Flags::Ref<positionTypeIdx> positionType() {
return flags_.at<positionTypeIdx>();
} }
BitfieldRef<YGWrap> flexWrap() { return {*this, flexWrapOffset}; }
YGWrap flexWrap() const { return flags_.at<flexWrapIdx>(); } YGOverflow overflow() const {
Flags::Ref<flexWrapIdx> flexWrap() { return flags_.at<flexWrapIdx>(); } return facebook::yoga::detail::getEnumData<YGOverflow>(
flags, overflowOffset);
}
BitfieldRef<YGOverflow> overflow() { return {*this, overflowOffset}; }
YGOverflow overflow() const { return flags_.at<overflowIdx>(); } YGDisplay display() const {
Flags::Ref<overflowIdx> overflow() { return flags_.at<overflowIdx>(); } return facebook::yoga::detail::getEnumData<YGDisplay>(flags, displayOffset);
}
YGDisplay display() const { return flags_.at<displayIdx>(); } BitfieldRef<YGDisplay> display() { return {*this, displayOffset}; }
Flags::Ref<displayIdx> display() { return flags_.at<displayIdx>(); }
YGFloatOptional flex() const { return flex_; } YGFloatOptional flex() const { return flex_; }
Ref<YGFloatOptional, &YGStyle::flex_> flex() { return {*this}; } Ref<YGFloatOptional, &YGStyle::flex_> flex() { return {*this}; }
@ -201,3 +232,5 @@ YOGA_EXPORT bool operator==(const YGStyle& lhs, const YGStyle& rhs);
YOGA_EXPORT inline bool operator!=(const YGStyle& lhs, const YGStyle& rhs) { YOGA_EXPORT inline bool operator!=(const YGStyle& lhs, const YGStyle& rhs) {
return !(lhs == rhs); return !(lhs == rhs);
} }
#endif

View File

@ -11,6 +11,13 @@
#include "YGEnums.h" #include "YGEnums.h"
#include "YGMacros.h" #include "YGMacros.h"
#if defined(_MSC_VER) && defined(__clang__)
#define COMPILING_WITH_CLANG_ON_WINDOWS
#endif
#if defined(COMPILING_WITH_CLANG_ON_WINDOWS)
#include <limits>
constexpr float YGUndefined = std::numeric_limits<float>::quiet_NaN();
#else
YG_EXTERN_C_BEGIN YG_EXTERN_C_BEGIN
// Not defined in MSVC++ // Not defined in MSVC++
@ -20,6 +27,7 @@ static const uint32_t __nan = 0x7fc00000;
#endif #endif
#define YGUndefined NAN #define YGUndefined NAN
#endif
typedef struct YGValue { typedef struct YGValue {
float value; float value;
@ -30,7 +38,10 @@ YOGA_EXPORT extern const YGValue YGValueAuto;
YOGA_EXPORT extern const YGValue YGValueUndefined; YOGA_EXPORT extern const YGValue YGValueUndefined;
YOGA_EXPORT extern const YGValue YGValueZero; YOGA_EXPORT extern const YGValue YGValueZero;
#if !defined(COMPILING_WITH_CLANG_ON_WINDOWS)
YG_EXTERN_C_END YG_EXTERN_C_END
#endif
#undef COMPILING_WITH_CLANG_ON_WINDOWS
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -33,6 +33,10 @@ inline bool isUndefined(float value) {
return std::isnan(value); return std::isnan(value);
} }
inline bool isUndefined(double value) {
return std::isnan(value);
}
} // namespace yoga } // namespace yoga
} // namespace facebook } // namespace facebook
@ -54,10 +58,10 @@ struct YGCachedMeasurement {
float computedHeight; float computedHeight;
YGCachedMeasurement() YGCachedMeasurement()
: availableWidth(0), : availableWidth(-1),
availableHeight(0), availableHeight(-1),
widthMeasureMode((YGMeasureMode) -1), widthMeasureMode(YGMeasureModeUndefined),
heightMeasureMode((YGMeasureMode) -1), heightMeasureMode(YGMeasureModeUndefined),
computedWidth(-1), computedWidth(-1),
computedHeight(-1) {} computedHeight(-1) {}
@ -144,8 +148,3 @@ static const float kDefaultFlexShrink = 0.0f;
static const float kWebDefaultFlexShrink = 1.0f; static const float kWebDefaultFlexShrink = 1.0f;
extern bool YGFloatsEqual(const float a, const float b); extern bool YGFloatsEqual(const float a, const float b);
extern facebook::yoga::detail::CompactValue YGComputedEdgeValue(
const facebook::yoga::detail::Values<
facebook::yoga::enums::count<YGEdge>()>& edges,
YGEdge edge,
facebook::yoga::detail::CompactValue defaultValue);

View File

@ -106,38 +106,12 @@ static int YGDefaultLog(
#undef YG_UNUSED #undef YG_UNUSED
#endif #endif
YOGA_EXPORT bool YGFloatIsUndefined(const float value) { static inline bool YGDoubleIsUndefined(const double value) {
return facebook::yoga::isUndefined(value); return facebook::yoga::isUndefined(value);
} }
detail::CompactValue YGComputedEdgeValue( YOGA_EXPORT bool YGFloatIsUndefined(const float value) {
const YGStyle::Edges& edges, return facebook::yoga::isUndefined(value);
YGEdge edge,
detail::CompactValue defaultValue) {
if (!edges[edge].isUndefined()) {
return edges[edge];
}
if ((edge == YGEdgeTop || edge == YGEdgeBottom) &&
!edges[YGEdgeVertical].isUndefined()) {
return edges[YGEdgeVertical];
}
if ((edge == YGEdgeLeft || edge == YGEdgeRight || edge == YGEdgeStart ||
edge == YGEdgeEnd) &&
!edges[YGEdgeHorizontal].isUndefined()) {
return edges[YGEdgeHorizontal];
}
if (!edges[YGEdgeAll].isUndefined()) {
return edges[YGEdgeAll];
}
if (edge == YGEdgeStart || edge == YGEdgeEnd) {
return detail::CompactValue::ofUndefined();
}
return defaultValue;
} }
YOGA_EXPORT void* YGNodeGetContext(YGNodeRef node) { YOGA_EXPORT void* YGNodeGetContext(YGNodeRef node) {
@ -249,9 +223,6 @@ YOGA_EXPORT YGNodeRef YGNodeClone(YGNodeRef oldNode) {
static YGConfigRef YGConfigClone(const YGConfig& oldConfig) { static YGConfigRef YGConfigClone(const YGConfig& oldConfig) {
const YGConfigRef config = new YGConfig(oldConfig); const YGConfigRef config = new YGConfig(oldConfig);
YGAssert(config != nullptr, "Could not allocate memory for config"); YGAssert(config != nullptr, "Could not allocate memory for config");
if (config == nullptr) {
abort();
}
gConfigInstanceCount++; gConfigInstanceCount++;
return config; return config;
} }
@ -386,6 +357,14 @@ YOGA_EXPORT void YGNodeInsertChild(
owner->markDirtyAndPropogate(); owner->markDirtyAndPropogate();
} }
YOGA_EXPORT void YGNodeSwapChild(
const YGNodeRef owner,
const YGNodeRef child,
const uint32_t index) {
owner->replaceChild(child, index);
child->setOwner(owner);
}
YOGA_EXPORT void YGNodeRemoveChild( YOGA_EXPORT void YGNodeRemoveChild(
const YGNodeRef owner, const YGNodeRef owner,
const YGNodeRef excludedChild) { const YGNodeRef excludedChild) {
@ -1126,7 +1105,7 @@ static bool YGIsBaselineLayout(const YGNodeRef node) {
const uint32_t childCount = YGNodeGetChildCount(node); const uint32_t childCount = YGNodeGetChildCount(node);
for (uint32_t i = 0; i < childCount; i++) { for (uint32_t i = 0; i < childCount; i++) {
const YGNodeRef child = YGNodeGetChild(node, i); const YGNodeRef child = YGNodeGetChild(node, i);
if (child->getStyle().positionType() == YGPositionTypeRelative && if (child->getStyle().positionType() != YGPositionTypeAbsolute &&
child->getStyle().alignSelf() == YGAlignBaseline) { child->getStyle().alignSelf() == YGAlignBaseline) {
return true; return true;
} }
@ -1655,8 +1634,8 @@ static void YGNodeAbsoluteLayoutChild(
static void YGNodeWithMeasureFuncSetMeasuredDimensions( static void YGNodeWithMeasureFuncSetMeasuredDimensions(
const YGNodeRef node, const YGNodeRef node,
const float availableWidth, float availableWidth,
const float availableHeight, float availableHeight,
const YGMeasureMode widthMeasureMode, const YGMeasureMode widthMeasureMode,
const YGMeasureMode heightMeasureMode, const YGMeasureMode heightMeasureMode,
const float ownerWidth, const float ownerWidth,
@ -1669,40 +1648,40 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(
node->hasMeasureFunc(), node->hasMeasureFunc(),
"Expected node to have custom measure function"); "Expected node to have custom measure function");
const float paddingAndBorderAxisRow = if (widthMeasureMode == YGMeasureModeUndefined) {
YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, availableWidth); availableWidth = YGUndefined;
const float paddingAndBorderAxisColumn = YGNodePaddingAndBorderForAxis( }
node, YGFlexDirectionColumn, availableWidth); if (heightMeasureMode == YGMeasureModeUndefined) {
const float marginAxisRow = availableHeight = YGUndefined;
node->getMarginForAxis(YGFlexDirectionRow, availableWidth).unwrap(); }
const float marginAxisColumn =
node->getMarginForAxis(YGFlexDirectionColumn, availableWidth).unwrap(); const auto& padding = node->getLayout().padding;
const auto& border = node->getLayout().border;
const float paddingAndBorderAxisRow = padding[YGEdgeLeft] +
padding[YGEdgeRight] + border[YGEdgeLeft] + border[YGEdgeRight];
const float paddingAndBorderAxisColumn = padding[YGEdgeTop] +
padding[YGEdgeBottom] + border[YGEdgeTop] + border[YGEdgeBottom];
// We want to make sure we don't call measure with negative size // We want to make sure we don't call measure with negative size
const float innerWidth = YGFloatIsUndefined(availableWidth) const float innerWidth = YGFloatIsUndefined(availableWidth)
? availableWidth ? availableWidth
: YGFloatMax(0, availableWidth - marginAxisRow - paddingAndBorderAxisRow); : YGFloatMax(0, availableWidth - paddingAndBorderAxisRow);
const float innerHeight = YGFloatIsUndefined(availableHeight) const float innerHeight = YGFloatIsUndefined(availableHeight)
? availableHeight ? availableHeight
: YGFloatMax( : YGFloatMax(0, availableHeight - paddingAndBorderAxisColumn);
0, availableHeight - marginAxisColumn - paddingAndBorderAxisColumn);
if (widthMeasureMode == YGMeasureModeExactly && if (widthMeasureMode == YGMeasureModeExactly &&
heightMeasureMode == YGMeasureModeExactly) { heightMeasureMode == YGMeasureModeExactly) {
// Don't bother sizing the text if both dimensions are already defined. // Don't bother sizing the text if both dimensions are already defined.
node->setLayoutMeasuredDimension( node->setLayoutMeasuredDimension(
YGNodeBoundAxis( YGNodeBoundAxis(
node, node, YGFlexDirectionRow, availableWidth, ownerWidth, ownerWidth),
YGFlexDirectionRow,
availableWidth - marginAxisRow,
ownerWidth,
ownerWidth),
YGDimensionWidth); YGDimensionWidth);
node->setLayoutMeasuredDimension( node->setLayoutMeasuredDimension(
YGNodeBoundAxis( YGNodeBoundAxis(
node, node,
YGFlexDirectionColumn, YGFlexDirectionColumn,
availableHeight - marginAxisColumn, availableHeight,
ownerHeight, ownerHeight,
ownerWidth), ownerWidth),
YGDimensionHeight); YGDimensionHeight);
@ -1739,7 +1718,7 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(
(widthMeasureMode == YGMeasureModeUndefined || (widthMeasureMode == YGMeasureModeUndefined ||
widthMeasureMode == YGMeasureModeAtMost) widthMeasureMode == YGMeasureModeAtMost)
? measuredSize.width + paddingAndBorderAxisRow ? measuredSize.width + paddingAndBorderAxisRow
: availableWidth - marginAxisRow, : availableWidth,
ownerWidth, ownerWidth,
ownerWidth), ownerWidth),
YGDimensionWidth); YGDimensionWidth);
@ -1751,7 +1730,7 @@ static void YGNodeWithMeasureFuncSetMeasuredDimensions(
(heightMeasureMode == YGMeasureModeUndefined || (heightMeasureMode == YGMeasureModeUndefined ||
heightMeasureMode == YGMeasureModeAtMost) heightMeasureMode == YGMeasureModeAtMost)
? measuredSize.height + paddingAndBorderAxisColumn ? measuredSize.height + paddingAndBorderAxisColumn
: availableHeight - marginAxisColumn, : availableHeight,
ownerHeight, ownerHeight,
ownerWidth), ownerWidth),
YGDimensionHeight); YGDimensionHeight);
@ -1768,37 +1747,28 @@ static void YGNodeEmptyContainerSetMeasuredDimensions(
const YGMeasureMode heightMeasureMode, const YGMeasureMode heightMeasureMode,
const float ownerWidth, const float ownerWidth,
const float ownerHeight) { const float ownerHeight) {
const float paddingAndBorderAxisRow = const auto& padding = node->getLayout().padding;
YGNodePaddingAndBorderForAxis(node, YGFlexDirectionRow, ownerWidth); const auto& border = node->getLayout().border;
const float paddingAndBorderAxisColumn =
YGNodePaddingAndBorderForAxis(node, YGFlexDirectionColumn, ownerWidth);
const float marginAxisRow =
node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
const float marginAxisColumn =
node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
float width = availableWidth;
if (widthMeasureMode == YGMeasureModeUndefined ||
widthMeasureMode == YGMeasureModeAtMost) {
width = padding[YGEdgeLeft] + padding[YGEdgeRight] + border[YGEdgeLeft] +
border[YGEdgeRight];
}
node->setLayoutMeasuredDimension( node->setLayoutMeasuredDimension(
YGNodeBoundAxis( YGNodeBoundAxis(node, YGFlexDirectionRow, width, ownerWidth, ownerWidth),
node,
YGFlexDirectionRow,
(widthMeasureMode == YGMeasureModeUndefined ||
widthMeasureMode == YGMeasureModeAtMost)
? paddingAndBorderAxisRow
: availableWidth - marginAxisRow,
ownerWidth,
ownerWidth),
YGDimensionWidth); YGDimensionWidth);
float height = availableHeight;
if (heightMeasureMode == YGMeasureModeUndefined ||
heightMeasureMode == YGMeasureModeAtMost) {
height = padding[YGEdgeTop] + padding[YGEdgeBottom] + border[YGEdgeTop] +
border[YGEdgeBottom];
}
node->setLayoutMeasuredDimension( node->setLayoutMeasuredDimension(
YGNodeBoundAxis( YGNodeBoundAxis(
node, node, YGFlexDirectionColumn, height, ownerHeight, ownerWidth),
YGFlexDirectionColumn,
(heightMeasureMode == YGMeasureModeUndefined ||
heightMeasureMode == YGMeasureModeAtMost)
? paddingAndBorderAxisColumn
: availableHeight - marginAxisColumn,
ownerHeight,
ownerWidth),
YGDimensionHeight); YGDimensionHeight);
} }
@ -1816,11 +1786,6 @@ static bool YGNodeFixedSizeSetMeasuredDimensions(
heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) || heightMeasureMode == YGMeasureModeAtMost && availableHeight <= 0.0f) ||
(widthMeasureMode == YGMeasureModeExactly && (widthMeasureMode == YGMeasureModeExactly &&
heightMeasureMode == YGMeasureModeExactly)) { heightMeasureMode == YGMeasureModeExactly)) {
auto marginAxisColumn =
node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
auto marginAxisRow =
node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
node->setLayoutMeasuredDimension( node->setLayoutMeasuredDimension(
YGNodeBoundAxis( YGNodeBoundAxis(
node, node,
@ -1829,7 +1794,7 @@ static bool YGNodeFixedSizeSetMeasuredDimensions(
(widthMeasureMode == YGMeasureModeAtMost && (widthMeasureMode == YGMeasureModeAtMost &&
availableWidth < 0.0f) availableWidth < 0.0f)
? 0.0f ? 0.0f
: availableWidth - marginAxisRow, : availableWidth,
ownerWidth, ownerWidth,
ownerWidth), ownerWidth),
YGDimensionWidth); YGDimensionWidth);
@ -1842,7 +1807,7 @@ static bool YGNodeFixedSizeSetMeasuredDimensions(
(heightMeasureMode == YGMeasureModeAtMost && (heightMeasureMode == YGMeasureModeAtMost &&
availableHeight < 0.0f) availableHeight < 0.0f)
? 0.0f ? 0.0f
: availableHeight - marginAxisColumn, : availableHeight,
ownerHeight, ownerHeight,
ownerWidth), ownerWidth),
YGDimensionHeight); YGDimensionHeight);
@ -1866,19 +1831,11 @@ static void YGZeroOutLayoutRecursivly(
static float YGNodeCalculateAvailableInnerDim( static float YGNodeCalculateAvailableInnerDim(
const YGNodeConstRef node, const YGNodeConstRef node,
YGFlexDirection axis, const YGDimension dimension,
float availableDim, const float availableDim,
float ownerDim) { const float paddingAndBorder,
YGFlexDirection direction = const float ownerDim) {
YGFlexDirectionIsRow(axis) ? YGFlexDirectionRow : YGFlexDirectionColumn; float availableInnerDim = availableDim - paddingAndBorder;
YGDimension dimension =
YGFlexDirectionIsRow(axis) ? YGDimensionWidth : YGDimensionHeight;
const float margin = node->getMarginForAxis(direction, ownerDim).unwrap();
const float paddingAndBorder =
YGNodePaddingAndBorderForAxis(node, direction, ownerDim);
float availableInnerDim = availableDim - margin - paddingAndBorder;
// Max dimension overrides predefined dimension value; Min dimension in turn // Max dimension overrides predefined dimension value; Min dimension in turn
// overrides both of the above // overrides both of the above
if (!YGFloatIsUndefined(availableInnerDim)) { if (!YGFloatIsUndefined(availableInnerDim)) {
@ -2328,7 +2285,8 @@ static void YGDistributeFreeSpaceFirstPass(
// first and second passes. // first and second passes.
deltaFreeSpace += boundMainSize - childFlexBasis; deltaFreeSpace += boundMainSize - childFlexBasis;
collectedFlexItemsValues.totalFlexShrinkScaledFactors -= collectedFlexItemsValues.totalFlexShrinkScaledFactors -=
flexShrinkScaledFactor; (-currentRelativeChild->resolveFlexShrink() *
currentRelativeChild->getLayout().computedFlexBasis.unwrap());
} }
} }
} else if ( } else if (
@ -2490,7 +2448,7 @@ static void YGJustifyMainAxis(
i < collectedFlexItemsValues.endOfLineIndex; i < collectedFlexItemsValues.endOfLineIndex;
i++) { i++) {
const YGNodeRef child = node->getChild(i); const YGNodeRef child = node->getChild(i);
if (child->getStyle().positionType() == YGPositionTypeRelative) { if (child->getStyle().positionType() != YGPositionTypeAbsolute) {
if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) { if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
numberOfAutoMarginsOnCurrentLine++; numberOfAutoMarginsOnCurrentLine++;
} }
@ -2574,7 +2532,7 @@ static void YGJustifyMainAxis(
// Now that we placed the element, we need to update the variables. // 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 // We need to do that only for relative elements. Absolute elements do not
// take part in that phase. // take part in that phase.
if (childStyle.positionType() == YGPositionTypeRelative) { if (childStyle.positionType() != YGPositionTypeAbsolute) {
if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) { if (child->marginLeadingValue(mainAxis).unit == YGUnitAuto) {
collectedFlexItemsValues.mainDim += collectedFlexItemsValues.mainDim +=
collectedFlexItemsValues.remainingFreeSpace / collectedFlexItemsValues.remainingFreeSpace /
@ -2764,16 +2722,22 @@ static void YGNodelayoutImpl(
const YGEdge startEdge = const YGEdge startEdge =
direction == YGDirectionLTR ? YGEdgeLeft : YGEdgeRight; direction == YGDirectionLTR ? YGEdgeLeft : YGEdgeRight;
const YGEdge endEdge = direction == YGDirectionLTR ? YGEdgeRight : YGEdgeLeft; const YGEdge endEdge = direction == YGDirectionLTR ? YGEdgeRight : YGEdgeLeft;
node->setLayoutMargin(
node->getLeadingMargin(flexRowDirection, ownerWidth).unwrap(), startEdge); const float marginRowLeading =
node->setLayoutMargin( node->getLeadingMargin(flexRowDirection, ownerWidth).unwrap();
node->getTrailingMargin(flexRowDirection, ownerWidth).unwrap(), endEdge); node->setLayoutMargin(marginRowLeading, startEdge);
node->setLayoutMargin( const float marginRowTrailing =
node->getLeadingMargin(flexColumnDirection, ownerWidth).unwrap(), node->getTrailingMargin(flexRowDirection, ownerWidth).unwrap();
YGEdgeTop); node->setLayoutMargin(marginRowTrailing, endEdge);
node->setLayoutMargin( const float marginColumnLeading =
node->getTrailingMargin(flexColumnDirection, ownerWidth).unwrap(), node->getLeadingMargin(flexColumnDirection, ownerWidth).unwrap();
YGEdgeBottom); node->setLayoutMargin(marginColumnLeading, YGEdgeTop);
const float marginColumnTrailing =
node->getTrailingMargin(flexColumnDirection, ownerWidth).unwrap();
node->setLayoutMargin(marginColumnTrailing, YGEdgeBottom);
const float marginAxisRow = marginRowLeading + marginRowTrailing;
const float marginAxisColumn = marginColumnLeading + marginColumnTrailing;
node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), startEdge); node->setLayoutBorder(node->getLeadingBorder(flexRowDirection), startEdge);
node->setLayoutBorder(node->getTrailingBorder(flexRowDirection), endEdge); node->setLayoutBorder(node->getTrailingBorder(flexRowDirection), endEdge);
@ -2796,8 +2760,8 @@ static void YGNodelayoutImpl(
if (node->hasMeasureFunc()) { if (node->hasMeasureFunc()) {
YGNodeWithMeasureFuncSetMeasuredDimensions( YGNodeWithMeasureFuncSetMeasuredDimensions(
node, node,
availableWidth, availableWidth - marginAxisRow,
availableHeight, availableHeight - marginAxisColumn,
widthMeasureMode, widthMeasureMode,
heightMeasureMode, heightMeasureMode,
ownerWidth, ownerWidth,
@ -2812,8 +2776,8 @@ static void YGNodelayoutImpl(
if (childCount == 0) { if (childCount == 0) {
YGNodeEmptyContainerSetMeasuredDimensions( YGNodeEmptyContainerSetMeasuredDimensions(
node, node,
availableWidth, availableWidth - marginAxisRow,
availableHeight, availableHeight - marginAxisColumn,
widthMeasureMode, widthMeasureMode,
heightMeasureMode, heightMeasureMode,
ownerWidth, ownerWidth,
@ -2826,8 +2790,8 @@ static void YGNodelayoutImpl(
if (!performLayout && if (!performLayout &&
YGNodeFixedSizeSetMeasuredDimensions( YGNodeFixedSizeSetMeasuredDimensions(
node, node,
availableWidth, availableWidth - marginAxisRow,
availableHeight, availableHeight - marginAxisColumn,
widthMeasureMode, widthMeasureMode,
heightMeasureMode, heightMeasureMode,
ownerWidth, ownerWidth,
@ -2851,12 +2815,14 @@ static void YGNodelayoutImpl(
const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight; const float mainAxisownerSize = isMainAxisRow ? ownerWidth : ownerHeight;
const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth; const float crossAxisownerSize = isMainAxisRow ? ownerHeight : ownerWidth;
const float leadingPaddingAndBorderCross =
node->getLeadingPaddingAndBorder(crossAxis, ownerWidth).unwrap();
const float paddingAndBorderAxisMain = const float paddingAndBorderAxisMain =
YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth); YGNodePaddingAndBorderForAxis(node, mainAxis, ownerWidth);
const float leadingPaddingAndBorderCross =
node->getLeadingPaddingAndBorder(crossAxis, ownerWidth).unwrap();
const float trailingPaddingAndBorderCross =
node->getTrailingPaddingAndBorder(crossAxis, ownerWidth).unwrap();
const float paddingAndBorderAxisCross = const float paddingAndBorderAxisCross =
YGNodePaddingAndBorderForAxis(node, crossAxis, ownerWidth); leadingPaddingAndBorderCross + trailingPaddingAndBorderCross;
YGMeasureMode measureModeMainDim = YGMeasureMode measureModeMainDim =
isMainAxisRow ? widthMeasureMode : heightMeasureMode; isMainAxisRow ? widthMeasureMode : heightMeasureMode;
@ -2868,35 +2834,20 @@ static void YGNodelayoutImpl(
const float paddingAndBorderAxisColumn = const float paddingAndBorderAxisColumn =
isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain; isMainAxisRow ? paddingAndBorderAxisCross : paddingAndBorderAxisMain;
const float marginAxisRow =
node->getMarginForAxis(YGFlexDirectionRow, ownerWidth).unwrap();
const float marginAxisColumn =
node->getMarginForAxis(YGFlexDirectionColumn, ownerWidth).unwrap();
const auto& minDimensions = node->getStyle().minDimensions();
const auto& maxDimensions = node->getStyle().maxDimensions();
const float minInnerWidth =
YGResolveValue(minDimensions[YGDimensionWidth], ownerWidth).unwrap() -
paddingAndBorderAxisRow;
const float maxInnerWidth =
YGResolveValue(maxDimensions[YGDimensionWidth], ownerWidth).unwrap() -
paddingAndBorderAxisRow;
const float minInnerHeight =
YGResolveValue(minDimensions[YGDimensionHeight], ownerHeight).unwrap() -
paddingAndBorderAxisColumn;
const float maxInnerHeight =
YGResolveValue(maxDimensions[YGDimensionHeight], ownerHeight).unwrap() -
paddingAndBorderAxisColumn;
const float minInnerMainDim = isMainAxisRow ? minInnerWidth : minInnerHeight;
const float maxInnerMainDim = isMainAxisRow ? maxInnerWidth : maxInnerHeight;
// STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS // STEP 2: DETERMINE AVAILABLE SIZE IN MAIN AND CROSS DIRECTIONS
float availableInnerWidth = YGNodeCalculateAvailableInnerDim( float availableInnerWidth = YGNodeCalculateAvailableInnerDim(
node, YGFlexDirectionRow, availableWidth, ownerWidth); node,
YGDimensionWidth,
availableWidth - marginAxisRow,
paddingAndBorderAxisRow,
ownerWidth);
float availableInnerHeight = YGNodeCalculateAvailableInnerDim( float availableInnerHeight = YGNodeCalculateAvailableInnerDim(
node, YGFlexDirectionColumn, availableHeight, ownerHeight); node,
YGDimensionHeight,
availableHeight - marginAxisColumn,
paddingAndBorderAxisColumn,
ownerHeight);
float availableInnerMainDim = float availableInnerMainDim =
isMainAxisRow ? availableInnerWidth : availableInnerHeight; isMainAxisRow ? availableInnerWidth : availableInnerHeight;
@ -2968,6 +2919,28 @@ static void YGNodelayoutImpl(
// If we don't measure with exact main dimension we want to ensure we don't // If we don't measure with exact main dimension we want to ensure we don't
// violate min and max // violate min and max
if (measureModeMainDim != YGMeasureModeExactly) { if (measureModeMainDim != YGMeasureModeExactly) {
const auto& minDimensions = node->getStyle().minDimensions();
const auto& maxDimensions = node->getStyle().maxDimensions();
const float minInnerWidth =
YGResolveValue(minDimensions[YGDimensionWidth], ownerWidth).unwrap() -
paddingAndBorderAxisRow;
const float maxInnerWidth =
YGResolveValue(maxDimensions[YGDimensionWidth], ownerWidth).unwrap() -
paddingAndBorderAxisRow;
const float minInnerHeight =
YGResolveValue(minDimensions[YGDimensionHeight], ownerHeight)
.unwrap() -
paddingAndBorderAxisColumn;
const float maxInnerHeight =
YGResolveValue(maxDimensions[YGDimensionHeight], ownerHeight)
.unwrap() -
paddingAndBorderAxisColumn;
const float minInnerMainDim =
isMainAxisRow ? minInnerWidth : minInnerHeight;
const float maxInnerMainDim =
isMainAxisRow ? maxInnerWidth : maxInnerHeight;
if (!YGFloatIsUndefined(minInnerMainDim) && if (!YGFloatIsUndefined(minInnerMainDim) &&
collectedFlexItemsValues.sizeConsumedOnCurrentLine < collectedFlexItemsValues.sizeConsumedOnCurrentLine <
minInnerMainDim) { minInnerMainDim) {
@ -3296,7 +3269,7 @@ static void YGNodelayoutImpl(
if (child->getStyle().display() == YGDisplayNone) { if (child->getStyle().display() == YGDisplayNone) {
continue; continue;
} }
if (child->getStyle().positionType() == YGPositionTypeRelative) { if (child->getStyle().positionType() != YGPositionTypeAbsolute) {
if (child->getLineIndex() != i) { if (child->getLineIndex() != i) {
break; break;
} }
@ -3338,7 +3311,7 @@ static void YGNodelayoutImpl(
if (child->getStyle().display() == YGDisplayNone) { if (child->getStyle().display() == YGDisplayNone) {
continue; continue;
} }
if (child->getStyle().positionType() == YGPositionTypeRelative) { if (child->getStyle().positionType() != YGPositionTypeAbsolute) {
switch (YGNodeAlignItem(node, child)) { switch (YGNodeAlignItem(node, child)) {
case YGAlignFlexStart: { case YGAlignFlexStart: {
child->setLayoutPosition( child->setLayoutPosition(
@ -3516,8 +3489,8 @@ static void YGNodelayoutImpl(
YGNodeBoundAxisWithinMinAndMax( YGNodeBoundAxisWithinMinAndMax(
node, node,
crossAxis, crossAxis,
YGFloatOptional{totalLineCrossDim + YGFloatOptional{
paddingAndBorderAxisCross}, totalLineCrossDim + paddingAndBorderAxisCross},
crossAxisownerSize) crossAxisownerSize)
.unwrap()), .unwrap()),
paddingAndBorderAxisCross), paddingAndBorderAxisCross),
@ -3529,7 +3502,7 @@ static void YGNodelayoutImpl(
if (performLayout && node->getStyle().flexWrap() == YGWrapWrapReverse) { if (performLayout && node->getStyle().flexWrap() == YGWrapWrapReverse) {
for (uint32_t i = 0; i < childCount; i++) { for (uint32_t i = 0; i < childCount; i++) {
const YGNodeRef child = YGNodeGetChild(node, i); const YGNodeRef child = YGNodeGetChild(node, i);
if (child->getStyle().positionType() == YGPositionTypeRelative) { if (child->getStyle().positionType() != YGPositionTypeAbsolute) {
child->setLayoutPosition( child->setLayoutPosition(
node->getLayout().measuredDimensions[dim[crossAxis]] - node->getLayout().measuredDimensions[dim[crossAxis]] -
child->getLayout().position[pos[crossAxis]] - child->getLayout().position[pos[crossAxis]] -
@ -3542,7 +3515,8 @@ static void YGNodelayoutImpl(
if (performLayout) { if (performLayout) {
// STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN // STEP 10: SIZING AND POSITIONING ABSOLUTE CHILDREN
for (auto child : node->getChildren()) { for (auto child : node->getChildren()) {
if (child->getStyle().positionType() != YGPositionTypeAbsolute) { if (child->getStyle().display() == YGDisplayNone ||
child->getStyle().positionType() != YGPositionTypeAbsolute) {
continue; continue;
} }
YGNodeAbsoluteLayoutChild( YGNodeAbsoluteLayoutChild(
@ -3646,14 +3620,14 @@ static inline bool YGMeasureModeNewMeasureSizeIsStricterAndStillValid(
} }
YOGA_EXPORT float YGRoundValueToPixelGrid( YOGA_EXPORT float YGRoundValueToPixelGrid(
const float value, const double value,
const float pointScaleFactor, const double pointScaleFactor,
const bool forceCeil, const bool forceCeil,
const bool forceFloor) { const bool forceFloor) {
double scaledValue = ((double) value) * pointScaleFactor; double scaledValue = value * pointScaleFactor;
// We want to calculate `fractial` such that `floor(scaledValue) = scaledValue // We want to calculate `fractial` such that `floor(scaledValue) = scaledValue
// - fractial`. // - fractial`.
float fractial = fmodf(scaledValue, 1.0f); double fractial = fmod(scaledValue, 1.0);
if (fractial < 0) { if (fractial < 0) {
// This branch is for handling negative numbers for `value`. // This branch is for handling negative numbers for `value`.
// //
@ -3672,28 +3646,28 @@ YOGA_EXPORT float YGRoundValueToPixelGrid(
// - Finding the `floor`: -2.2 - fractial2 = -2.2 - 0.8 = -3 // - Finding the `floor`: -2.2 - fractial2 = -2.2 - 0.8 = -3
++fractial; ++fractial;
} }
if (YGFloatsEqual(fractial, 0)) { if (YGDoubleEqual(fractial, 0)) {
// First we check if the value is already rounded // First we check if the value is already rounded
scaledValue = scaledValue - fractial; scaledValue = scaledValue - fractial;
} else if (YGFloatsEqual(fractial, 1.0f)) { } else if (YGDoubleEqual(fractial, 1.0)) {
scaledValue = scaledValue - fractial + 1.0f; scaledValue = scaledValue - fractial + 1.0;
} else if (forceCeil) { } else if (forceCeil) {
// Next we check if we need to use forced rounding // Next we check if we need to use forced rounding
scaledValue = scaledValue - fractial + 1.0f; scaledValue = scaledValue - fractial + 1.0;
} else if (forceFloor) { } else if (forceFloor) {
scaledValue = scaledValue - fractial; scaledValue = scaledValue - fractial;
} else { } else {
// Finally we just round the value // Finally we just round the value
scaledValue = scaledValue - fractial + scaledValue = scaledValue - fractial +
(!YGFloatIsUndefined(fractial) && (!YGDoubleIsUndefined(fractial) &&
(fractial > 0.5f || YGFloatsEqual(fractial, 0.5f)) (fractial > 0.5 || YGDoubleEqual(fractial, 0.5))
? 1.0f ? 1.0
: 0.0f); : 0.0);
} }
return (YGFloatIsUndefined(scaledValue) || return (YGDoubleIsUndefined(scaledValue) ||
YGFloatIsUndefined(pointScaleFactor)) YGDoubleIsUndefined(pointScaleFactor))
? YGUndefined ? YGUndefined
: scaledValue / pointScaleFactor; : (float) (scaledValue / pointScaleFactor);
} }
YOGA_EXPORT bool YGNodeCanUseCachedMeasurement( YOGA_EXPORT bool YGNodeCanUseCachedMeasurement(
@ -3803,8 +3777,10 @@ bool YGLayoutNodeInternal(
if (needToVisitNode) { if (needToVisitNode) {
// Invalidate the cached results. // Invalidate the cached results.
layout->nextCachedMeasurementsIndex = 0; layout->nextCachedMeasurementsIndex = 0;
layout->cachedLayout.widthMeasureMode = (YGMeasureMode) -1; layout->cachedLayout.availableWidth = -1;
layout->cachedLayout.heightMeasureMode = (YGMeasureMode) -1; layout->cachedLayout.availableHeight = -1;
layout->cachedLayout.widthMeasureMode = YGMeasureModeUndefined;
layout->cachedLayout.heightMeasureMode = YGMeasureModeUndefined;
layout->cachedLayout.computedWidth = -1; layout->cachedLayout.computedWidth = -1;
layout->cachedLayout.computedHeight = -1; layout->cachedLayout.computedHeight = -1;
} }
@ -4061,24 +4037,24 @@ YOGA_EXPORT void YGConfigSetPointScaleFactor(
static void YGRoundToPixelGrid( static void YGRoundToPixelGrid(
const YGNodeRef node, const YGNodeRef node,
const float pointScaleFactor, const double pointScaleFactor,
const float absoluteLeft, const double absoluteLeft,
const float absoluteTop) { const double absoluteTop) {
if (pointScaleFactor == 0.0f) { if (pointScaleFactor == 0.0f) {
return; return;
} }
const float nodeLeft = node->getLayout().position[YGEdgeLeft]; const double nodeLeft = node->getLayout().position[YGEdgeLeft];
const float nodeTop = node->getLayout().position[YGEdgeTop]; const double nodeTop = node->getLayout().position[YGEdgeTop];
const float nodeWidth = node->getLayout().dimensions[YGDimensionWidth]; const double nodeWidth = node->getLayout().dimensions[YGDimensionWidth];
const float nodeHeight = node->getLayout().dimensions[YGDimensionHeight]; const double nodeHeight = node->getLayout().dimensions[YGDimensionHeight];
const float absoluteNodeLeft = absoluteLeft + nodeLeft; const double absoluteNodeLeft = absoluteLeft + nodeLeft;
const float absoluteNodeTop = absoluteTop + nodeTop; const double absoluteNodeTop = absoluteTop + nodeTop;
const float absoluteNodeRight = absoluteNodeLeft + nodeWidth; const double absoluteNodeRight = absoluteNodeLeft + nodeWidth;
const float absoluteNodeBottom = absoluteNodeTop + nodeHeight; const double absoluteNodeBottom = absoluteNodeTop + nodeHeight;
// If a node has a custom measure function we never want to round down its // If a node has a custom measure function we never want to round down its
// size as this could lead to unwanted text truncation. // size as this could lead to unwanted text truncation.
@ -4096,11 +4072,11 @@ static void YGRoundToPixelGrid(
// whole number, we don't have any fraction To verify if the result is close // 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 // to whole number we want to check both floor and ceil numbers
const bool hasFractionalWidth = const bool hasFractionalWidth =
!YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 0) && !YGDoubleEqual(fmod(nodeWidth * pointScaleFactor, 1.0), 0) &&
!YGFloatsEqual(fmodf(nodeWidth * pointScaleFactor, 1.0), 1.0); !YGDoubleEqual(fmod(nodeWidth * pointScaleFactor, 1.0), 1.0);
const bool hasFractionalHeight = const bool hasFractionalHeight =
!YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 0) && !YGDoubleEqual(fmod(nodeHeight * pointScaleFactor, 1.0), 0) &&
!YGFloatsEqual(fmodf(nodeHeight * pointScaleFactor, 1.0), 1.0); !YGDoubleEqual(fmod(nodeHeight * pointScaleFactor, 1.0), 1.0);
node->setLayoutDimension( node->setLayoutDimension(
YGRoundValueToPixelGrid( YGRoundValueToPixelGrid(
@ -4321,6 +4297,7 @@ YOGA_EXPORT void YGConfigSetShouldDiffLayoutWithoutLegacyStretchBehaviour(
void YGAssert(const bool condition, const char* message) { void YGAssert(const bool condition, const char* message) {
if (!condition) { if (!condition) {
Log::log(YGNodeRef{nullptr}, YGLogLevelFatal, nullptr, "%s\n", message); Log::log(YGNodeRef{nullptr}, YGLogLevelFatal, nullptr, "%s\n", message);
throwLogicalErrorWithMessage(message);
} }
} }
@ -4330,6 +4307,7 @@ void YGAssertWithNode(
const char* message) { const char* message) {
if (!condition) { if (!condition) {
Log::log(node, YGLogLevelFatal, nullptr, "%s\n", message); Log::log(node, YGLogLevelFatal, nullptr, "%s\n", message);
throwLogicalErrorWithMessage(message);
} }
} }
@ -4339,6 +4317,7 @@ void YGAssertWithConfig(
const char* message) { const char* message) {
if (!condition) { if (!condition) {
Log::log(config, YGLogLevelFatal, nullptr, "%s\n", message); Log::log(config, YGLogLevelFatal, nullptr, "%s\n", message);
throwLogicalErrorWithMessage(message);
} }
} }

View File

@ -69,6 +69,11 @@ WIN_EXPORT void YGNodeInsertChild(
YGNodeRef child, YGNodeRef child,
uint32_t index); uint32_t index);
WIN_EXPORT void YGNodeSwapChild(
YGNodeRef node,
YGNodeRef child,
uint32_t index);
WIN_EXPORT void YGNodeRemoveChild(YGNodeRef node, YGNodeRef child); WIN_EXPORT void YGNodeRemoveChild(YGNodeRef node, YGNodeRef child);
WIN_EXPORT void YGNodeRemoveAllChildren(YGNodeRef node); WIN_EXPORT void YGNodeRemoveAllChildren(YGNodeRef node);
WIN_EXPORT YGNodeRef YGNodeGetChild(YGNodeRef node, uint32_t index); WIN_EXPORT YGNodeRef YGNodeGetChild(YGNodeRef node, uint32_t index);
@ -102,7 +107,7 @@ WIN_EXPORT void YGNodeMarkDirty(YGNodeRef node);
// Marks the current node and all its descendants as dirty. // Marks the current node and all its descendants as dirty.
// //
// Intended to be used for Uoga benchmarks. Don't use in production, as calling // Intended to be used for Yoga benchmarks. Don't use in production, as calling
// `YGCalculateLayout` will cause the recalculation of each and every node. // `YGCalculateLayout` will cause the recalculation of each and every node.
WIN_EXPORT void YGNodeMarkDirtyAndPropogateToDescendants(YGNodeRef node); WIN_EXPORT void YGNodeMarkDirtyAndPropogateToDescendants(YGNodeRef node);
@ -347,8 +352,8 @@ WIN_EXPORT void YGConfigSetContext(YGConfigRef config, void* context);
WIN_EXPORT void* YGConfigGetContext(YGConfigRef config); WIN_EXPORT void* YGConfigGetContext(YGConfigRef config);
WIN_EXPORT float YGRoundValueToPixelGrid( WIN_EXPORT float YGRoundValueToPixelGrid(
float value, double value,
float pointScaleFactor, double pointScaleFactor,
bool forceCeil, bool forceCeil,
bool forceFloor); bool forceFloor);

View File

@ -8,7 +8,6 @@
#include "event.h" #include "event.h"
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <stdexcept>
namespace facebook { namespace facebook {
namespace yoga { namespace yoga {

View File

@ -11,6 +11,7 @@
#include <vector> #include <vector>
#include <array> #include <array>
#include <yoga/YGEnums.h> #include <yoga/YGEnums.h>
#include <stdint.h>
struct YGConfig; struct YGConfig;
struct YGNode; struct YGNode;

View File

@ -26,10 +26,6 @@ void vlog(
va_list args) { va_list args) {
YGConfig* logConfig = config != nullptr ? config : YGConfigGetDefault(); YGConfig* logConfig = config != nullptr ? config : YGConfigGetDefault();
logConfig->log(logConfig, node, level, context, format, args); logConfig->log(logConfig, node, level, context, format, args);
if (level == YGLogLevelFatal) {
abort();
}
} }
} // namespace } // namespace