Files
yoga/yoga/Yoga.cpp
Nick Gerleman 9b99e4fc22 C++ style enums 8/N: Direction (#1392)
Summary:
X-link: https://github.com/facebook/react-native/pull/39483

Pull Request resolved: https://github.com/facebook/yoga/pull/1392

Moves internal usages of YGDirection to Direction.

bypass-github-export-checks

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D49335231

fbshipit-source-id: 459fe820c91be88734cebaa8655cd3f0afda83bf
2023-09-19 16:30:02 -07:00

962 lines
30 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.
*/
#include <yoga/Yoga-internal.h>
#include <yoga/Yoga.h>
#include <yoga/algorithm/Cache.h>
#include <yoga/algorithm/CalculateLayout.h>
#include <yoga/algorithm/PixelGrid.h>
#include <yoga/debug/AssertFatal.h>
#include <yoga/debug/Log.h>
#include <yoga/debug/NodeToString.h>
#include <yoga/event/event.h>
#include <yoga/node/Node.h>
using namespace facebook;
using namespace facebook::yoga;
bool YGFloatIsUndefined(const float value) {
return yoga::isUndefined(value);
}
void* YGNodeGetContext(YGNodeConstRef node) {
return resolveRef(node)->getContext();
}
void YGNodeSetContext(YGNodeRef node, void* context) {
return resolveRef(node)->setContext(context);
}
YGConfigConstRef YGNodeGetConfig(YGNodeRef node) {
return resolveRef(node)->getConfig();
}
void YGNodeSetConfig(YGNodeRef node, YGConfigRef config) {
resolveRef(node)->setConfig(resolveRef(config));
}
bool YGNodeHasMeasureFunc(YGNodeConstRef node) {
return resolveRef(node)->hasMeasureFunc();
}
void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc) {
resolveRef(node)->setMeasureFunc(measureFunc);
}
bool YGNodeHasBaselineFunc(YGNodeConstRef node) {
return resolveRef(node)->hasBaselineFunc();
}
void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc) {
resolveRef(node)->setBaselineFunc(baselineFunc);
}
YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeConstRef node) {
return resolveRef(node)->getDirtiedFunc();
}
void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc) {
resolveRef(node)->setDirtiedFunc(dirtiedFunc);
}
void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) {
resolveRef(node)->setPrintFunc(printFunc);
}
bool YGNodeGetHasNewLayout(YGNodeConstRef node) {
return resolveRef(node)->getHasNewLayout();
}
void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled) {
resolveRef(config)->setShouldPrintTree(enabled);
}
void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) {
resolveRef(node)->setHasNewLayout(hasNewLayout);
}
YGNodeType YGNodeGetNodeType(YGNodeConstRef node) {
return unscopedEnum(resolveRef(node)->getNodeType());
}
void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType) {
return resolveRef(node)->setNodeType(scopedEnum(nodeType));
}
bool YGNodeIsDirty(YGNodeConstRef node) {
return resolveRef(node)->isDirty();
}
void YGNodeMarkDirtyAndPropagateToDescendants(const YGNodeRef node) {
return resolveRef(node)->markDirtyAndPropagateDownwards();
}
YGNodeRef YGNodeNewWithConfig(const YGConfigConstRef config) {
auto* node = new yoga::Node{resolveRef(config)};
yoga::assertFatal(
config != nullptr, "Tried to construct YGNode with null config");
Event::publish<Event::NodeAllocation>(node, {config});
return node;
}
YGConfigConstRef YGConfigGetDefault() {
return &yoga::Config::getDefault();
}
YGNodeRef YGNodeNew(void) {
return YGNodeNewWithConfig(YGConfigGetDefault());
}
YGNodeRef YGNodeClone(YGNodeConstRef oldNodeRef) {
auto oldNode = resolveRef(oldNodeRef);
const auto node = new yoga::Node(*oldNode);
yoga::assertFatalWithConfig(
oldNode->getConfig(),
node != nullptr,
"Could not allocate memory for node");
Event::publish<Event::NodeAllocation>(node, {node->getConfig()});
node->setOwner(nullptr);
return node;
}
void YGNodeFree(const YGNodeRef nodeRef) {
const auto node = resolveRef(nodeRef);
if (auto owner = node->getOwner()) {
owner->removeChild(node);
node->setOwner(nullptr);
}
const size_t childCount = node->getChildCount();
for (size_t i = 0; i < childCount; i++) {
auto child = node->getChild(i);
child->setOwner(nullptr);
}
node->clearChildren();
YGNodeDeallocate(node);
}
void YGNodeDeallocate(const YGNodeRef node) {
Event::publish<Event::NodeDeallocation>(node, {YGNodeGetConfig(node)});
delete resolveRef(node);
}
void YGNodeFreeRecursiveWithCleanupFunc(
const YGNodeRef rootRef,
YGNodeCleanupFunc cleanup) {
const auto root = resolveRef(rootRef);
size_t skipped = 0;
while (root->getChildCount() > skipped) {
const auto child = root->getChild(skipped);
if (child->getOwner() != root) {
// Don't free shared nodes that we don't own.
skipped += 1;
} else {
YGNodeRemoveChild(root, child);
YGNodeFreeRecursive(child);
}
}
if (cleanup != nullptr) {
cleanup(root);
}
YGNodeFree(root);
}
void YGNodeFreeRecursive(const YGNodeRef root) {
return YGNodeFreeRecursiveWithCleanupFunc(root, nullptr);
}
void YGNodeReset(YGNodeRef node) {
resolveRef(node)->reset();
}
YGConfigRef YGConfigNew(void) {
return new yoga::Config(getDefaultLogger());
}
void YGConfigFree(const YGConfigRef config) {
delete resolveRef(config);
}
void YGNodeSetIsReferenceBaseline(YGNodeRef nodeRef, bool isReferenceBaseline) {
const auto node = resolveRef(nodeRef);
if (node->isReferenceBaseline() != isReferenceBaseline) {
node->setIsReferenceBaseline(isReferenceBaseline);
node->markDirtyAndPropagate();
}
}
bool YGNodeIsReferenceBaseline(YGNodeConstRef node) {
return resolveRef(node)->isReferenceBaseline();
}
void YGNodeInsertChild(
const YGNodeRef ownerRef,
const YGNodeRef childRef,
const size_t index) {
auto owner = resolveRef(ownerRef);
auto child = resolveRef(childRef);
yoga::assertFatalWithNode(
owner,
child->getOwner() == nullptr,
"Child already has a owner, it must be removed first.");
yoga::assertFatalWithNode(
owner,
!owner->hasMeasureFunc(),
"Cannot add child: Nodes with measure functions cannot have children.");
owner->insertChild(child, index);
child->setOwner(owner);
owner->markDirtyAndPropagate();
}
void YGNodeSwapChild(
const YGNodeRef ownerRef,
const YGNodeRef childRef,
const size_t index) {
auto owner = resolveRef(ownerRef);
auto child = resolveRef(childRef);
owner->replaceChild(child, index);
child->setOwner(owner);
}
void YGNodeRemoveChild(
const YGNodeRef ownerRef,
const YGNodeRef excludedChildRef) {
auto owner = resolveRef(ownerRef);
auto excludedChild = resolveRef(excludedChildRef);
if (owner->getChildCount() == 0) {
// This is an empty set. Nothing to remove.
return;
}
// Children may be shared between parents, which is indicated by not having an
// owner. We only want to reset the child completely if it is owned
// exclusively by one node.
auto childOwner = excludedChild->getOwner();
if (owner->removeChild(excludedChild)) {
if (owner == childOwner) {
excludedChild->setLayout({}); // layout is no longer valid
excludedChild->setOwner(nullptr);
}
owner->markDirtyAndPropagate();
}
}
void YGNodeRemoveAllChildren(const YGNodeRef ownerRef) {
auto owner = resolveRef(ownerRef);
const size_t childCount = owner->getChildCount();
if (childCount == 0) {
// This is an empty set already. Nothing to do.
return;
}
auto* firstChild = owner->getChild(0);
if (firstChild->getOwner() == owner) {
// If the first child has this node as its owner, we assume that this child
// set is unique.
for (size_t i = 0; i < childCount; i++) {
yoga::Node* oldChild = owner->getChild(i);
oldChild->setLayout({}); // layout is no longer valid
oldChild->setOwner(nullptr);
}
owner->clearChildren();
owner->markDirtyAndPropagate();
return;
}
// Otherwise, we are not the owner of the child set. We don't have to do
// anything to clear it.
owner->setChildren({});
owner->markDirtyAndPropagate();
}
void YGNodeSetChildren(
const YGNodeRef ownerRef,
const YGNodeRef* childrenRefs,
const size_t count) {
auto owner = resolveRef(ownerRef);
auto children = reinterpret_cast<yoga::Node* const*>(childrenRefs);
if (!owner) {
return;
}
const std::vector<yoga::Node*> childrenVector = {children, children + count};
if (childrenVector.size() == 0) {
if (owner->getChildCount() > 0) {
for (auto* child : owner->getChildren()) {
child->setLayout({});
child->setOwner(nullptr);
}
owner->setChildren({});
owner->markDirtyAndPropagate();
}
} else {
if (owner->getChildCount() > 0) {
for (auto* oldChild : owner->getChildren()) {
// Our new children may have nodes in common with the old children. We
// don't reset these common nodes.
if (std::find(childrenVector.begin(), childrenVector.end(), oldChild) ==
childrenVector.end()) {
oldChild->setLayout({});
oldChild->setOwner(nullptr);
}
}
}
owner->setChildren(childrenVector);
for (yoga::Node* child : childrenVector) {
child->setOwner(owner);
}
owner->markDirtyAndPropagate();
}
}
YGNodeRef YGNodeGetChild(const YGNodeRef nodeRef, const size_t index) {
const auto node = resolveRef(nodeRef);
if (index < node->getChildren().size()) {
return node->getChild(index);
}
return nullptr;
}
size_t YGNodeGetChildCount(const YGNodeConstRef node) {
return resolveRef(node)->getChildren().size();
}
YGNodeRef YGNodeGetOwner(const YGNodeRef node) {
return resolveRef(node)->getOwner();
}
YGNodeRef YGNodeGetParent(const YGNodeRef node) {
return resolveRef(node)->getOwner();
}
void YGNodeMarkDirty(const YGNodeRef nodeRef) {
const auto node = resolveRef(nodeRef);
yoga::assertFatalWithNode(
node,
node->hasMeasureFunc(),
"Only leaf nodes with custom measure functions "
"should manually mark themselves as dirty");
node->markDirtyAndPropagate();
}
void YGNodeCopyStyle(
const YGNodeRef dstNodeRef,
const YGNodeConstRef srcNodeRef) {
auto dstNode = resolveRef(dstNodeRef);
auto srcNode = resolveRef(srcNodeRef);
if (!(dstNode->getStyle() == srcNode->getStyle())) {
dstNode->setStyle(srcNode->getStyle());
dstNode->markDirtyAndPropagate();
}
}
float YGNodeStyleGetFlexGrow(const YGNodeConstRef nodeRef) {
const auto node = resolveRef(nodeRef);
return node->getStyle().flexGrow().isUndefined()
? Style::DefaultFlexGrow
: node->getStyle().flexGrow().unwrap();
}
float YGNodeStyleGetFlexShrink(const YGNodeConstRef nodeRef) {
const auto node = resolveRef(nodeRef);
return node->getStyle().flexShrink().isUndefined()
? (node->getConfig()->useWebDefaults() ? Style::WebDefaultFlexShrink
: Style::DefaultFlexShrink)
: node->getStyle().flexShrink().unwrap();
}
namespace {
template <typename T, typename NeedsUpdate, typename Update>
void updateStyle(
yoga::Node* node,
T value,
NeedsUpdate&& needsUpdate,
Update&& update) {
if (needsUpdate(node->getStyle(), value)) {
update(node->getStyle(), value);
node->markDirtyAndPropagate();
}
}
template <typename Ref, typename T>
void updateStyle(YGNodeRef node, Ref (Style::*prop)(), T value) {
updateStyle(
resolveRef(node),
value,
[prop](Style& s, T x) { return (s.*prop)() != x; },
[prop](Style& s, T x) { (s.*prop)() = x; });
}
template <typename Ref, typename Idx>
void updateIndexedStyleProp(
YGNodeRef node,
Ref (Style::*prop)(),
Idx idx,
CompactValue value) {
updateStyle(
resolveRef(node),
value,
[idx, prop](Style& s, CompactValue x) { return (s.*prop)()[idx] != x; },
[idx, prop](Style& s, CompactValue x) { (s.*prop)()[idx] = x; });
}
} // namespace
// MSVC has trouble inferring the return type of pointer to member functions
// with const and non-const overloads, instead of preferring the non-const
// overload like clang and GCC. For the purposes of updateStyle(), we can help
// MSVC by specifying that return type explicitly. In combination with
// decltype, MSVC will prefer the non-const version.
#define MSVC_HINT(PROP) decltype(Style{}.PROP())
void YGNodeStyleSetDirection(const YGNodeRef node, const YGDirection value) {
updateStyle<MSVC_HINT(direction)>(node, &Style::direction, scopedEnum(value));
}
YGDirection YGNodeStyleGetDirection(const YGNodeConstRef node) {
return unscopedEnum(resolveRef(node)->getStyle().direction());
}
void YGNodeStyleSetFlexDirection(
const YGNodeRef node,
const YGFlexDirection flexDirection) {
updateStyle<MSVC_HINT(flexDirection)>(
node, &Style::flexDirection, flexDirection);
}
YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().flexDirection();
}
void YGNodeStyleSetJustifyContent(
const YGNodeRef node,
const YGJustify justifyContent) {
updateStyle<MSVC_HINT(justifyContent)>(
node, &Style::justifyContent, justifyContent);
}
YGJustify YGNodeStyleGetJustifyContent(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().justifyContent();
}
void YGNodeStyleSetAlignContent(
const YGNodeRef node,
const YGAlign alignContent) {
updateStyle<MSVC_HINT(alignContent)>(
node, &Style::alignContent, alignContent);
}
YGAlign YGNodeStyleGetAlignContent(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().alignContent();
}
void YGNodeStyleSetAlignItems(const YGNodeRef node, const YGAlign alignItems) {
updateStyle<MSVC_HINT(alignItems)>(node, &Style::alignItems, alignItems);
}
YGAlign YGNodeStyleGetAlignItems(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().alignItems();
}
void YGNodeStyleSetAlignSelf(const YGNodeRef node, const YGAlign alignSelf) {
updateStyle<MSVC_HINT(alignSelf)>(node, &Style::alignSelf, alignSelf);
}
YGAlign YGNodeStyleGetAlignSelf(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().alignSelf();
}
void YGNodeStyleSetPositionType(
const YGNodeRef node,
const YGPositionType positionType) {
updateStyle<MSVC_HINT(positionType)>(
node, &Style::positionType, positionType);
}
YGPositionType YGNodeStyleGetPositionType(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().positionType();
}
void YGNodeStyleSetFlexWrap(const YGNodeRef node, const YGWrap flexWrap) {
updateStyle<MSVC_HINT(flexWrap)>(node, &Style::flexWrap, flexWrap);
}
YGWrap YGNodeStyleGetFlexWrap(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().flexWrap();
}
void YGNodeStyleSetOverflow(const YGNodeRef node, const YGOverflow overflow) {
updateStyle<MSVC_HINT(overflow)>(node, &Style::overflow, overflow);
}
YGOverflow YGNodeStyleGetOverflow(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().overflow();
}
void YGNodeStyleSetDisplay(const YGNodeRef node, const YGDisplay display) {
updateStyle<MSVC_HINT(display)>(node, &Style::display, display);
}
YGDisplay YGNodeStyleGetDisplay(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().display();
}
// TODO(T26792433): Change the API to accept FloatOptional.
void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) {
updateStyle<MSVC_HINT(flex)>(node, &Style::flex, FloatOptional{flex});
}
// TODO(T26792433): Change the API to accept FloatOptional.
float YGNodeStyleGetFlex(const YGNodeConstRef nodeRef) {
const auto node = resolveRef(nodeRef);
return node->getStyle().flex().isUndefined()
? YGUndefined
: node->getStyle().flex().unwrap();
}
// TODO(T26792433): Change the API to accept FloatOptional.
void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) {
updateStyle<MSVC_HINT(flexGrow)>(
node, &Style::flexGrow, FloatOptional{flexGrow});
}
// TODO(T26792433): Change the API to accept FloatOptional.
void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) {
updateStyle<MSVC_HINT(flexShrink)>(
node, &Style::flexShrink, FloatOptional{flexShrink});
}
YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef node) {
YGValue flexBasis = resolveRef(node)->getStyle().flexBasis();
if (flexBasis.unit == YGUnitUndefined || flexBasis.unit == YGUnitAuto) {
// TODO(T26792433): Get rid off the use of YGUndefined at client side
flexBasis.value = YGUndefined;
}
return flexBasis;
}
void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) {
auto value = CompactValue::ofMaybe<YGUnitPoint>(flexBasis);
updateStyle<MSVC_HINT(flexBasis)>(node, &Style::flexBasis, value);
}
void YGNodeStyleSetFlexBasisPercent(
const YGNodeRef node,
const float flexBasisPercent) {
auto value = CompactValue::ofMaybe<YGUnitPercent>(flexBasisPercent);
updateStyle<MSVC_HINT(flexBasis)>(node, &Style::flexBasis, value);
}
void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) {
updateStyle<MSVC_HINT(flexBasis)>(
node, &Style::flexBasis, CompactValue::ofAuto());
}
void YGNodeStyleSetPosition(YGNodeRef node, YGEdge edge, float points) {
auto value = CompactValue::ofMaybe<YGUnitPoint>(points);
updateIndexedStyleProp<MSVC_HINT(position)>(
node, &Style::position, edge, value);
}
void YGNodeStyleSetPositionPercent(YGNodeRef node, YGEdge edge, float percent) {
auto value = CompactValue::ofMaybe<YGUnitPercent>(percent);
updateIndexedStyleProp<MSVC_HINT(position)>(
node, &Style::position, edge, value);
}
YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge) {
return resolveRef(node)->getStyle().position()[edge];
}
void YGNodeStyleSetMargin(YGNodeRef node, YGEdge edge, float points) {
auto value = CompactValue::ofMaybe<YGUnitPoint>(points);
updateIndexedStyleProp<MSVC_HINT(margin)>(node, &Style::margin, edge, value);
}
void YGNodeStyleSetMarginPercent(YGNodeRef node, YGEdge edge, float percent) {
auto value = CompactValue::ofMaybe<YGUnitPercent>(percent);
updateIndexedStyleProp<MSVC_HINT(margin)>(node, &Style::margin, edge, value);
}
void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge) {
updateIndexedStyleProp<MSVC_HINT(margin)>(
node, &Style::margin, edge, CompactValue::ofAuto());
}
YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge) {
return resolveRef(node)->getStyle().margin()[edge];
}
void YGNodeStyleSetPadding(YGNodeRef node, YGEdge edge, float points) {
auto value = CompactValue::ofMaybe<YGUnitPoint>(points);
updateIndexedStyleProp<MSVC_HINT(padding)>(
node, &Style::padding, edge, value);
}
void YGNodeStyleSetPaddingPercent(YGNodeRef node, YGEdge edge, float percent) {
auto value = CompactValue::ofMaybe<YGUnitPercent>(percent);
updateIndexedStyleProp<MSVC_HINT(padding)>(
node, &Style::padding, edge, value);
}
YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge) {
return resolveRef(node)->getStyle().padding()[edge];
}
// TODO(T26792433): Change the API to accept FloatOptional.
void YGNodeStyleSetBorder(
const YGNodeRef node,
const YGEdge edge,
const float border) {
auto value = CompactValue::ofMaybe<YGUnitPoint>(border);
updateIndexedStyleProp<MSVC_HINT(border)>(node, &Style::border, edge, value);
}
float YGNodeStyleGetBorder(const YGNodeConstRef node, const YGEdge edge) {
auto border = resolveRef(node)->getStyle().border()[edge];
if (border.isUndefined() || border.isAuto()) {
// TODO(T26792433): Rather than returning YGUndefined, change the api to
// return FloatOptional.
return YGUndefined;
}
return static_cast<YGValue>(border).value;
}
void YGNodeStyleSetGap(
const YGNodeRef node,
const YGGutter gutter,
const float gapLength) {
auto length = CompactValue::ofMaybe<YGUnitPoint>(gapLength);
updateIndexedStyleProp<MSVC_HINT(gap)>(node, &Style::gap, gutter, length);
}
float YGNodeStyleGetGap(const YGNodeConstRef node, const YGGutter gutter) {
auto gapLength = resolveRef(node)->getStyle().gap()[gutter];
if (gapLength.isUndefined() || gapLength.isAuto()) {
// TODO(T26792433): Rather than returning YGUndefined, change the api to
// return FloatOptional.
return YGUndefined;
}
return static_cast<YGValue>(gapLength).value;
}
// Yoga specific properties, not compatible with flexbox specification
// TODO(T26792433): Change the API to accept FloatOptional.
float YGNodeStyleGetAspectRatio(const YGNodeConstRef node) {
const FloatOptional op = resolveRef(node)->getStyle().aspectRatio();
return op.isUndefined() ? YGUndefined : op.unwrap();
}
// TODO(T26792433): Change the API to accept FloatOptional.
void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) {
updateStyle<MSVC_HINT(aspectRatio)>(
node, &Style::aspectRatio, FloatOptional{aspectRatio});
}
void YGNodeStyleSetWidth(YGNodeRef node, float points) {
auto value = CompactValue::ofMaybe<YGUnitPoint>(points);
updateIndexedStyleProp<MSVC_HINT(dimensions)>(
node, &Style::dimensions, YGDimensionWidth, value);
}
void YGNodeStyleSetWidthPercent(YGNodeRef node, float percent) {
auto value = CompactValue::ofMaybe<YGUnitPercent>(percent);
updateIndexedStyleProp<MSVC_HINT(dimensions)>(
node, &Style::dimensions, YGDimensionWidth, value);
}
void YGNodeStyleSetWidthAuto(YGNodeRef node) {
updateIndexedStyleProp<MSVC_HINT(dimensions)>(
node, &Style::dimensions, YGDimensionWidth, CompactValue::ofAuto());
}
YGValue YGNodeStyleGetWidth(YGNodeConstRef node) {
return resolveRef(node)->getStyle().dimensions()[YGDimensionWidth];
}
void YGNodeStyleSetHeight(YGNodeRef node, float points) {
auto value = CompactValue::ofMaybe<YGUnitPoint>(points);
updateIndexedStyleProp<MSVC_HINT(dimensions)>(
node, &Style::dimensions, YGDimensionHeight, value);
}
void YGNodeStyleSetHeightPercent(YGNodeRef node, float percent) {
auto value = CompactValue::ofMaybe<YGUnitPercent>(percent);
updateIndexedStyleProp<MSVC_HINT(dimensions)>(
node, &Style::dimensions, YGDimensionHeight, value);
}
void YGNodeStyleSetHeightAuto(YGNodeRef node) {
updateIndexedStyleProp<MSVC_HINT(dimensions)>(
node, &Style::dimensions, YGDimensionHeight, CompactValue::ofAuto());
}
YGValue YGNodeStyleGetHeight(YGNodeConstRef node) {
return resolveRef(node)->getStyle().dimensions()[YGDimensionHeight];
}
void YGNodeStyleSetMinWidth(const YGNodeRef node, const float minWidth) {
auto value = CompactValue::ofMaybe<YGUnitPoint>(minWidth);
updateIndexedStyleProp<MSVC_HINT(minDimensions)>(
node, &Style::minDimensions, YGDimensionWidth, value);
}
void YGNodeStyleSetMinWidthPercent(const YGNodeRef node, const float minWidth) {
auto value = CompactValue::ofMaybe<YGUnitPercent>(minWidth);
updateIndexedStyleProp<MSVC_HINT(minDimensions)>(
node, &Style::minDimensions, YGDimensionWidth, value);
}
YGValue YGNodeStyleGetMinWidth(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().minDimensions()[YGDimensionWidth];
}
void YGNodeStyleSetMinHeight(const YGNodeRef node, const float minHeight) {
auto value = CompactValue::ofMaybe<YGUnitPoint>(minHeight);
updateIndexedStyleProp<MSVC_HINT(minDimensions)>(
node, &Style::minDimensions, YGDimensionHeight, value);
}
void YGNodeStyleSetMinHeightPercent(
const YGNodeRef node,
const float minHeight) {
auto value = CompactValue::ofMaybe<YGUnitPercent>(minHeight);
updateIndexedStyleProp<MSVC_HINT(minDimensions)>(
node, &Style::minDimensions, YGDimensionHeight, value);
}
YGValue YGNodeStyleGetMinHeight(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().minDimensions()[YGDimensionHeight];
}
void YGNodeStyleSetMaxWidth(const YGNodeRef node, const float maxWidth) {
auto value = CompactValue::ofMaybe<YGUnitPoint>(maxWidth);
updateIndexedStyleProp<MSVC_HINT(maxDimensions)>(
node, &Style::maxDimensions, YGDimensionWidth, value);
}
void YGNodeStyleSetMaxWidthPercent(const YGNodeRef node, const float maxWidth) {
auto value = CompactValue::ofMaybe<YGUnitPercent>(maxWidth);
updateIndexedStyleProp<MSVC_HINT(maxDimensions)>(
node, &Style::maxDimensions, YGDimensionWidth, value);
}
YGValue YGNodeStyleGetMaxWidth(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().maxDimensions()[YGDimensionWidth];
}
void YGNodeStyleSetMaxHeight(const YGNodeRef node, const float maxHeight) {
auto value = CompactValue::ofMaybe<YGUnitPoint>(maxHeight);
updateIndexedStyleProp<MSVC_HINT(maxDimensions)>(
node, &Style::maxDimensions, YGDimensionHeight, value);
}
void YGNodeStyleSetMaxHeightPercent(
const YGNodeRef node,
const float maxHeight) {
auto value = CompactValue::ofMaybe<YGUnitPercent>(maxHeight);
updateIndexedStyleProp<MSVC_HINT(maxDimensions)>(
node, &Style::maxDimensions, YGDimensionHeight, value);
}
YGValue YGNodeStyleGetMaxHeight(const YGNodeConstRef node) {
return resolveRef(node)->getStyle().maxDimensions()[YGDimensionHeight];
}
namespace {
template <auto LayoutMember>
float getResolvedLayoutProperty(
const YGNodeConstRef nodeRef,
const YGEdge edge) {
const auto node = resolveRef(nodeRef);
yoga::assertFatalWithNode(
node,
edge <= YGEdgeEnd,
"Cannot get layout properties of multi-edge shorthands");
if (edge == YGEdgeStart) {
if (node->getLayout().direction() == Direction::RTL) {
return (node->getLayout().*LayoutMember)[YGEdgeRight];
} else {
return (node->getLayout().*LayoutMember)[YGEdgeLeft];
}
}
if (edge == YGEdgeEnd) {
if (node->getLayout().direction() == Direction::RTL) {
return (node->getLayout().*LayoutMember)[YGEdgeLeft];
} else {
return (node->getLayout().*LayoutMember)[YGEdgeRight];
}
}
return (node->getLayout().*LayoutMember)[edge];
}
} // namespace
float YGNodeLayoutGetLeft(const YGNodeConstRef node) {
return resolveRef(node)->getLayout().position[YGEdgeLeft];
}
float YGNodeLayoutGetTop(const YGNodeConstRef node) {
return resolveRef(node)->getLayout().position[YGEdgeTop];
}
float YGNodeLayoutGetRight(const YGNodeConstRef node) {
return resolveRef(node)->getLayout().position[YGEdgeRight];
}
float YGNodeLayoutGetBottom(const YGNodeConstRef node) {
return resolveRef(node)->getLayout().position[YGEdgeBottom];
}
float YGNodeLayoutGetWidth(const YGNodeConstRef node) {
return resolveRef(node)->getLayout().dimensions[YGDimensionWidth];
}
float YGNodeLayoutGetHeight(const YGNodeConstRef node) {
return resolveRef(node)->getLayout().dimensions[YGDimensionHeight];
}
YGDirection YGNodeLayoutGetDirection(const YGNodeConstRef node) {
return unscopedEnum(resolveRef(node)->getLayout().direction());
}
bool YGNodeLayoutGetHadOverflow(const YGNodeConstRef node) {
return resolveRef(node)->getLayout().hadOverflow();
}
float YGNodeLayoutGetMargin(YGNodeConstRef node, YGEdge edge) {
return getResolvedLayoutProperty<&LayoutResults::margin>(node, edge);
}
float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge) {
return getResolvedLayoutProperty<&LayoutResults::border>(node, edge);
}
float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge) {
return getResolvedLayoutProperty<&LayoutResults::padding>(node, edge);
}
#ifdef DEBUG
void YGNodePrint(const YGNodeConstRef node, const YGPrintOptions options) {
yoga::print(resolveRef(node), scopedEnum(options));
}
#endif
void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) {
if (logger != nullptr) {
resolveRef(config)->setLogger(logger);
} else {
resolveRef(config)->setLogger(getDefaultLogger());
}
}
void YGConfigSetPointScaleFactor(
const YGConfigRef config,
const float pixelsInPoint) {
yoga::assertFatalWithConfig(
resolveRef(config),
pixelsInPoint >= 0.0f,
"Scale factor should not be less than zero");
// We store points for Pixel as we will use it for rounding
if (pixelsInPoint == 0.0f) {
// Zero is used to skip rounding
resolveRef(config)->setPointScaleFactor(0.0f);
} else {
resolveRef(config)->setPointScaleFactor(pixelsInPoint);
}
}
float YGConfigGetPointScaleFactor(const YGConfigConstRef config) {
return resolveRef(config)->getPointScaleFactor();
}
float YGRoundValueToPixelGrid(
const double value,
const double pointScaleFactor,
const bool forceCeil,
const bool forceFloor) {
return yoga::roundValueToPixelGrid(
value, pointScaleFactor, forceCeil, forceFloor);
}
void YGConfigSetExperimentalFeatureEnabled(
const YGConfigRef config,
const YGExperimentalFeature feature,
const bool enabled) {
resolveRef(config)->setExperimentalFeatureEnabled(
scopedEnum(feature), enabled);
}
bool YGConfigIsExperimentalFeatureEnabled(
const YGConfigConstRef config,
const YGExperimentalFeature feature) {
return resolveRef(config)->isExperimentalFeatureEnabled(scopedEnum(feature));
}
void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled) {
resolveRef(config)->setUseWebDefaults(enabled);
}
bool YGConfigGetUseWebDefaults(const YGConfigConstRef config) {
return resolveRef(config)->useWebDefaults();
}
void YGConfigSetContext(const YGConfigRef config, void* context) {
resolveRef(config)->setContext(context);
}
void* YGConfigGetContext(const YGConfigConstRef config) {
return resolveRef(config)->getContext();
}
void YGConfigSetErrata(YGConfigRef config, YGErrata errata) {
resolveRef(config)->setErrata(scopedEnum(errata));
}
YGErrata YGConfigGetErrata(YGConfigConstRef config) {
return unscopedEnum(resolveRef(config)->getErrata());
}
void YGConfigSetCloneNodeFunc(
const YGConfigRef config,
const YGCloneNodeFunc callback) {
resolveRef(config)->setCloneNodeCallback(callback);
}
// TODO: This should not be part of the public API. Remove after removing
// ComponentKit usage of it.
bool YGNodeCanUseCachedMeasurement(
YGMeasureMode widthMode,
float availableWidth,
YGMeasureMode heightMode,
float availableHeight,
YGMeasureMode lastWidthMode,
float lastAvailableWidth,
YGMeasureMode lastHeightMode,
float lastAvailableHeight,
float lastComputedWidth,
float lastComputedHeight,
float marginRow,
float marginColumn,
YGConfigRef config) {
return yoga::canUseCachedMeasurement(
scopedEnum(widthMode),
availableWidth,
scopedEnum(heightMode),
availableHeight,
scopedEnum(lastWidthMode),
lastAvailableWidth,
scopedEnum(lastHeightMode),
lastAvailableHeight,
lastComputedWidth,
lastComputedHeight,
marginRow,
marginColumn,
resolveRef(config));
}
void YGNodeCalculateLayout(
const YGNodeRef node,
const float ownerWidth,
const float ownerHeight,
const YGDirection ownerDirection) {
yoga::calculateLayout(
resolveRef(node), ownerWidth, ownerHeight, scopedEnum(ownerDirection));
}