Summary: Pull Request resolved: https://github.com/facebook/yoga/pull/1355 X-link: https://github.com/facebook/react-native/pull/39198 ## This diff This splits up `Yoga-internal.h` which has become a grab bag. The actual header is left, with the purpose of being a private C ABI for bindings, but everything else is moved to a place more appropriate or removed. A few notes: 1. `yoga::isUndefined` is replaced with `std::isnan` to avoid a layer of indirection (we will never be able to change its representation anyway). Internal usages of `YGFloatIsUndefined` are also replaced with `std::isnan` since the previous being at a library boundary means I'm not sure it can be inlined/. 2. `leading`, `trailing` arrays are factored into proper functions 3. `Values` is replaced entirely with `std::array`, since most of it was unused. ## This stack The organization of the C++ internals of Yoga are in need of attention. 1. Some of the C++ internals are namespaced, but others not. 2. Some of the namespaces include `detail`, but are meant to be used outside of the translation unit (FB Clang Tidy rules warn on any usage of these) 2. Most of the files are in a flat hierarchy, except for event tracing in its own folder 3. Some files and functions begin with YG, others don’t 4. Some functions are uppercase, others are not 5. Almost all of the interesting logic is in Yoga.cpp, and the file is too large to reason about 6. There are multiple grab bag files where folks put random functions they need in (Utils, BitUtils, Yoga-Internal.h) 7. There is no clear indication from file structure or type naming what is private vs not 8. Handles like `YGNodeRef` and `YGConfigRef` can be used to access internals just by importing headers This stack does some much needed spring cleaning: 1. All non-public headers and C++ implementation details are in separate folders from the root level `yoga`. This will give us room to split up logic and add more files without too large a flat hierarchy 3. All private C++ internals are under the `facebook::yoga` namespace. Details namespaces are only ever used within the same header, as they are intended 4. Utils files are split 5. Most C++ internals drop the YG prefix 6. Most C++ internal function names are all lower camel case 7. We start to split up Yoga.cpp 8. Every header beginning with YG or at the top-level directory is public and C only, with the exception of Yoga-Internal.h which has non-public functions for bindings 9. It is not possible to use private APIs without static casting handles to internal classes This will give us more leeway to continue splitting monolithic files, and consistent guidelines for style in new files as well. These changes should not be breaking to any project using only public Yoga headers. This includes every usage of Yoga in fbsource except for RN Fabric which is currently tied to internals. This refactor should make that boundary clearer. Reviewed By: rshest Differential Revision: D48769241 fbshipit-source-id: 5b8e2192309539e7c133c3b3b29b445b59dd5835
232 lines
7.3 KiB
C++
232 lines
7.3 KiB
C++
/*
|
|
* Copyright (c) Meta Platforms, Inc. and 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 <algorithm>
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <type_traits>
|
|
|
|
#include <yoga/Yoga.h>
|
|
|
|
#include <yoga/bits/NumericBitfield.h>
|
|
#include <yoga/numeric/FloatOptional.h>
|
|
#include <yoga/style/CompactValue.h>
|
|
|
|
namespace facebook::yoga {
|
|
|
|
class YOGA_EXPORT Style {
|
|
template <typename Enum>
|
|
using Values = std::array<CompactValue, enums::count<Enum>()>;
|
|
|
|
public:
|
|
using Dimensions = Values<YGDimension>;
|
|
using Edges = Values<YGEdge>;
|
|
using Gutters = Values<YGGutter>;
|
|
|
|
static constexpr float DefaultFlexGrow = 0.0f;
|
|
static constexpr float DefaultFlexShrink = 0.0f;
|
|
static constexpr float WebDefaultFlexShrink = 1.0f;
|
|
|
|
template <typename T>
|
|
struct BitfieldRef {
|
|
Style& style;
|
|
size_t offset;
|
|
operator T() const { return getEnumData<T>(style.flags, offset); }
|
|
BitfieldRef<T>& operator=(T x) {
|
|
setEnumData<T>(style.flags, offset, x);
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
template <typename T, T Style::*Prop>
|
|
struct Ref {
|
|
Style& style;
|
|
operator T() const { return style.*Prop; }
|
|
Ref<T, Prop>& operator=(T value) {
|
|
style.*Prop = value;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
template <typename Idx, Values<Idx> Style::*Prop>
|
|
struct IdxRef {
|
|
struct Ref {
|
|
Style& style;
|
|
Idx idx;
|
|
operator CompactValue() const { return (style.*Prop)[idx]; }
|
|
operator YGValue() const { return (style.*Prop)[idx]; }
|
|
Ref& operator=(CompactValue value) {
|
|
(style.*Prop)[idx] = value;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
Style& style;
|
|
IdxRef<Idx, Prop>& operator=(const Values<Idx>& values) {
|
|
style.*Prop = values;
|
|
return *this;
|
|
}
|
|
operator const Values<Idx>&() const { return style.*Prop; }
|
|
Ref operator[](Idx idx) { return {style, idx}; }
|
|
CompactValue operator[](Idx idx) const { return (style.*Prop)[idx]; }
|
|
};
|
|
|
|
Style() {
|
|
alignContent() = YGAlignFlexStart;
|
|
alignItems() = YGAlignStretch;
|
|
}
|
|
~Style() = default;
|
|
|
|
private:
|
|
static constexpr size_t directionOffset = 0;
|
|
static constexpr size_t flexdirectionOffset =
|
|
directionOffset + minimumBitCount<YGDirection>();
|
|
static constexpr size_t justifyContentOffset =
|
|
flexdirectionOffset + minimumBitCount<YGFlexDirection>();
|
|
static constexpr size_t alignContentOffset =
|
|
justifyContentOffset + minimumBitCount<YGJustify>();
|
|
static constexpr size_t alignItemsOffset =
|
|
alignContentOffset + minimumBitCount<YGAlign>();
|
|
static constexpr size_t alignSelfOffset =
|
|
alignItemsOffset + minimumBitCount<YGAlign>();
|
|
static constexpr size_t positionTypeOffset =
|
|
alignSelfOffset + minimumBitCount<YGAlign>();
|
|
static constexpr size_t flexWrapOffset =
|
|
positionTypeOffset + minimumBitCount<YGPositionType>();
|
|
static constexpr size_t overflowOffset =
|
|
flexWrapOffset + minimumBitCount<YGWrap>();
|
|
static constexpr size_t displayOffset =
|
|
overflowOffset + minimumBitCount<YGOverflow>();
|
|
|
|
uint32_t flags = 0;
|
|
|
|
FloatOptional flex_ = {};
|
|
FloatOptional flexGrow_ = {};
|
|
FloatOptional flexShrink_ = {};
|
|
CompactValue flexBasis_ = CompactValue::ofAuto();
|
|
Edges margin_ = {};
|
|
Edges position_ = {};
|
|
Edges padding_ = {};
|
|
Edges border_ = {};
|
|
Gutters gap_ = {};
|
|
Dimensions dimensions_{CompactValue::ofAuto(), CompactValue::ofAuto()};
|
|
Dimensions minDimensions_ = {};
|
|
Dimensions maxDimensions_ = {};
|
|
// Yoga specific properties, not compatible with flexbox specification
|
|
FloatOptional aspectRatio_ = {};
|
|
|
|
public:
|
|
// for library users needing a type
|
|
using ValueRepr = std::remove_reference<decltype(margin_[0])>::type;
|
|
|
|
YGDirection direction() const {
|
|
return getEnumData<YGDirection>(flags, directionOffset);
|
|
}
|
|
BitfieldRef<YGDirection> direction() { return {*this, directionOffset}; }
|
|
|
|
YGFlexDirection flexDirection() const {
|
|
return getEnumData<YGFlexDirection>(flags, flexdirectionOffset);
|
|
}
|
|
BitfieldRef<YGFlexDirection> flexDirection() {
|
|
return {*this, flexdirectionOffset};
|
|
}
|
|
|
|
YGJustify justifyContent() const {
|
|
return getEnumData<YGJustify>(flags, justifyContentOffset);
|
|
}
|
|
BitfieldRef<YGJustify> justifyContent() {
|
|
return {*this, justifyContentOffset};
|
|
}
|
|
|
|
YGAlign alignContent() const {
|
|
return getEnumData<YGAlign>(flags, alignContentOffset);
|
|
}
|
|
BitfieldRef<YGAlign> alignContent() { return {*this, alignContentOffset}; }
|
|
|
|
YGAlign alignItems() const {
|
|
return getEnumData<YGAlign>(flags, alignItemsOffset);
|
|
}
|
|
BitfieldRef<YGAlign> alignItems() { return {*this, alignItemsOffset}; }
|
|
|
|
YGAlign alignSelf() const {
|
|
return getEnumData<YGAlign>(flags, alignSelfOffset);
|
|
}
|
|
BitfieldRef<YGAlign> alignSelf() { return {*this, alignSelfOffset}; }
|
|
|
|
YGPositionType positionType() const {
|
|
return getEnumData<YGPositionType>(flags, positionTypeOffset);
|
|
}
|
|
BitfieldRef<YGPositionType> positionType() {
|
|
return {*this, positionTypeOffset};
|
|
}
|
|
|
|
YGWrap flexWrap() const { return getEnumData<YGWrap>(flags, flexWrapOffset); }
|
|
BitfieldRef<YGWrap> flexWrap() { return {*this, flexWrapOffset}; }
|
|
|
|
YGOverflow overflow() const {
|
|
return getEnumData<YGOverflow>(flags, overflowOffset);
|
|
}
|
|
BitfieldRef<YGOverflow> overflow() { return {*this, overflowOffset}; }
|
|
|
|
YGDisplay display() const {
|
|
return getEnumData<YGDisplay>(flags, displayOffset);
|
|
}
|
|
BitfieldRef<YGDisplay> display() { return {*this, displayOffset}; }
|
|
|
|
FloatOptional flex() const { return flex_; }
|
|
Ref<FloatOptional, &Style::flex_> flex() { return {*this}; }
|
|
|
|
FloatOptional flexGrow() const { return flexGrow_; }
|
|
Ref<FloatOptional, &Style::flexGrow_> flexGrow() { return {*this}; }
|
|
|
|
FloatOptional flexShrink() const { return flexShrink_; }
|
|
Ref<FloatOptional, &Style::flexShrink_> flexShrink() { return {*this}; }
|
|
|
|
CompactValue flexBasis() const { return flexBasis_; }
|
|
Ref<CompactValue, &Style::flexBasis_> flexBasis() { return {*this}; }
|
|
|
|
const Edges& margin() const { return margin_; }
|
|
IdxRef<YGEdge, &Style::margin_> margin() { return {*this}; }
|
|
|
|
const Edges& position() const { return position_; }
|
|
IdxRef<YGEdge, &Style::position_> position() { return {*this}; }
|
|
|
|
const Edges& padding() const { return padding_; }
|
|
IdxRef<YGEdge, &Style::padding_> padding() { return {*this}; }
|
|
|
|
const Edges& border() const { return border_; }
|
|
IdxRef<YGEdge, &Style::border_> border() { return {*this}; }
|
|
|
|
const Gutters& gap() const { return gap_; }
|
|
IdxRef<YGGutter, &Style::gap_> gap() { return {*this}; }
|
|
|
|
const Dimensions& dimensions() const { return dimensions_; }
|
|
IdxRef<YGDimension, &Style::dimensions_> dimensions() { return {*this}; }
|
|
|
|
const Dimensions& minDimensions() const { return minDimensions_; }
|
|
IdxRef<YGDimension, &Style::minDimensions_> minDimensions() {
|
|
return {*this};
|
|
}
|
|
|
|
const Dimensions& maxDimensions() const { return maxDimensions_; }
|
|
IdxRef<YGDimension, &Style::maxDimensions_> maxDimensions() {
|
|
return {*this};
|
|
}
|
|
|
|
// Yoga specific properties, not compatible with flexbox specification
|
|
FloatOptional aspectRatio() const { return aspectRatio_; }
|
|
Ref<FloatOptional, &Style::aspectRatio_> aspectRatio() { return {*this}; }
|
|
};
|
|
|
|
YOGA_EXPORT bool operator==(const Style& lhs, const Style& rhs);
|
|
YOGA_EXPORT inline bool operator!=(const Style& lhs, const Style& rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
} // namespace facebook::yoga
|