From 1b58b4ea0198bbb5f43d0e5b6a64de0fd5fe3c86 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Fri, 3 Nov 2023 15:06:23 -0700 Subject: [PATCH] Modularize and document public API Summary: This aims to clean up the public Yoga C API, by: 1. Documenting most public APIs 2. Splitting APIs for specific objects into different header files (because Yoga.h was big enough without documentation) 3. Reordering headers and definitions for consistent grouping 4. Removed `Yoga-internal.h`, making all top-level headers public. `YGNodeDeallocate` is folded into a public `YGNodeFinalize` API 5. Move JNI bindings fully to public API Differential Revision: D50963424 --- Yoga.podspec | 2 +- java/com/facebook/yoga/YogaNative.java | 2 +- .../facebook/yoga/YogaNodeJNIFinalizer.java | 2 +- java/jni/YGJNIVanilla.cpp | 16 +- tests/YGRoundingFunctionTest.cpp | 1 - yoga/YGConfig.cpp | 102 ++ yoga/YGConfig.h | 163 +++ yoga/YGNode.cpp | 365 +++++++ yoga/YGNode.h | 283 ++++++ yoga/YGNodeLayout.cpp | 90 ++ yoga/YGNodeLayout.h | 35 + yoga/YGNodeStyle.cpp | 442 ++++++++ yoga/YGNodeStyle.h | 123 +++ yoga/YGPixelGrid.cpp | 22 + yoga/YGPixelGrid.h | 29 + yoga/YGValue.cpp | 8 + yoga/YGValue.h | 36 +- yoga/Yoga-internal.h | 22 - yoga/Yoga.cpp | 959 ------------------ yoga/Yoga.h | 314 +----- yoga/module.modulemap | 5 + 21 files changed, 1711 insertions(+), 1310 deletions(-) create mode 100644 yoga/YGConfig.cpp create mode 100644 yoga/YGConfig.h create mode 100644 yoga/YGNode.cpp create mode 100644 yoga/YGNode.h create mode 100644 yoga/YGNodeLayout.cpp create mode 100644 yoga/YGNodeLayout.h create mode 100644 yoga/YGNodeStyle.cpp create mode 100644 yoga/YGNodeStyle.h create mode 100644 yoga/YGPixelGrid.cpp create mode 100644 yoga/YGPixelGrid.h delete mode 100644 yoga/Yoga-internal.h delete mode 100644 yoga/Yoga.cpp diff --git a/Yoga.podspec b/Yoga.podspec index e8e4dc0cc1..0dd171e297 100644 --- a/Yoga.podspec +++ b/Yoga.podspec @@ -41,7 +41,7 @@ Pod::Spec.new do |spec| spec.source_files = 'yoga/**/*.{h,cpp}' spec.header_mappings_dir = 'yoga' - public_header_files = 'yoga/{Yoga,YGEnums,YGMacros,YGValue}.h' + public_header_files = 'yoga/*.h' spec.public_header_files = public_header_files all_header_files = 'yoga/**/*.h' diff --git a/java/com/facebook/yoga/YogaNative.java b/java/com/facebook/yoga/YogaNative.java index 6ae00f0f2e..a0b7c165f1 100644 --- a/java/com/facebook/yoga/YogaNative.java +++ b/java/com/facebook/yoga/YogaNative.java @@ -31,7 +31,7 @@ public class YogaNative { // YGNode related static native long jni_YGNodeNewJNI(); static native long jni_YGNodeNewWithConfigJNI(long configPointer); - static native void jni_YGNodeDeallocateJNI(long nativePointer); + static native void jni_YGNodeFinalizeJNI(long nativePointer); static native void jni_YGNodeResetJNI(long nativePointer); static native void jni_YGNodeInsertChildJNI(long nativePointer, long childPointer, int index); static native void jni_YGNodeSwapChildJNI(long nativePointer, long childPointer, int index); diff --git a/java/com/facebook/yoga/YogaNodeJNIFinalizer.java b/java/com/facebook/yoga/YogaNodeJNIFinalizer.java index ab617c7f16..23cf2a31e5 100644 --- a/java/com/facebook/yoga/YogaNodeJNIFinalizer.java +++ b/java/com/facebook/yoga/YogaNodeJNIFinalizer.java @@ -29,7 +29,7 @@ public void freeNatives() { if (mNativePointer != 0) { long nativePointer = mNativePointer; mNativePointer = 0; - YogaNative.jni_YGNodeDeallocateJNI(nativePointer); + YogaNative.jni_YGNodeFinalizeJNI(nativePointer); } } } diff --git a/java/jni/YGJNIVanilla.cpp b/java/jni/YGJNIVanilla.cpp index e01aa24875..213ff8ccea 100644 --- a/java/jni/YGJNIVanilla.cpp +++ b/java/jni/YGJNIVanilla.cpp @@ -16,9 +16,6 @@ #include "common.h" #include "jni.h" -#include -#include - using namespace facebook; using namespace facebook::yoga; using namespace facebook::yoga::vanillajni; @@ -190,12 +187,12 @@ static void jni_YGConfigSetLoggerJNI( } static void -jni_YGNodeDeallocateJNI(JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) { +jni_YGNodeFinalizeJNI(JNIEnv* /*env*/, jobject /*obj*/, jlong nativePointer) { if (nativePointer == 0) { return; } const YGNodeRef node = _jlong2YGNodeRef(nativePointer); - YGNodeDeallocate(node); + YGNodeFinalize(node); } static void @@ -638,8 +635,11 @@ static YGSize YGJNIMeasureFunc( uint32_t wBits = 0xFFFFFFFF & (measureResult >> 32); uint32_t hBits = 0xFFFFFFFF & measureResult; - const float measuredWidth = yoga::bit_cast(wBits); - const float measuredHeight = yoga::bit_cast(hBits); + float measuredWidth{}; + std::memcpy(&measuredWidth, &wBits, sizeof(measuredWidth)); + + float measuredHeight{}; + std::memcpy(&measuredHeight, &hBits, sizeof(measuredHeight)); return YGSize{measuredWidth, measuredHeight}; } else { @@ -751,7 +751,7 @@ static JNINativeMethod methods[] = { (void*)jni_YGConfigSetLoggerJNI}, {"jni_YGNodeNewJNI", "()J", (void*)jni_YGNodeNewJNI}, {"jni_YGNodeNewWithConfigJNI", "(J)J", (void*)jni_YGNodeNewWithConfigJNI}, - {"jni_YGNodeDeallocateJNI", "(J)V", (void*)jni_YGNodeDeallocateJNI}, + {"jni_YGNodeFinalizeJNI", "(J)V", (void*)jni_YGNodeFinalizeJNI}, {"jni_YGNodeResetJNI", "(J)V", (void*)jni_YGNodeResetJNI}, {"jni_YGNodeInsertChildJNI", "(JJI)V", (void*)jni_YGNodeInsertChildJNI}, {"jni_YGNodeSwapChildJNI", "(JJI)V", (void*)jni_YGNodeSwapChildJNI}, diff --git a/tests/YGRoundingFunctionTest.cpp b/tests/YGRoundingFunctionTest.cpp index 7fb2d30bdb..9639a92088 100644 --- a/tests/YGRoundingFunctionTest.cpp +++ b/tests/YGRoundingFunctionTest.cpp @@ -6,7 +6,6 @@ */ #include -#include #include TEST(YogaTest, rounding_value) { diff --git a/yoga/YGConfig.cpp b/yoga/YGConfig.cpp new file mode 100644 index 0000000000..2cdc7af995 --- /dev/null +++ b/yoga/YGConfig.cpp @@ -0,0 +1,102 @@ +/* + * 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 +#include +#include + +using namespace facebook; +using namespace facebook::yoga; + +YGConfigRef YGConfigNew(void) { + return new yoga::Config(getDefaultLogger()); +} + +void YGConfigFree(const YGConfigRef config) { + delete resolveRef(config); +} + +YGConfigConstRef YGConfigGetDefault() { + return &yoga::Config::getDefault(); +} + +void YGConfigSetUseWebDefaults(const YGConfigRef config, const bool enabled) { + resolveRef(config)->setUseWebDefaults(enabled); +} + +bool YGConfigGetUseWebDefaults(const YGConfigConstRef config) { + return resolveRef(config)->useWebDefaults(); +} + +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(); +} + +void YGConfigSetErrata(YGConfigRef config, YGErrata errata) { + resolveRef(config)->setErrata(scopedEnum(errata)); +} + +YGErrata YGConfigGetErrata(YGConfigConstRef config) { + return unscopedEnum(resolveRef(config)->getErrata()); +} + +void YGConfigSetLogger(const YGConfigRef config, YGLogger logger) { + if (logger != nullptr) { + resolveRef(config)->setLogger(logger); + } else { + resolveRef(config)->setLogger(getDefaultLogger()); + } +} + +void YGConfigSetContext(const YGConfigRef config, void* context) { + resolveRef(config)->setContext(context); +} + +void* YGConfigGetContext(const YGConfigConstRef config) { + return resolveRef(config)->getContext(); +} + +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 YGConfigSetCloneNodeFunc( + const YGConfigRef config, + const YGCloneNodeFunc callback) { + resolveRef(config)->setCloneNodeCallback(callback); +} + +void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled) { + resolveRef(config)->setShouldPrintTree(enabled); +} diff --git a/yoga/YGConfig.h b/yoga/YGConfig.h new file mode 100644 index 0000000000..b8fe27f424 --- /dev/null +++ b/yoga/YGConfig.h @@ -0,0 +1,163 @@ +/* + * 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 +#include +#include + +#include +#include + +YG_EXTERN_C_BEGIN + +typedef struct YGNode* YGNodeRef; +typedef const struct YGNode* YGNodeConstRef; + +/** + * Handle to a mutable Yoga configuration + */ +typedef struct YGConfig* YGConfigRef; + +/** + * Handle to an immutable Yoga configruation + */ +typedef const struct YGConfig* YGConfigConstRef; + +/** + * Allocates a set of configuration options. The configuration may be applied to + * multiple nodes (i.e. a single global config), or can be applied more + * granularly per-node. + */ +YG_EXPORT YGConfigRef YGConfigNew(void); + +/** + * Frees the associated Yoga configuration. + */ +YG_EXPORT void YGConfigFree(YGConfigRef config); + +/** + * Returns the default config values set by Yoga + */ +YG_EXPORT YGConfigConstRef YGConfigGetDefault(void); + +/** + * Yoga by default creates new nodes with style defaults different from flexbox + * on web (e.g. `YGFlexDirectionColumn` and `YGPositionRelative`). + * `UseWebDefaults` instructs Yoga to instead use a default style consistent + * with the web. + */ +YG_EXPORT void YGConfigSetUseWebDefaults(YGConfigRef config, bool enabled); + +/** + * Whether the configuration is set to use web defaults + */ +YG_EXPORT bool YGConfigGetUseWebDefaults(YGConfigConstRef config); + +/** + * Yoga will by deafult round final layout positions and dimensions to the + * nearst point. `pointScaleFactor` controls the density of the grid used for + * layout rounding (e.g. to round to the closest display pixel). + * + * May be set to 0.0f to avoid rounding the layout results. + */ +YG_EXPORT void YGConfigSetPointScaleFactor( + YGConfigRef config, + float pixelsInPoint); + +/** + * Get the currently set point scale factor + */ +YG_EXPORT float YGConfigGetPointScaleFactor(YGConfigConstRef config); + +/** + * Configures how Yoga balances W3C conformance vs compatibility with layouts + * created against earlier versions of Yoga. + * + * By deafult Yoga will prioritize W3C conformance. `Errata` may be set to ask + * Yoga to produce specific incorrect behaviors. E.g. `YGConfigSetErrata(config, + * YGErrataPositionStaticBehavesLikeRelative)`. + * + * YGErrata is a bitmask, and multiple errata may be set at once. Predfined + * constants exist for convenience: + * 1. YGErrataNone: No errata + * 2. YGErrataClassic: Match layout behaviors of Yoga 1.x + * 3. YGErrataAll: Match layout behaviors of Yoga 1.x, including + * `UseLegacyStretchBehaviour` + */ +YG_EXPORT void YGConfigSetErrata(YGConfigRef config, YGErrata errata); + +/** + * Get the currently set errata + */ +YG_EXPORT YGErrata YGConfigGetErrata(YGConfigConstRef config); + +/** + * Function pointer type for YGConfigSetLogger + */ +typedef int (*YGLogger)( + YGConfigConstRef config, + YGNodeConstRef node, + YGLogLevel level, + const char* format, + va_list args); + +/** + * Set a custom log function for to use when logging diagnostics or fatal + * errors. + */ +YG_EXPORT void YGConfigSetLogger(YGConfigRef config, YGLogger logger); + +/** + * Sets an arbitrary context pointer on the config which may be read from during + * callbacks + */ +YG_EXPORT void YGConfigSetContext(YGConfigRef config, void* context); + +/** + * Gets the currently set context + */ +YG_EXPORT void* YGConfigGetContext(YGConfigConstRef config); + +/** + * Function pointer type for YGConfigSetCloneNodeFunc + */ +typedef YGNodeRef (*YGCloneNodeFunc)( + YGNodeConstRef oldNode, + YGNodeConstRef owner, + size_t childIndex); + +/** + * Enable an experimental/unsupported feature in Yoga. + */ +YG_EXPORT void YGConfigSetExperimentalFeatureEnabled( + YGConfigRef config, + YGExperimentalFeature feature, + bool enabled); + +/** + * Whether an experimental feature is set. + */ +YG_EXPORT bool YGConfigIsExperimentalFeatureEnabled( + YGConfigConstRef config, + YGExperimentalFeature feature); + +/** + * Sets a callback, called during layout, to create a new mutable Yoga node if + * Yoga must write to it and its owner is not its parent observed during layout. + */ +YG_EXPORT void YGConfigSetCloneNodeFunc( + YGConfigRef config, + YGCloneNodeFunc callback); + +/** + * Allows printing the Yoga node tree during layout for debugging purposes. + */ +YG_EXPORT void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled); + +YG_EXTERN_C_END diff --git a/yoga/YGNode.cpp b/yoga/YGNode.cpp new file mode 100644 index 0000000000..c928f53535 --- /dev/null +++ b/yoga/YGNode.cpp @@ -0,0 +1,365 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include + +using namespace facebook; +using namespace facebook::yoga; + +YGNodeRef YGNodeNew(void) { + return YGNodeNewWithConfig(YGConfigGetDefault()); +} + +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(node, {config}); + + return node; +} + +YGNodeRef YGNodeClone(YGNodeConstRef oldNodeRef) { + auto oldNode = resolveRef(oldNodeRef); + const auto node = new yoga::Node(*oldNode); + Event::publish(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(); + YGNodeFinalize(node); +} + +void YGNodeFreeRecursive(YGNodeRef rootRef) { + 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); + } + } + YGNodeFree(root); +} + +void YGNodeFinalize(const YGNodeRef node) { + Event::publish(node, {YGNodeGetConfig(node)}); + delete resolveRef(node); +} + +void YGNodeReset(YGNodeRef node) { + resolveRef(node)->reset(); +} + +void YGNodeCalculateLayout( + const YGNodeRef node, + const float ownerWidth, + const float ownerHeight, + const YGDirection ownerDirection) { + yoga::calculateLayout( + resolveRef(node), ownerWidth, ownerHeight, scopedEnum(ownerDirection)); +} + +bool YGNodeGetHasNewLayout(YGNodeConstRef node) { + return resolveRef(node)->getHasNewLayout(); +} + +void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout) { + resolveRef(node)->setHasNewLayout(hasNewLayout); +} + +bool YGNodeIsDirty(YGNodeConstRef node) { + return resolveRef(node)->isDirty(); +} + +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 YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc) { + resolveRef(node)->setDirtiedFunc(dirtiedFunc); +} + +YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeConstRef node) { + return resolveRef(node)->getDirtiedFunc(); +} + +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(childrenRefs); + + if (!owner) { + return; + } + + const std::vector 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 YGNodeSetConfig(YGNodeRef node, YGConfigRef config) { + resolveRef(node)->setConfig(resolveRef(config)); +} + +YGConfigConstRef YGNodeGetConfig(YGNodeRef node) { + return resolveRef(node)->getConfig(); +} + +void YGNodeSetContext(YGNodeRef node, void* context) { + return resolveRef(node)->setContext(context); +} + +void* YGNodeGetContext(YGNodeConstRef node) { + return resolveRef(node)->getContext(); +} + +void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc) { + resolveRef(node)->setMeasureFunc(measureFunc); +} + +bool YGNodeHasMeasureFunc(YGNodeConstRef node) { + return resolveRef(node)->hasMeasureFunc(); +} + +void YGNodeSetBaselineFunc(YGNodeRef node, YGBaselineFunc baselineFunc) { + resolveRef(node)->setBaselineFunc(baselineFunc); +} + +bool YGNodeHasBaselineFunc(YGNodeConstRef node) { + return resolveRef(node)->hasBaselineFunc(); +} + +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 YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType) { + return resolveRef(node)->setNodeType(scopedEnum(nodeType)); +} + +YGNodeType YGNodeGetNodeType(YGNodeConstRef node) { + return unscopedEnum(resolveRef(node)->getNodeType()); +} + +void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc) { + resolveRef(node)->setPrintFunc(printFunc); +} + +#ifdef DEBUG +void YGNodePrint(const YGNodeConstRef node, const YGPrintOptions options) { + yoga::print(resolveRef(node), scopedEnum(options)); +} +#endif + +// TODO: This leaks internal details to 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)); +} diff --git a/yoga/YGNode.h b/yoga/YGNode.h new file mode 100644 index 0000000000..b99432c181 --- /dev/null +++ b/yoga/YGNode.h @@ -0,0 +1,283 @@ +/* + * 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 +#include + +#include +#include +#include + +YG_EXTERN_C_BEGIN + +/** + * Handle to a mutable Yoga Node + */ +typedef struct YGNode* YGNodeRef; + +/** + * Handle to an immutable Yoga Node + */ +typedef const struct YGNode* YGNodeConstRef; + +/** + * Heap allocates and returns a new Yoga node using Yoga settings. + */ +YG_EXPORT YGNodeRef YGNodeNew(void); + +/** + * Heap allocates and returns a new Yoga node, with customized settings. + */ +YG_EXPORT YGNodeRef YGNodeNewWithConfig(YGConfigConstRef config); + +/** + * Returns a mutable copy of an existing node, with the same context and + * children, but no owner set. Does not call the function set by + * YGConfigSetCloneNodeFunc(). + */ +YG_EXPORT YGNodeRef YGNodeClone(YGNodeConstRef node); + +/** + * Frees the Yoga node, disconnecting it from its owner and children. + */ +YG_EXPORT void YGNodeFree(YGNodeRef node); + +/** + * Frees the subtree of Yoga nodes rooted at the given node. + */ +YG_EXPORT void YGNodeFreeRecursive(YGNodeRef node); + +/** + * Frees the Yoga node without disconnecting it from its owner or children. + * Allows garbage collecting Yoga nodes in parallel when the entire tree is + * unrechable. + */ +YG_EXPORT void YGNodeFinalize(YGNodeRef node); + +/** + * Resets the node to its default state. + */ +YG_EXPORT void YGNodeReset(YGNodeRef node); + +/** + * Calculates the layout of the tree rooted at the given node. + * + * Layout results may be read after calling YGNodeCalculateLayout() using + * functions like YGNodeLayoutGetLeft(), YGNodeLayoutGetTop(), etc. + * + * YGNodeGetHasNewLayout() may be read to know if the layout of the node or its + * subtrees may have changed since the last time YGNodeCalculate() was called. + */ +YG_EXPORT void YGNodeCalculateLayout( + YGNodeRef node, + float availableWidth, + float availableHeight, + YGDirection ownerDirection); + +/** + * Whether the given node may have new layout results. Must be reset by calling + * YGNodeSetHasNewLayout(). + */ +YG_EXPORT bool YGNodeGetHasNewLayout(YGNodeConstRef node); + +/** + * Sets whether a nodes layout is considered new. + */ +YG_EXPORT void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout); + +/** + * Whether the node's layout results are dirty due to it or its children + * changing. + */ +YG_EXPORT bool YGNodeIsDirty(YGNodeConstRef node); + +/** + * Marks a node with custom measure function as dirty. + */ +YG_EXPORT void YGNodeMarkDirty(YGNodeRef node); + +typedef void (*YGDirtiedFunc)(YGNodeConstRef node); + +/** + * Called when a change is made to the Yoga tree which dirties this node. + */ +YG_EXPORT void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc); + +/** + * Returns a dirtied func if set. + */ +YG_EXPORT YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeConstRef node); + +/** + * Inserts a child node at the given index. + */ +YG_EXPORT void YGNodeInsertChild(YGNodeRef node, YGNodeRef child, size_t index); + +/** + * Replaces the child node at a given index with a new one. + */ +YG_EXPORT void YGNodeSwapChild(YGNodeRef node, YGNodeRef child, size_t index); + +/** + * Removes the given child node + */ +YG_EXPORT void YGNodeRemoveChild(YGNodeRef node, YGNodeRef child); + +/** + * Removes all children nodes + */ +YG_EXPORT void YGNodeRemoveAllChildren(YGNodeRef node); + +/** + * Sets children according to the given list of nodes + */ +YG_EXPORT void +YGNodeSetChildren(YGNodeRef owner, const YGNodeRef* children, size_t count); + +/** + * Get the child node at a given index + */ +YG_EXPORT YGNodeRef YGNodeGetChild(YGNodeRef node, size_t index); + +/** + * The number of child nodes + */ +YG_EXPORT size_t YGNodeGetChildCount(YGNodeConstRef node); + +/** + * Get the parent/owner currently set for a node + */ +YG_EXPORT YGNodeRef YGNodeGetOwner(YGNodeRef node); + +/** + * Get the parent/owner currently set for a node + */ +YG_EXPORT YGNodeRef YGNodeGetParent(YGNodeRef node); + +/** + * Set a new config for the node after creation + */ +YG_EXPORT void YGNodeSetConfig(YGNodeRef node, YGConfigRef config); + +/** + * Get the config currently set on the node + */ +YG_EXPORT YGConfigConstRef YGNodeGetConfig(YGNodeRef node); + +/** + * Sets extra data on the Yoga node which may be read from during callbacks. + */ +YG_EXPORT void YGNodeSetContext(YGNodeRef node, void* context); + +/** + * Returns the context or NULL if no context has been set. + */ +YG_EXPORT void* YGNodeGetContext(YGNodeConstRef node); + +typedef struct YGSize { + float width; + float height; +} YGSize; + +/** + * @returns the size of the leaf node, measured under the given contraints + */ +typedef YGSize (*YGMeasureFunc)( + YGNodeConstRef node, + float width, + YGMeasureMode widthMode, + float height, + YGMeasureMode heightMode); + +/** + * Allows providing custom measurements for a Yoga leaf node (usually for + * measuring text). YGNodeMarkDirty() must be set if content effecting the + * measurements of the node changes. + */ +YG_EXPORT void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc); + +/** + * Whether a measure function is set. + */ +YG_EXPORT bool YGNodeHasMeasureFunc(YGNodeConstRef node); + +/** + * @returns a defined offet to baseline (ascent) + */ +typedef float (*YGBaselineFunc)(YGNodeConstRef node, float width, float height); + +/** + * Set a custom function for determining the text baseline for use in baseline + * alignment. + */ +YG_EXPORT void YGNodeSetBaselineFunc( + YGNodeRef node, + YGBaselineFunc baselineFunc); + +/** + * Whether a baseline function is set. + */ +YG_EXPORT bool YGNodeHasBaselineFunc(YGNodeConstRef node); + +/** + * Sets this node should be considered the reference baseline among siblings. + */ +YG_EXPORT void YGNodeSetIsReferenceBaseline( + YGNodeRef node, + bool isReferenceBaseline); + +/** + * Whether this node is set as the reference baseline. + */ +YG_EXPORT bool YGNodeIsReferenceBaseline(YGNodeConstRef node); + +/** + * Sets whether a leaf node's layout results may be truncated during layout + * rounding. + */ +YG_EXPORT void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType); + +/** + * Wwhether a leaf node's layout results may be truncated during layout + * rounding. + */ +YG_EXPORT YGNodeType YGNodeGetNodeType(YGNodeConstRef node); + +typedef void (*YGPrintFunc)(YGNodeConstRef node); + +/** + * Set a function to be called when configured to print nodes during layout for + * debugging + */ +YG_EXPORT void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc); + +/** + * Print a node to log output + */ +YG_EXPORT void YGNodePrint(YGNodeConstRef node, YGPrintOptions options); + +/** + * @deprecated + */ +YG_EXPORT 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); + +YG_EXTERN_C_END diff --git a/yoga/YGNodeLayout.cpp b/yoga/YGNodeLayout.cpp new file mode 100644 index 0000000000..39f67f9dc9 --- /dev/null +++ b/yoga/YGNodeLayout.cpp @@ -0,0 +1,90 @@ +/* + * 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 +#include +#include + +using namespace facebook; +using namespace facebook::yoga; + +namespace { + +template +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().dimension(Dimension::Width); +} + +float YGNodeLayoutGetHeight(const YGNodeConstRef node) { + return resolveRef(node)->getLayout().dimension(Dimension::Height); +} + +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); +} diff --git a/yoga/YGNodeLayout.h b/yoga/YGNodeLayout.h new file mode 100644 index 0000000000..02ead5883b --- /dev/null +++ b/yoga/YGNodeLayout.h @@ -0,0 +1,35 @@ +/* + * 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 + +#include +#include +#include + +YG_EXTERN_C_BEGIN + +YG_EXPORT float YGNodeLayoutGetLeft(YGNodeConstRef node); +YG_EXPORT float YGNodeLayoutGetTop(YGNodeConstRef node); +YG_EXPORT float YGNodeLayoutGetRight(YGNodeConstRef node); +YG_EXPORT float YGNodeLayoutGetBottom(YGNodeConstRef node); +YG_EXPORT float YGNodeLayoutGetWidth(YGNodeConstRef node); +YG_EXPORT float YGNodeLayoutGetHeight(YGNodeConstRef node); +YG_EXPORT YGDirection YGNodeLayoutGetDirection(YGNodeConstRef node); +YG_EXPORT bool YGNodeLayoutGetHadOverflow(YGNodeConstRef node); + +// Get the computed values for these nodes after performing layout. If they were +// set using point values then the returned value will be the same as +// YGNodeStyleGetXXX. However if they were set using a percentage value then the +// returned value is the computed value used during layout. +YG_EXPORT float YGNodeLayoutGetMargin(YGNodeConstRef node, YGEdge edge); +YG_EXPORT float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge); +YG_EXPORT float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge); + +YG_EXTERN_C_END diff --git a/yoga/YGNodeStyle.cpp b/yoga/YGNodeStyle.cpp new file mode 100644 index 0000000000..57d352cd01 --- /dev/null +++ b/yoga/YGNodeStyle.cpp @@ -0,0 +1,442 @@ +/* + * 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 +#include +#include + +using namespace facebook; +using namespace facebook::yoga; + +namespace { + +template +void updateStyle( + yoga::Node* node, + T value, + NeedsUpdate&& needsUpdate, + Update&& update) { + if (needsUpdate(node->getStyle(), value)) { + update(node->getStyle(), value); + node->markDirtyAndPropagate(); + } +} + +template +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 +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; }); +} + +template +void updateIndexedStyleProp(YGNodeRef node, IdxT idx, CompactValue value) { + updateStyle( + resolveRef(node), + value, + [idx](Style& s, CompactValue x) { return (s.*GetterT)(idx) != x; }, + [idx](Style& s, CompactValue x) { (s.*SetterT)(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 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(); + } +} + +void YGNodeStyleSetDirection(const YGNodeRef node, const YGDirection value) { + updateStyle(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( + node, &Style::flexDirection, scopedEnum(flexDirection)); +} + +YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeConstRef node) { + return unscopedEnum(resolveRef(node)->getStyle().flexDirection()); +} + +void YGNodeStyleSetJustifyContent( + const YGNodeRef node, + const YGJustify justifyContent) { + updateStyle( + node, &Style::justifyContent, scopedEnum(justifyContent)); +} + +YGJustify YGNodeStyleGetJustifyContent(const YGNodeConstRef node) { + return unscopedEnum(resolveRef(node)->getStyle().justifyContent()); +} + +void YGNodeStyleSetAlignContent( + const YGNodeRef node, + const YGAlign alignContent) { + updateStyle( + node, &Style::alignContent, scopedEnum(alignContent)); +} + +YGAlign YGNodeStyleGetAlignContent(const YGNodeConstRef node) { + return unscopedEnum(resolveRef(node)->getStyle().alignContent()); +} + +void YGNodeStyleSetAlignItems(const YGNodeRef node, const YGAlign alignItems) { + updateStyle( + node, &Style::alignItems, scopedEnum(alignItems)); +} + +YGAlign YGNodeStyleGetAlignItems(const YGNodeConstRef node) { + return unscopedEnum(resolveRef(node)->getStyle().alignItems()); +} + +void YGNodeStyleSetAlignSelf(const YGNodeRef node, const YGAlign alignSelf) { + updateStyle( + node, &Style::alignSelf, scopedEnum(alignSelf)); +} + +YGAlign YGNodeStyleGetAlignSelf(const YGNodeConstRef node) { + return unscopedEnum(resolveRef(node)->getStyle().alignSelf()); +} + +void YGNodeStyleSetPositionType( + const YGNodeRef node, + const YGPositionType positionType) { + updateStyle( + node, &Style::positionType, scopedEnum(positionType)); +} + +YGPositionType YGNodeStyleGetPositionType(const YGNodeConstRef node) { + return unscopedEnum(resolveRef(node)->getStyle().positionType()); +} + +void YGNodeStyleSetFlexWrap(const YGNodeRef node, const YGWrap flexWrap) { + updateStyle( + node, &Style::flexWrap, scopedEnum(flexWrap)); +} + +YGWrap YGNodeStyleGetFlexWrap(const YGNodeConstRef node) { + return unscopedEnum(resolveRef(node)->getStyle().flexWrap()); +} + +void YGNodeStyleSetOverflow(const YGNodeRef node, const YGOverflow overflow) { + updateStyle( + node, &Style::overflow, scopedEnum(overflow)); +} + +YGOverflow YGNodeStyleGetOverflow(const YGNodeConstRef node) { + return unscopedEnum(resolveRef(node)->getStyle().overflow()); +} + +void YGNodeStyleSetDisplay(const YGNodeRef node, const YGDisplay display) { + updateStyle(node, &Style::display, scopedEnum(display)); +} + +YGDisplay YGNodeStyleGetDisplay(const YGNodeConstRef node) { + return unscopedEnum(resolveRef(node)->getStyle().display()); +} + +void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { + updateStyle(node, &Style::flex, FloatOptional{flex}); +} + +float YGNodeStyleGetFlex(const YGNodeConstRef nodeRef) { + const auto node = resolveRef(nodeRef); + return node->getStyle().flex().isUndefined() + ? YGUndefined + : node->getStyle().flex().unwrap(); +} + +void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) { + updateStyle( + node, &Style::flexGrow, FloatOptional{flexGrow}); +} + +float YGNodeStyleGetFlexGrow(const YGNodeConstRef nodeRef) { + const auto node = resolveRef(nodeRef); + return node->getStyle().flexGrow().isUndefined() + ? Style::DefaultFlexGrow + : node->getStyle().flexGrow().unwrap(); +} + +void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) { + updateStyle( + node, &Style::flexShrink, FloatOptional{flexShrink}); +} + +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(); +} + +void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) { + auto value = CompactValue::ofMaybe(flexBasis); + updateStyle(node, &Style::flexBasis, value); +} + +void YGNodeStyleSetFlexBasisPercent( + const YGNodeRef node, + const float flexBasisPercent) { + auto value = CompactValue::ofMaybe(flexBasisPercent); + updateStyle(node, &Style::flexBasis, value); +} + +void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) { + updateStyle( + node, &Style::flexBasis, CompactValue::ofAuto()); +} + +YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef node) { + YGValue flexBasis = resolveRef(node)->getStyle().flexBasis(); + if (flexBasis.unit == YGUnitUndefined || flexBasis.unit == YGUnitAuto) { + flexBasis.value = YGUndefined; + } + return flexBasis; +} + +void YGNodeStyleSetPosition(YGNodeRef node, YGEdge edge, float points) { + auto value = CompactValue::ofMaybe(points); + updateIndexedStyleProp( + node, &Style::position, edge, value); +} + +void YGNodeStyleSetPositionPercent(YGNodeRef node, YGEdge edge, float percent) { + auto value = CompactValue::ofMaybe(percent); + updateIndexedStyleProp( + 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(points); + updateIndexedStyleProp(node, &Style::margin, edge, value); +} + +void YGNodeStyleSetMarginPercent(YGNodeRef node, YGEdge edge, float percent) { + auto value = CompactValue::ofMaybe(percent); + updateIndexedStyleProp(node, &Style::margin, edge, value); +} + +void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge) { + updateIndexedStyleProp( + 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(points); + updateIndexedStyleProp( + node, &Style::padding, edge, value); +} + +void YGNodeStyleSetPaddingPercent(YGNodeRef node, YGEdge edge, float percent) { + auto value = CompactValue::ofMaybe(percent); + updateIndexedStyleProp( + node, &Style::padding, edge, value); +} + +YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge) { + return resolveRef(node)->getStyle().padding()[edge]; +} + +void YGNodeStyleSetBorder( + const YGNodeRef node, + const YGEdge edge, + const float border) { + auto value = CompactValue::ofMaybe(border); + updateIndexedStyleProp(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()) { + return YGUndefined; + } + + return static_cast(border).value; +} + +void YGNodeStyleSetGap( + const YGNodeRef node, + const YGGutter gutter, + const float gapLength) { + auto length = CompactValue::ofMaybe(gapLength); + updateIndexedStyleProp<&Style::gap, &Style::setGap>( + node, scopedEnum(gutter), length); +} + +float YGNodeStyleGetGap(const YGNodeConstRef node, const YGGutter gutter) { + auto gapLength = resolveRef(node)->getStyle().gap(scopedEnum(gutter)); + if (gapLength.isUndefined() || gapLength.isAuto()) { + return YGUndefined; + } + + return static_cast(gapLength).value; +} + +void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) { + updateStyle( + node, &Style::aspectRatio, FloatOptional{aspectRatio}); +} + +float YGNodeStyleGetAspectRatio(const YGNodeConstRef node) { + const FloatOptional op = resolveRef(node)->getStyle().aspectRatio(); + return op.isUndefined() ? YGUndefined : op.unwrap(); +} + +void YGNodeStyleSetWidth(YGNodeRef node, float points) { + auto value = CompactValue::ofMaybe(points); + updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( + node, Dimension::Width, value); +} + +void YGNodeStyleSetWidthPercent(YGNodeRef node, float percent) { + auto value = CompactValue::ofMaybe(percent); + updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( + node, Dimension::Width, value); +} + +void YGNodeStyleSetWidthAuto(YGNodeRef node) { + updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( + node, Dimension::Width, CompactValue::ofAuto()); +} + +YGValue YGNodeStyleGetWidth(YGNodeConstRef node) { + return resolveRef(node)->getStyle().dimension(Dimension::Width); +} + +void YGNodeStyleSetHeight(YGNodeRef node, float points) { + auto value = CompactValue::ofMaybe(points); + updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( + node, Dimension::Height, value); +} + +void YGNodeStyleSetHeightPercent(YGNodeRef node, float percent) { + auto value = CompactValue::ofMaybe(percent); + updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( + node, Dimension::Height, value); +} + +void YGNodeStyleSetHeightAuto(YGNodeRef node) { + updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( + node, Dimension::Height, CompactValue::ofAuto()); +} + +YGValue YGNodeStyleGetHeight(YGNodeConstRef node) { + return resolveRef(node)->getStyle().dimension(Dimension::Height); +} + +void YGNodeStyleSetMinWidth(const YGNodeRef node, const float minWidth) { + auto value = CompactValue::ofMaybe(minWidth); + updateIndexedStyleProp<&Style::minDimension, &Style::setMinDimension>( + node, Dimension::Width, value); +} + +void YGNodeStyleSetMinWidthPercent(const YGNodeRef node, const float minWidth) { + auto value = CompactValue::ofMaybe(minWidth); + updateIndexedStyleProp<&Style::minDimension, &Style::setMinDimension>( + node, Dimension::Width, value); +} + +YGValue YGNodeStyleGetMinWidth(const YGNodeConstRef node) { + return resolveRef(node)->getStyle().minDimension(Dimension::Width); +} + +void YGNodeStyleSetMinHeight(const YGNodeRef node, const float minHeight) { + auto value = CompactValue::ofMaybe(minHeight); + updateIndexedStyleProp<&Style::minDimension, &Style::setMinDimension>( + node, Dimension::Height, value); +} + +void YGNodeStyleSetMinHeightPercent( + const YGNodeRef node, + const float minHeight) { + auto value = CompactValue::ofMaybe(minHeight); + updateIndexedStyleProp<&Style::minDimension, &Style::setMinDimension>( + node, Dimension::Height, value); +} + +YGValue YGNodeStyleGetMinHeight(const YGNodeConstRef node) { + return resolveRef(node)->getStyle().minDimension(Dimension::Height); +} + +void YGNodeStyleSetMaxWidth(const YGNodeRef node, const float maxWidth) { + auto value = CompactValue::ofMaybe(maxWidth); + updateIndexedStyleProp<&Style::maxDimension, &Style::setMaxDimension>( + node, Dimension::Width, value); +} + +void YGNodeStyleSetMaxWidthPercent(const YGNodeRef node, const float maxWidth) { + auto value = CompactValue::ofMaybe(maxWidth); + updateIndexedStyleProp<&Style::maxDimension, &Style::setMaxDimension>( + node, Dimension::Width, value); +} + +YGValue YGNodeStyleGetMaxWidth(const YGNodeConstRef node) { + return resolveRef(node)->getStyle().maxDimension(Dimension::Width); +} + +void YGNodeStyleSetMaxHeight(const YGNodeRef node, const float maxHeight) { + auto value = CompactValue::ofMaybe(maxHeight); + updateIndexedStyleProp<&Style::maxDimension, &Style::setMaxDimension>( + node, Dimension::Height, value); +} + +void YGNodeStyleSetMaxHeightPercent( + const YGNodeRef node, + const float maxHeight) { + auto value = CompactValue::ofMaybe(maxHeight); + updateIndexedStyleProp<&Style::maxDimension, &Style::setMaxDimension>( + node, Dimension::Height, value); +} + +YGValue YGNodeStyleGetMaxHeight(const YGNodeConstRef node) { + return resolveRef(node)->getStyle().maxDimension(Dimension::Height); +} diff --git a/yoga/YGNodeStyle.h b/yoga/YGNodeStyle.h new file mode 100644 index 0000000000..09727087ba --- /dev/null +++ b/yoga/YGNodeStyle.h @@ -0,0 +1,123 @@ +/* + * 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 + +#include +#include + +YG_EXTERN_C_BEGIN + +YG_EXPORT void YGNodeCopyStyle(YGNodeRef dstNode, YGNodeConstRef srcNode); + +YG_EXPORT void YGNodeStyleSetDirection(YGNodeRef node, YGDirection direction); +YG_EXPORT YGDirection YGNodeStyleGetDirection(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetFlexDirection( + YGNodeRef node, + YGFlexDirection flexDirection); +YG_EXPORT YGFlexDirection YGNodeStyleGetFlexDirection(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetJustifyContent( + YGNodeRef node, + YGJustify justifyContent); +YG_EXPORT YGJustify YGNodeStyleGetJustifyContent(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetAlignContent(YGNodeRef node, YGAlign alignContent); +YG_EXPORT YGAlign YGNodeStyleGetAlignContent(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetAlignItems(YGNodeRef node, YGAlign alignItems); +YG_EXPORT YGAlign YGNodeStyleGetAlignItems(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetAlignSelf(YGNodeRef node, YGAlign alignSelf); +YG_EXPORT YGAlign YGNodeStyleGetAlignSelf(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetPositionType( + YGNodeRef node, + YGPositionType positionType); +YG_EXPORT YGPositionType YGNodeStyleGetPositionType(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetFlexWrap(YGNodeRef node, YGWrap flexWrap); +YG_EXPORT YGWrap YGNodeStyleGetFlexWrap(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetOverflow(YGNodeRef node, YGOverflow overflow); +YG_EXPORT YGOverflow YGNodeStyleGetOverflow(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetDisplay(YGNodeRef node, YGDisplay display); +YG_EXPORT YGDisplay YGNodeStyleGetDisplay(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetFlex(YGNodeRef node, float flex); +YG_EXPORT float YGNodeStyleGetFlex(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetFlexGrow(YGNodeRef node, float flexGrow); +YG_EXPORT float YGNodeStyleGetFlexGrow(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetFlexShrink(YGNodeRef node, float flexShrink); +YG_EXPORT float YGNodeStyleGetFlexShrink(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetFlexBasis(YGNodeRef node, float flexBasis); +YG_EXPORT void YGNodeStyleSetFlexBasisPercent(YGNodeRef node, float flexBasis); +YG_EXPORT void YGNodeStyleSetFlexBasisAuto(YGNodeRef node); +YG_EXPORT YGValue YGNodeStyleGetFlexBasis(YGNodeConstRef node); + +YG_EXPORT void +YGNodeStyleSetPosition(YGNodeRef node, YGEdge edge, float position); +YG_EXPORT void +YGNodeStyleSetPositionPercent(YGNodeRef node, YGEdge edge, float position); +YG_EXPORT YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge); + +YG_EXPORT void YGNodeStyleSetMargin(YGNodeRef node, YGEdge edge, float margin); +YG_EXPORT void +YGNodeStyleSetMarginPercent(YGNodeRef node, YGEdge edge, float margin); +YG_EXPORT void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge); +YG_EXPORT YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge); + +YG_EXPORT void +YGNodeStyleSetPadding(YGNodeRef node, YGEdge edge, float padding); +YG_EXPORT void +YGNodeStyleSetPaddingPercent(YGNodeRef node, YGEdge edge, float padding); +YG_EXPORT YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge); + +YG_EXPORT void YGNodeStyleSetBorder(YGNodeRef node, YGEdge edge, float border); +YG_EXPORT float YGNodeStyleGetBorder(YGNodeConstRef node, YGEdge edge); + +YG_EXPORT void +YGNodeStyleSetGap(YGNodeRef node, YGGutter gutter, float gapLength); +YG_EXPORT float YGNodeStyleGetGap(YGNodeConstRef node, YGGutter gutter); + +YG_EXPORT void YGNodeStyleSetWidth(YGNodeRef node, float width); +YG_EXPORT void YGNodeStyleSetWidthPercent(YGNodeRef node, float width); +YG_EXPORT void YGNodeStyleSetWidthAuto(YGNodeRef node); +YG_EXPORT YGValue YGNodeStyleGetWidth(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetHeight(YGNodeRef node, float height); +YG_EXPORT void YGNodeStyleSetHeightPercent(YGNodeRef node, float height); +YG_EXPORT void YGNodeStyleSetHeightAuto(YGNodeRef node); +YG_EXPORT YGValue YGNodeStyleGetHeight(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetMinWidth(YGNodeRef node, float minWidth); +YG_EXPORT void YGNodeStyleSetMinWidthPercent(YGNodeRef node, float minWidth); +YG_EXPORT YGValue YGNodeStyleGetMinWidth(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetMinHeight(YGNodeRef node, float minHeight); +YG_EXPORT void YGNodeStyleSetMinHeightPercent(YGNodeRef node, float minHeight); +YG_EXPORT YGValue YGNodeStyleGetMinHeight(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetMaxWidth(YGNodeRef node, float maxWidth); +YG_EXPORT void YGNodeStyleSetMaxWidthPercent(YGNodeRef node, float maxWidth); +YG_EXPORT YGValue YGNodeStyleGetMaxWidth(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetMaxHeight(YGNodeRef node, float maxHeight); +YG_EXPORT void YGNodeStyleSetMaxHeightPercent(YGNodeRef node, float maxHeight); +YG_EXPORT YGValue YGNodeStyleGetMaxHeight(YGNodeConstRef node); + +YG_EXPORT void YGNodeStyleSetAspectRatio(YGNodeRef node, float aspectRatio); +YG_EXPORT float YGNodeStyleGetAspectRatio(YGNodeConstRef node); + +YG_EXTERN_C_END diff --git a/yoga/YGPixelGrid.cpp b/yoga/YGPixelGrid.cpp new file mode 100644 index 0000000000..a855a292c2 --- /dev/null +++ b/yoga/YGPixelGrid.cpp @@ -0,0 +1,22 @@ +/* + * 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 + +#include + +using namespace facebook; +using namespace facebook::yoga; + +float YGRoundValueToPixelGrid( + const double value, + const double pointScaleFactor, + const bool forceCeil, + const bool forceFloor) { + return yoga::roundValueToPixelGrid( + value, pointScaleFactor, forceCeil, forceFloor); +} diff --git a/yoga/YGPixelGrid.h b/yoga/YGPixelGrid.h new file mode 100644 index 0000000000..e2a6aeb698 --- /dev/null +++ b/yoga/YGPixelGrid.h @@ -0,0 +1,29 @@ +/* + * 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 + +#include +#include +#include + +YG_EXTERN_C_BEGIN + +/** + * Rounds a point value to the nearest whole pixel, given a pointScaleFactor + * describing pixel density. + * @returns the rounded value in points + */ +YG_EXPORT float YGRoundValueToPixelGrid( + double value, + double pointScaleFactor, + bool forceCeil, + bool forceFloor); + +YG_EXTERN_C_END diff --git a/yoga/YGValue.cpp b/yoga/YGValue.cpp index 194d22caa8..7a469b9cc4 100644 --- a/yoga/YGValue.cpp +++ b/yoga/YGValue.cpp @@ -6,7 +6,15 @@ */ #include +#include + +using namespace facebook; +using namespace facebook::yoga; const YGValue YGValueZero = {0, YGUnitPoint}; const YGValue YGValueUndefined = {YGUndefined, YGUnitUndefined}; const YGValue YGValueAuto = {YGUndefined, YGUnitAuto}; + +bool YGFloatIsUndefined(const float value) { + return yoga::isUndefined(value); +} diff --git a/yoga/YGValue.h b/yoga/YGValue.h index d6051070b0..400a4b8fb2 100644 --- a/yoga/YGValue.h +++ b/yoga/YGValue.h @@ -7,30 +7,50 @@ #pragma once +#include +#include + #include #include YG_EXTERN_C_BEGIN +/** + * Float value to represent "undefined" in style values + */ +#define YGUndefined NAN + +/** + * Structure used to represent a dimension in a style + */ typedef struct YGValue { float value; YGUnit unit; } YGValue; +/** + * Constant for a dimension of "auto" + */ YG_EXPORT extern const YGValue YGValueAuto; + +/** + * Constant for a dimension which is not defined + */ YG_EXPORT extern const YGValue YGValueUndefined; + +/** + * Constant for a dimension that is zero-length + */ YG_EXPORT extern const YGValue YGValueZero; -YG_EXTERN_C_END +/** + * Whether a dimension represented as a float is defined + */ +YG_EXPORT bool YGFloatIsUndefined(float value); -#ifdef __cplusplus -#include -constexpr float YGUndefined = std::numeric_limits::quiet_NaN(); -#else -#include -#define YGUndefined NAN -#endif +YG_EXTERN_C_END +// Equality operators for comparison of YGValue in C++ #ifdef __cplusplus inline bool operator==(const YGValue& lhs, const YGValue& rhs) { if (lhs.unit != rhs.unit) { diff --git a/yoga/Yoga-internal.h b/yoga/Yoga-internal.h deleted file mode 100644 index 7c1caaa378..0000000000 --- a/yoga/Yoga-internal.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 -#include -#include - -#include - -YG_EXTERN_C_BEGIN - -// Deallocates a Yoga Node. Unlike YGNodeFree, does not remove the node from -// its parent or children. -YG_EXPORT void YGNodeDeallocate(YGNodeRef node); - -YG_EXTERN_C_END diff --git a/yoga/Yoga.cpp b/yoga/Yoga.cpp deleted file mode 100644 index 5109223fe3..0000000000 --- a/yoga/Yoga.cpp +++ /dev/null @@ -1,959 +0,0 @@ -/* - * 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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -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(); -} - -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(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(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(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(childrenRefs); - - if (!owner) { - return; - } - - const std::vector 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 -void updateStyle( - yoga::Node* node, - T value, - NeedsUpdate&& needsUpdate, - Update&& update) { - if (needsUpdate(node->getStyle(), value)) { - update(node->getStyle(), value); - node->markDirtyAndPropagate(); - } -} - -template -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 -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; }); -} - -template -void updateIndexedStyleProp(YGNodeRef node, IdxT idx, CompactValue value) { - updateStyle( - resolveRef(node), - value, - [idx](Style& s, CompactValue x) { return (s.*GetterT)(idx) != x; }, - [idx](Style& s, CompactValue x) { (s.*SetterT)(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(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( - node, &Style::flexDirection, scopedEnum(flexDirection)); -} -YGFlexDirection YGNodeStyleGetFlexDirection(const YGNodeConstRef node) { - return unscopedEnum(resolveRef(node)->getStyle().flexDirection()); -} - -void YGNodeStyleSetJustifyContent( - const YGNodeRef node, - const YGJustify justifyContent) { - updateStyle( - node, &Style::justifyContent, scopedEnum(justifyContent)); -} -YGJustify YGNodeStyleGetJustifyContent(const YGNodeConstRef node) { - return unscopedEnum(resolveRef(node)->getStyle().justifyContent()); -} - -void YGNodeStyleSetAlignContent( - const YGNodeRef node, - const YGAlign alignContent) { - updateStyle( - node, &Style::alignContent, scopedEnum(alignContent)); -} -YGAlign YGNodeStyleGetAlignContent(const YGNodeConstRef node) { - return unscopedEnum(resolveRef(node)->getStyle().alignContent()); -} - -void YGNodeStyleSetAlignItems(const YGNodeRef node, const YGAlign alignItems) { - updateStyle( - node, &Style::alignItems, scopedEnum(alignItems)); -} -YGAlign YGNodeStyleGetAlignItems(const YGNodeConstRef node) { - return unscopedEnum(resolveRef(node)->getStyle().alignItems()); -} - -void YGNodeStyleSetAlignSelf(const YGNodeRef node, const YGAlign alignSelf) { - updateStyle( - node, &Style::alignSelf, scopedEnum(alignSelf)); -} -YGAlign YGNodeStyleGetAlignSelf(const YGNodeConstRef node) { - return unscopedEnum(resolveRef(node)->getStyle().alignSelf()); -} - -void YGNodeStyleSetPositionType( - const YGNodeRef node, - const YGPositionType positionType) { - updateStyle( - node, &Style::positionType, scopedEnum(positionType)); -} -YGPositionType YGNodeStyleGetPositionType(const YGNodeConstRef node) { - return unscopedEnum(resolveRef(node)->getStyle().positionType()); -} - -void YGNodeStyleSetFlexWrap(const YGNodeRef node, const YGWrap flexWrap) { - updateStyle( - node, &Style::flexWrap, scopedEnum(flexWrap)); -} -YGWrap YGNodeStyleGetFlexWrap(const YGNodeConstRef node) { - return unscopedEnum(resolveRef(node)->getStyle().flexWrap()); -} - -void YGNodeStyleSetOverflow(const YGNodeRef node, const YGOverflow overflow) { - updateStyle( - node, &Style::overflow, scopedEnum(overflow)); -} -YGOverflow YGNodeStyleGetOverflow(const YGNodeConstRef node) { - return unscopedEnum(resolveRef(node)->getStyle().overflow()); -} - -void YGNodeStyleSetDisplay(const YGNodeRef node, const YGDisplay display) { - updateStyle(node, &Style::display, scopedEnum(display)); -} -YGDisplay YGNodeStyleGetDisplay(const YGNodeConstRef node) { - return unscopedEnum(resolveRef(node)->getStyle().display()); -} - -void YGNodeStyleSetFlex(const YGNodeRef node, const float flex) { - updateStyle(node, &Style::flex, FloatOptional{flex}); -} - -float YGNodeStyleGetFlex(const YGNodeConstRef nodeRef) { - const auto node = resolveRef(nodeRef); - return node->getStyle().flex().isUndefined() - ? YGUndefined - : node->getStyle().flex().unwrap(); -} - -void YGNodeStyleSetFlexGrow(const YGNodeRef node, const float flexGrow) { - updateStyle( - node, &Style::flexGrow, FloatOptional{flexGrow}); -} - -void YGNodeStyleSetFlexShrink(const YGNodeRef node, const float flexShrink) { - updateStyle( - node, &Style::flexShrink, FloatOptional{flexShrink}); -} - -YGValue YGNodeStyleGetFlexBasis(const YGNodeConstRef node) { - YGValue flexBasis = resolveRef(node)->getStyle().flexBasis(); - if (flexBasis.unit == YGUnitUndefined || flexBasis.unit == YGUnitAuto) { - flexBasis.value = YGUndefined; - } - return flexBasis; -} - -void YGNodeStyleSetFlexBasis(const YGNodeRef node, const float flexBasis) { - auto value = CompactValue::ofMaybe(flexBasis); - updateStyle(node, &Style::flexBasis, value); -} - -void YGNodeStyleSetFlexBasisPercent( - const YGNodeRef node, - const float flexBasisPercent) { - auto value = CompactValue::ofMaybe(flexBasisPercent); - updateStyle(node, &Style::flexBasis, value); -} - -void YGNodeStyleSetFlexBasisAuto(const YGNodeRef node) { - updateStyle( - node, &Style::flexBasis, CompactValue::ofAuto()); -} - -void YGNodeStyleSetPosition(YGNodeRef node, YGEdge edge, float points) { - auto value = CompactValue::ofMaybe(points); - updateIndexedStyleProp( - node, &Style::position, edge, value); -} -void YGNodeStyleSetPositionPercent(YGNodeRef node, YGEdge edge, float percent) { - auto value = CompactValue::ofMaybe(percent); - updateIndexedStyleProp( - 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(points); - updateIndexedStyleProp(node, &Style::margin, edge, value); -} -void YGNodeStyleSetMarginPercent(YGNodeRef node, YGEdge edge, float percent) { - auto value = CompactValue::ofMaybe(percent); - updateIndexedStyleProp(node, &Style::margin, edge, value); -} -void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge) { - updateIndexedStyleProp( - 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(points); - updateIndexedStyleProp( - node, &Style::padding, edge, value); -} -void YGNodeStyleSetPaddingPercent(YGNodeRef node, YGEdge edge, float percent) { - auto value = CompactValue::ofMaybe(percent); - updateIndexedStyleProp( - node, &Style::padding, edge, value); -} -YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge) { - return resolveRef(node)->getStyle().padding()[edge]; -} - -void YGNodeStyleSetBorder( - const YGNodeRef node, - const YGEdge edge, - const float border) { - auto value = CompactValue::ofMaybe(border); - updateIndexedStyleProp(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()) { - return YGUndefined; - } - - return static_cast(border).value; -} - -void YGNodeStyleSetGap( - const YGNodeRef node, - const YGGutter gutter, - const float gapLength) { - auto length = CompactValue::ofMaybe(gapLength); - updateIndexedStyleProp<&Style::gap, &Style::setGap>( - node, scopedEnum(gutter), length); -} - -float YGNodeStyleGetGap(const YGNodeConstRef node, const YGGutter gutter) { - auto gapLength = resolveRef(node)->getStyle().gap(scopedEnum(gutter)); - if (gapLength.isUndefined() || gapLength.isAuto()) { - return YGUndefined; - } - - return static_cast(gapLength).value; -} - -// Yoga specific properties, not compatible with flexbox specification - -float YGNodeStyleGetAspectRatio(const YGNodeConstRef node) { - const FloatOptional op = resolveRef(node)->getStyle().aspectRatio(); - return op.isUndefined() ? YGUndefined : op.unwrap(); -} - -void YGNodeStyleSetAspectRatio(const YGNodeRef node, const float aspectRatio) { - updateStyle( - node, &Style::aspectRatio, FloatOptional{aspectRatio}); -} - -void YGNodeStyleSetWidth(YGNodeRef node, float points) { - auto value = CompactValue::ofMaybe(points); - updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( - node, Dimension::Width, value); -} -void YGNodeStyleSetWidthPercent(YGNodeRef node, float percent) { - auto value = CompactValue::ofMaybe(percent); - updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( - node, Dimension::Width, value); -} -void YGNodeStyleSetWidthAuto(YGNodeRef node) { - updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( - node, Dimension::Width, CompactValue::ofAuto()); -} -YGValue YGNodeStyleGetWidth(YGNodeConstRef node) { - return resolveRef(node)->getStyle().dimension(Dimension::Width); -} - -void YGNodeStyleSetHeight(YGNodeRef node, float points) { - auto value = CompactValue::ofMaybe(points); - updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( - node, Dimension::Height, value); -} -void YGNodeStyleSetHeightPercent(YGNodeRef node, float percent) { - auto value = CompactValue::ofMaybe(percent); - updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( - node, Dimension::Height, value); -} -void YGNodeStyleSetHeightAuto(YGNodeRef node) { - updateIndexedStyleProp<&Style::dimension, &Style::setDimension>( - node, Dimension::Height, CompactValue::ofAuto()); -} -YGValue YGNodeStyleGetHeight(YGNodeConstRef node) { - return resolveRef(node)->getStyle().dimension(Dimension::Height); -} - -void YGNodeStyleSetMinWidth(const YGNodeRef node, const float minWidth) { - auto value = CompactValue::ofMaybe(minWidth); - updateIndexedStyleProp<&Style::minDimension, &Style::setMinDimension>( - node, Dimension::Width, value); -} -void YGNodeStyleSetMinWidthPercent(const YGNodeRef node, const float minWidth) { - auto value = CompactValue::ofMaybe(minWidth); - updateIndexedStyleProp<&Style::minDimension, &Style::setMinDimension>( - node, Dimension::Width, value); -} -YGValue YGNodeStyleGetMinWidth(const YGNodeConstRef node) { - return resolveRef(node)->getStyle().minDimension(Dimension::Width); -} - -void YGNodeStyleSetMinHeight(const YGNodeRef node, const float minHeight) { - auto value = CompactValue::ofMaybe(minHeight); - updateIndexedStyleProp<&Style::minDimension, &Style::setMinDimension>( - node, Dimension::Height, value); -} -void YGNodeStyleSetMinHeightPercent( - const YGNodeRef node, - const float minHeight) { - auto value = CompactValue::ofMaybe(minHeight); - updateIndexedStyleProp<&Style::minDimension, &Style::setMinDimension>( - node, Dimension::Height, value); -} -YGValue YGNodeStyleGetMinHeight(const YGNodeConstRef node) { - return resolveRef(node)->getStyle().minDimension(Dimension::Height); -} - -void YGNodeStyleSetMaxWidth(const YGNodeRef node, const float maxWidth) { - auto value = CompactValue::ofMaybe(maxWidth); - updateIndexedStyleProp<&Style::maxDimension, &Style::setMaxDimension>( - node, Dimension::Width, value); -} -void YGNodeStyleSetMaxWidthPercent(const YGNodeRef node, const float maxWidth) { - auto value = CompactValue::ofMaybe(maxWidth); - updateIndexedStyleProp<&Style::maxDimension, &Style::setMaxDimension>( - node, Dimension::Width, value); -} -YGValue YGNodeStyleGetMaxWidth(const YGNodeConstRef node) { - return resolveRef(node)->getStyle().maxDimension(Dimension::Width); -} - -void YGNodeStyleSetMaxHeight(const YGNodeRef node, const float maxHeight) { - auto value = CompactValue::ofMaybe(maxHeight); - updateIndexedStyleProp<&Style::maxDimension, &Style::setMaxDimension>( - node, Dimension::Height, value); -} -void YGNodeStyleSetMaxHeightPercent( - const YGNodeRef node, - const float maxHeight) { - auto value = CompactValue::ofMaybe(maxHeight); - updateIndexedStyleProp<&Style::maxDimension, &Style::setMaxDimension>( - node, Dimension::Height, value); -} -YGValue YGNodeStyleGetMaxHeight(const YGNodeConstRef node) { - return resolveRef(node)->getStyle().maxDimension(Dimension::Height); -} - -namespace { - -template -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().dimension(Dimension::Width); -} - -float YGNodeLayoutGetHeight(const YGNodeConstRef node) { - return resolveRef(node)->getLayout().dimension(Dimension::Height); -} - -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)); -} diff --git a/yoga/Yoga.h b/yoga/Yoga.h index 86f09fa0c4..e4b16e4441 100644 --- a/yoga/Yoga.h +++ b/yoga/Yoga.h @@ -7,315 +7,11 @@ #pragma once -#include -#include -#include -#include - +#include #include #include +#include +#include +#include +#include #include - -YG_EXTERN_C_BEGIN - -typedef struct YGSize { - float width; - float height; -} YGSize; - -typedef struct YGConfig* YGConfigRef; -typedef const struct YGConfig* YGConfigConstRef; - -typedef struct YGNode* YGNodeRef; -typedef const struct YGNode* YGNodeConstRef; - -typedef YGSize (*YGMeasureFunc)( - YGNodeConstRef node, - float width, - YGMeasureMode widthMode, - float height, - YGMeasureMode heightMode); -typedef float (*YGBaselineFunc)(YGNodeConstRef node, float width, float height); -typedef void (*YGDirtiedFunc)(YGNodeConstRef node); -typedef void (*YGPrintFunc)(YGNodeConstRef node); -typedef void (*YGNodeCleanupFunc)(YGNodeConstRef node); -typedef int (*YGLogger)( - YGConfigConstRef config, - YGNodeConstRef node, - YGLogLevel level, - const char* format, - va_list args); -typedef YGNodeRef (*YGCloneNodeFunc)( - YGNodeConstRef oldNode, - YGNodeConstRef owner, - size_t childIndex); - -// YGNode -YG_EXPORT YGNodeRef YGNodeNew(void); -YG_EXPORT YGNodeRef YGNodeNewWithConfig(YGConfigConstRef config); -YG_EXPORT YGNodeRef YGNodeClone(YGNodeConstRef node); -YG_EXPORT void YGNodeFree(YGNodeRef node); -YG_EXPORT void YGNodeFreeRecursiveWithCleanupFunc( - YGNodeRef node, - YGNodeCleanupFunc cleanup); -YG_EXPORT void YGNodeFreeRecursive(YGNodeRef node); -YG_EXPORT void YGNodeReset(YGNodeRef node); - -YG_EXPORT void YGNodeInsertChild(YGNodeRef node, YGNodeRef child, size_t index); - -YG_EXPORT void YGNodeSwapChild(YGNodeRef node, YGNodeRef child, size_t index); - -YG_EXPORT void YGNodeRemoveChild(YGNodeRef node, YGNodeRef child); -YG_EXPORT void YGNodeRemoveAllChildren(YGNodeRef node); -YG_EXPORT YGNodeRef YGNodeGetChild(YGNodeRef node, size_t index); -YG_EXPORT YGNodeRef YGNodeGetOwner(YGNodeRef node); -YG_EXPORT YGNodeRef YGNodeGetParent(YGNodeRef node); -YG_EXPORT size_t YGNodeGetChildCount(YGNodeConstRef node); -YG_EXPORT void -YGNodeSetChildren(YGNodeRef owner, const YGNodeRef* children, size_t count); - -YG_EXPORT void YGNodeSetIsReferenceBaseline( - YGNodeRef node, - bool isReferenceBaseline); - -YG_EXPORT bool YGNodeIsReferenceBaseline(YGNodeConstRef node); - -YG_EXPORT void YGNodeCalculateLayout( - YGNodeRef node, - float availableWidth, - float availableHeight, - YGDirection ownerDirection); - -// Mark a node as dirty. Only valid for nodes with a custom measure function -// set. -// -// Yoga knows when to mark all other nodes as dirty but because nodes with -// measure functions depend on information not known to Yoga they must perform -// this dirty marking manually. -YG_EXPORT void YGNodeMarkDirty(YGNodeRef node); - -YG_EXPORT void YGNodePrint(YGNodeConstRef node, YGPrintOptions options); - -YG_EXPORT bool YGFloatIsUndefined(float value); - -// TODO: This should not be part of the public API. Remove after removing -// ComponentKit usage of it. -YG_EXPORT 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); - -YG_EXPORT void YGNodeCopyStyle(YGNodeRef dstNode, YGNodeConstRef srcNode); - -YG_EXPORT void* YGNodeGetContext(YGNodeConstRef node); -YG_EXPORT void YGNodeSetContext(YGNodeRef node, void* context); - -YG_EXPORT YGConfigConstRef YGNodeGetConfig(YGNodeRef node); -YG_EXPORT void YGNodeSetConfig(YGNodeRef node, YGConfigRef config); - -YG_EXPORT void YGConfigSetPrintTreeFlag(YGConfigRef config, bool enabled); -YG_EXPORT bool YGNodeHasMeasureFunc(YGNodeConstRef node); -YG_EXPORT void YGNodeSetMeasureFunc(YGNodeRef node, YGMeasureFunc measureFunc); -YG_EXPORT bool YGNodeHasBaselineFunc(YGNodeConstRef node); -YG_EXPORT void YGNodeSetBaselineFunc( - YGNodeRef node, - YGBaselineFunc baselineFunc); -YG_EXPORT YGDirtiedFunc YGNodeGetDirtiedFunc(YGNodeConstRef node); -YG_EXPORT void YGNodeSetDirtiedFunc(YGNodeRef node, YGDirtiedFunc dirtiedFunc); -YG_EXPORT void YGNodeSetPrintFunc(YGNodeRef node, YGPrintFunc printFunc); -YG_EXPORT bool YGNodeGetHasNewLayout(YGNodeConstRef node); -YG_EXPORT void YGNodeSetHasNewLayout(YGNodeRef node, bool hasNewLayout); -YG_EXPORT YGNodeType YGNodeGetNodeType(YGNodeConstRef node); -YG_EXPORT void YGNodeSetNodeType(YGNodeRef node, YGNodeType nodeType); -YG_EXPORT bool YGNodeIsDirty(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetDirection(YGNodeRef node, YGDirection direction); -YG_EXPORT YGDirection YGNodeStyleGetDirection(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetFlexDirection( - YGNodeRef node, - YGFlexDirection flexDirection); -YG_EXPORT YGFlexDirection YGNodeStyleGetFlexDirection(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetJustifyContent( - YGNodeRef node, - YGJustify justifyContent); -YG_EXPORT YGJustify YGNodeStyleGetJustifyContent(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetAlignContent(YGNodeRef node, YGAlign alignContent); -YG_EXPORT YGAlign YGNodeStyleGetAlignContent(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetAlignItems(YGNodeRef node, YGAlign alignItems); -YG_EXPORT YGAlign YGNodeStyleGetAlignItems(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetAlignSelf(YGNodeRef node, YGAlign alignSelf); -YG_EXPORT YGAlign YGNodeStyleGetAlignSelf(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetPositionType( - YGNodeRef node, - YGPositionType positionType); -YG_EXPORT YGPositionType YGNodeStyleGetPositionType(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetFlexWrap(YGNodeRef node, YGWrap flexWrap); -YG_EXPORT YGWrap YGNodeStyleGetFlexWrap(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetOverflow(YGNodeRef node, YGOverflow overflow); -YG_EXPORT YGOverflow YGNodeStyleGetOverflow(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetDisplay(YGNodeRef node, YGDisplay display); -YG_EXPORT YGDisplay YGNodeStyleGetDisplay(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetFlex(YGNodeRef node, float flex); -YG_EXPORT float YGNodeStyleGetFlex(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetFlexGrow(YGNodeRef node, float flexGrow); -YG_EXPORT float YGNodeStyleGetFlexGrow(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetFlexShrink(YGNodeRef node, float flexShrink); -YG_EXPORT float YGNodeStyleGetFlexShrink(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetFlexBasis(YGNodeRef node, float flexBasis); -YG_EXPORT void YGNodeStyleSetFlexBasisPercent(YGNodeRef node, float flexBasis); -YG_EXPORT void YGNodeStyleSetFlexBasisAuto(YGNodeRef node); -YG_EXPORT YGValue YGNodeStyleGetFlexBasis(YGNodeConstRef node); - -YG_EXPORT void -YGNodeStyleSetPosition(YGNodeRef node, YGEdge edge, float position); -YG_EXPORT void -YGNodeStyleSetPositionPercent(YGNodeRef node, YGEdge edge, float position); -YG_EXPORT YGValue YGNodeStyleGetPosition(YGNodeConstRef node, YGEdge edge); - -YG_EXPORT void YGNodeStyleSetMargin(YGNodeRef node, YGEdge edge, float margin); -YG_EXPORT void -YGNodeStyleSetMarginPercent(YGNodeRef node, YGEdge edge, float margin); -YG_EXPORT void YGNodeStyleSetMarginAuto(YGNodeRef node, YGEdge edge); -YG_EXPORT YGValue YGNodeStyleGetMargin(YGNodeConstRef node, YGEdge edge); - -YG_EXPORT void -YGNodeStyleSetPadding(YGNodeRef node, YGEdge edge, float padding); -YG_EXPORT void -YGNodeStyleSetPaddingPercent(YGNodeRef node, YGEdge edge, float padding); -YG_EXPORT YGValue YGNodeStyleGetPadding(YGNodeConstRef node, YGEdge edge); - -YG_EXPORT void YGNodeStyleSetBorder(YGNodeRef node, YGEdge edge, float border); -YG_EXPORT float YGNodeStyleGetBorder(YGNodeConstRef node, YGEdge edge); - -YG_EXPORT void -YGNodeStyleSetGap(YGNodeRef node, YGGutter gutter, float gapLength); -YG_EXPORT float YGNodeStyleGetGap(YGNodeConstRef node, YGGutter gutter); - -YG_EXPORT void YGNodeStyleSetWidth(YGNodeRef node, float width); -YG_EXPORT void YGNodeStyleSetWidthPercent(YGNodeRef node, float width); -YG_EXPORT void YGNodeStyleSetWidthAuto(YGNodeRef node); -YG_EXPORT YGValue YGNodeStyleGetWidth(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetHeight(YGNodeRef node, float height); -YG_EXPORT void YGNodeStyleSetHeightPercent(YGNodeRef node, float height); -YG_EXPORT void YGNodeStyleSetHeightAuto(YGNodeRef node); -YG_EXPORT YGValue YGNodeStyleGetHeight(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetMinWidth(YGNodeRef node, float minWidth); -YG_EXPORT void YGNodeStyleSetMinWidthPercent(YGNodeRef node, float minWidth); -YG_EXPORT YGValue YGNodeStyleGetMinWidth(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetMinHeight(YGNodeRef node, float minHeight); -YG_EXPORT void YGNodeStyleSetMinHeightPercent(YGNodeRef node, float minHeight); -YG_EXPORT YGValue YGNodeStyleGetMinHeight(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetMaxWidth(YGNodeRef node, float maxWidth); -YG_EXPORT void YGNodeStyleSetMaxWidthPercent(YGNodeRef node, float maxWidth); -YG_EXPORT YGValue YGNodeStyleGetMaxWidth(YGNodeConstRef node); - -YG_EXPORT void YGNodeStyleSetMaxHeight(YGNodeRef node, float maxHeight); -YG_EXPORT void YGNodeStyleSetMaxHeightPercent(YGNodeRef node, float maxHeight); -YG_EXPORT YGValue YGNodeStyleGetMaxHeight(YGNodeConstRef node); - -// Yoga specific properties, not compatible with flexbox specification Aspect -// ratio control the size of the undefined dimension of a node. Aspect ratio is -// encoded as a floating point value width/height. e.g. A value of 2 leads to a -// node with a width twice the size of its height while a value of 0.5 gives the -// opposite effect. -// -// - On a node with a set width/height aspect ratio control the size of the -// unset dimension -// - On a node with a set flex basis aspect ratio controls the size of the node -// in the cross axis if unset -// - On a node with a measure function aspect ratio works as though the measure -// function measures the flex basis -// - On a node with flex grow/shrink aspect ratio controls the size of the node -// in the cross axis if unset -// - Aspect ratio takes min/max dimensions into account -YG_EXPORT void YGNodeStyleSetAspectRatio(YGNodeRef node, float aspectRatio); -YG_EXPORT float YGNodeStyleGetAspectRatio(YGNodeConstRef node); - -YG_EXPORT float YGNodeLayoutGetLeft(YGNodeConstRef node); -YG_EXPORT float YGNodeLayoutGetTop(YGNodeConstRef node); -YG_EXPORT float YGNodeLayoutGetRight(YGNodeConstRef node); -YG_EXPORT float YGNodeLayoutGetBottom(YGNodeConstRef node); -YG_EXPORT float YGNodeLayoutGetWidth(YGNodeConstRef node); -YG_EXPORT float YGNodeLayoutGetHeight(YGNodeConstRef node); -YG_EXPORT YGDirection YGNodeLayoutGetDirection(YGNodeConstRef node); -YG_EXPORT bool YGNodeLayoutGetHadOverflow(YGNodeConstRef node); - -// Get the computed values for these nodes after performing layout. If they were -// set using point values then the returned value will be the same as -// YGNodeStyleGetXXX. However if they were set using a percentage value then the -// returned value is the computed value used during layout. -YG_EXPORT float YGNodeLayoutGetMargin(YGNodeConstRef node, YGEdge edge); -YG_EXPORT float YGNodeLayoutGetBorder(YGNodeConstRef node, YGEdge edge); -YG_EXPORT float YGNodeLayoutGetPadding(YGNodeConstRef node, YGEdge edge); - -YG_EXPORT void YGConfigSetLogger(YGConfigRef config, YGLogger logger); -// Set this to number of pixels in 1 point to round calculation results If you -// want to avoid rounding - set PointScaleFactor to 0 -YG_EXPORT void YGConfigSetPointScaleFactor( - YGConfigRef config, - float pixelsInPoint); -YG_EXPORT float YGConfigGetPointScaleFactor(YGConfigConstRef config); - -// YGConfig -YG_EXPORT YGConfigRef YGConfigNew(void); -YG_EXPORT void YGConfigFree(YGConfigRef config); - -YG_EXPORT void YGConfigSetExperimentalFeatureEnabled( - YGConfigRef config, - YGExperimentalFeature feature, - bool enabled); -YG_EXPORT bool YGConfigIsExperimentalFeatureEnabled( - YGConfigConstRef config, - YGExperimentalFeature feature); - -// Using the web defaults is the preferred configuration for new projects. Usage -// of non web defaults should be considered as legacy. -YG_EXPORT void YGConfigSetUseWebDefaults(YGConfigRef config, bool enabled); -YG_EXPORT bool YGConfigGetUseWebDefaults(YGConfigConstRef config); - -YG_EXPORT void YGConfigSetCloneNodeFunc( - YGConfigRef config, - YGCloneNodeFunc callback); - -YG_EXPORT YGConfigConstRef YGConfigGetDefault(void); - -YG_EXPORT void YGConfigSetContext(YGConfigRef config, void* context); -YG_EXPORT void* YGConfigGetContext(YGConfigConstRef config); - -YG_EXPORT void YGConfigSetErrata(YGConfigRef config, YGErrata errata); -YG_EXPORT YGErrata YGConfigGetErrata(YGConfigConstRef config); - -YG_EXPORT float YGRoundValueToPixelGrid( - double value, - double pointScaleFactor, - bool forceCeil, - bool forceFloor); - -YG_EXTERN_C_END diff --git a/yoga/module.modulemap b/yoga/module.modulemap index 91c6db2934..5a8aad8ff2 100644 --- a/yoga/module.modulemap +++ b/yoga/module.modulemap @@ -7,8 +7,13 @@ module yoga [system] { module core { + header "YGConfig.h" header "YGEnums.h" header "YGMacros.h" + header "YGNode.h" + header "YGNodeLayout.h" + header "YGNodeStye.h" + header "YGPixelGrid.h" header "YGValue.h" header "Yoga.h" export *