Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 76 additions & 42 deletions snap_drawing/src/snap_drawing/cpp/Layers/FlexboxLayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
//

#include "snap_drawing/cpp/Layers/FlexboxLayer.hpp"
#include <yoga/YGNode.h>
#include <yoga/node/Node.h>
#include <yoga/style/StyleLength.h>
#include <yoga/style/StyleSizeLength.h>

namespace snap::drawing {

Expand Down Expand Up @@ -41,7 +43,7 @@ struct FlexboxNode : public Valdi::SimpleRefCountable {
}

void setLayoutDirty() const {
if (yogaNode->hasMeasureFunc()) {
if (facebook::yoga::resolveRef(yogaNode)->hasMeasureFunc()) {
YGNodeMarkDirty(yogaNode);
}
}
Expand All @@ -63,152 +65,184 @@ struct FlexboxNode : public Valdi::SimpleRefCountable {
}
};

static YGFloatOptional toOptional(const std::optional<Scalar>& value) {
if (value) {
return YGFloatOptional(value.value());
} else {
return YGFloatOptional();
static facebook::yoga::FloatOptional toFloatOptional(const std::optional<Scalar>& value) {
return value ? facebook::yoga::FloatOptional(value.value()) : facebook::yoga::FloatOptional();
}

static facebook::yoga::StyleLength toStyleLength(FlexValue value) {
switch (value.value.unit) {
case YGUnitAuto:
return facebook::yoga::StyleLength::ofAuto();
case YGUnitPercent:
return facebook::yoga::StyleLength::percent(value.value.value);
case YGUnitPoint:
return facebook::yoga::StyleLength::points(value.value.value);
case YGUnitUndefined:
case YGUnitMaxContent:
case YGUnitFitContent:
case YGUnitStretch:
return facebook::yoga::StyleLength::undefined();
}
}

FlexboxAttributes::FlexboxAttributes(YGStyle* style) : _style(style) {}
static facebook::yoga::StyleSizeLength toStyleSizeLength(FlexValue value) {
switch (value.value.unit) {
case YGUnitAuto:
return facebook::yoga::StyleSizeLength::ofAuto();
case YGUnitPercent:
return facebook::yoga::StyleSizeLength::percent(value.value.value);
case YGUnitPoint:
return facebook::yoga::StyleSizeLength::points(value.value.value);
case YGUnitMaxContent:
return facebook::yoga::StyleSizeLength::ofMaxContent();
case YGUnitFitContent:
return facebook::yoga::StyleSizeLength::ofFitContent();
case YGUnitStretch:
return facebook::yoga::StyleSizeLength::ofStretch();
case YGUnitUndefined:
return facebook::yoga::StyleSizeLength::undefined();
}
}

FlexboxAttributes::FlexboxAttributes(facebook::yoga::Style* style) : _style(style) {}

FlexboxAttributes& FlexboxAttributes::setDirection(YGDirection value) {
_style->direction() = value;
_style->setDirection(facebook::yoga::scopedEnum(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setFlexDirection(YGFlexDirection value) {
_style->flexDirection() = value;
_style->setFlexDirection(facebook::yoga::scopedEnum(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setJustifyContent(YGJustify value) {
_style->justifyContent() = value;
_style->setJustifyContent(facebook::yoga::scopedEnum(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setAlignItems(YGAlign value) {
_style->alignItems() = value;
_style->setAlignItems(facebook::yoga::scopedEnum(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setAlignContent(YGAlign value) {
_style->alignContent() = value;
_style->setAlignContent(facebook::yoga::scopedEnum(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setAlignSelf(YGAlign value) {
_style->alignSelf() = value;
_style->setAlignSelf(facebook::yoga::scopedEnum(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setPadding(YGEdge edge, FlexValue value) {
_style->padding()[edge] = value.value;
_style->setPadding(facebook::yoga::scopedEnum(edge), toStyleLength(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setMargin(YGEdge edge, FlexValue value) {
_style->margin()[edge] = value.value;
_style->setMargin(facebook::yoga::scopedEnum(edge), toStyleLength(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setBorder(YGEdge edge, FlexValue value) {
_style->border()[edge] = value.value;
_style->setBorder(facebook::yoga::scopedEnum(edge), toStyleLength(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setPosition(YGEdge edge, FlexValue value) {
_style->position()[edge] = value.value;
_style->setPosition(facebook::yoga::scopedEnum(edge), toStyleLength(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setPositionType(YGPositionType value) {
_style->positionType() = value;
_style->setPositionType(facebook::yoga::scopedEnum(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setFlexWrap(YGWrap value) {
_style->flexWrap() = value;
_style->setFlexWrap(facebook::yoga::scopedEnum(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setOverflow(YGOverflow value) {
_style->overflow() = value;
_style->setOverflow(facebook::yoga::scopedEnum(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setDisplay(YGDisplay value) {
_style->display() = value;
_style->setDisplay(facebook::yoga::scopedEnum(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setFlex(std::optional<Scalar> value) {
_style->flex() = toOptional(value);
_style->setFlex(toFloatOptional(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setFlexGrow(std::optional<Scalar> value) {
_style->flexGrow() = toOptional(value);
_style->setFlexGrow(toFloatOptional(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setFlexShrink(std::optional<Scalar> value) {
_style->flexShrink() = toOptional(value);
_style->setFlexShrink(toFloatOptional(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setFlexBasis(FlexValue value) {
_style->flexBasis() = value.value;
_style->setFlexBasis(toStyleSizeLength(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setWidth(FlexValue value) {
_style->dimensions()[YGDimensionWidth] = value.value;
_style->setDimension(facebook::yoga::Dimension::Width, toStyleSizeLength(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setHeight(FlexValue value) {
_style->dimensions()[YGDimensionHeight] = value.value;
_style->setDimension(facebook::yoga::Dimension::Height, toStyleSizeLength(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setMinWidth(FlexValue value) {
_style->minDimensions()[YGDimensionWidth] = value.value;
_style->setMinDimension(facebook::yoga::Dimension::Width, toStyleSizeLength(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setMinHeight(FlexValue value) {
_style->minDimensions()[YGDimensionHeight] = value.value;
_style->setMinDimension(facebook::yoga::Dimension::Height, toStyleSizeLength(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setMaxWidth(FlexValue value) {
_style->maxDimensions()[YGDimensionWidth] = value.value;
_style->setMaxDimension(facebook::yoga::Dimension::Width, toStyleSizeLength(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setMaxHeight(FlexValue value) {
_style->maxDimensions()[YGDimensionHeight] = value.value;
_style->setMaxDimension(facebook::yoga::Dimension::Height, toStyleSizeLength(value));
return *this;
}

FlexboxAttributes& FlexboxAttributes::setAspectRatio(std::optional<Scalar> value) {
_style->aspectRatio() = toOptional(value);
_style->setAspectRatio(toFloatOptional(value));
return *this;
}

void onYogaNodeDirty(YGNodeRef node) {
auto* layer = reinterpret_cast<snap::drawing::Layer*>(node->getContext());
void onYogaNodeDirty(YGNodeConstRef node) {
auto* layer = reinterpret_cast<snap::drawing::Layer*>(facebook::yoga::resolveRef(node)->getContext());
if (layer == nullptr) {
return;
}

layer->setNeedsLayout();
}

YGSize onYogaMeasure(YGNodeRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) {
auto* layer = reinterpret_cast<snap::drawing::Layer*>(node->getContext());
YGSize onYogaMeasure(
YGNodeConstRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) {
auto* layer = reinterpret_cast<snap::drawing::Layer*>(facebook::yoga::resolveRef(node)->getContext());
if (layer == nullptr) {
return {.width = 0, .height = 0};
}
Expand All @@ -224,11 +258,12 @@ static Ref<FlexboxNode> createAndAssociateFlexboxNode(Layer* layer, bool isOwner
auto flexboxNode = Valdi::makeShared<FlexboxNode>();
layer->setAttachedData(flexboxNode);

flexboxNode->yogaNode->setContext(static_cast<snap::drawing::Layer*>(layer));
flexboxNode->yogaNode->setDirtiedFunc(&onYogaNodeDirty);
auto* yogaNode = facebook::yoga::resolveRef(flexboxNode->yogaNode);
yogaNode->setContext(static_cast<snap::drawing::Layer*>(layer));
yogaNode->setDirtiedFunc(&onYogaNodeDirty);

if (!isOwner) {
flexboxNode->yogaNode->setMeasureFunc(&onYogaMeasure);
yogaNode->setMeasureFunc(&onYogaMeasure);
}

return flexboxNode;
Expand Down Expand Up @@ -302,11 +337,10 @@ FlexboxAttributes FlexboxLayer::updateLayoutAttributesForLayer(const Ref<Layer>&
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
FlexboxAttributes FlexboxLayer::updateLayoutAttributesForLayer(Layer* layer) {
auto flexboxNode = mustGetFlexboxNode(layer);
auto& style = flexboxNode->yogaNode->getStyle();

flexboxNode->setLayoutDirty();

return FlexboxAttributes(&style);
return FlexboxAttributes(&facebook::yoga::resolveRef(flexboxNode->yogaNode)->style());
}

void FlexboxLayer::requestLayout(ILayer* layer) {
Expand Down
20 changes: 12 additions & 8 deletions snap_drawing/src/snap_drawing/cpp/Layers/FlexboxLayer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,37 @@

#include "snap_drawing/cpp/Layers/Layer.hpp"

#include <yoga/YGStyle.h>
#include <yoga/Yoga.h>

struct YGNode;

namespace facebook::yoga {
class Style;
}

namespace snap::drawing {

struct FlexValue {
facebook::yoga::detail::CompactValue value;
YGValue value;

constexpr FlexValue(facebook::yoga::detail::CompactValue value) : value(value) {}
constexpr explicit FlexValue(YGValue value) : value(value) {}

inline static FlexValue point(Scalar value) {
return facebook::yoga::detail::CompactValue::of<YGUnitPoint>(value);
return FlexValue(YGValue{.value = value, .unit = YGUnitPoint});
}

inline static FlexValue percent(Scalar value) {
return facebook::yoga::detail::CompactValue::of<YGUnitPercent>(value);
return FlexValue(YGValue{.value = value, .unit = YGUnitPercent});
}

inline static FlexValue undefined() {
return facebook::yoga::detail::CompactValue::ofUndefined();
return FlexValue(YGValue{.value = YGUndefined, .unit = YGUnitUndefined});
}
};

class FlexboxAttributes {
public:
FlexboxAttributes(YGStyle* _style);
FlexboxAttributes(facebook::yoga::Style* style);

FlexboxAttributes& setDirection(YGDirection value);

Expand Down Expand Up @@ -72,7 +76,7 @@ class FlexboxAttributes {
FlexboxAttributes& setAspectRatio(std::optional<Scalar> value);

private:
YGStyle* _style;
facebook::yoga::Style* _style;
};

/**
Expand Down
31 changes: 26 additions & 5 deletions snap_drawing/test/utils/TestDataUtils.cpp
Original file line number Diff line number Diff line change
@@ -1,24 +1,45 @@
#include "TestDataUtils.hpp"
#include "valdi_core/cpp/Utils/DiskUtils.hpp"
#include <initializer_list>
#include <unistd.h>

using namespace Valdi;

namespace snap::drawing {

Path resolveTestPath(const std::string& path) {
namespace {

constexpr const char* kTestDataSubDir = "snap_drawing/testdata";

Path resolveRunfilesTestPath(std::initializer_list<const char*> subDirsToCheck) {
char cwdBuffer[PATH_MAX];
(void)::getcwd(cwdBuffer, PATH_MAX);

auto basePath = Path(cwdBuffer);
auto cwdPath = Path(cwdBuffer);
Path basePath;

for (const auto& subDir : subDirsToCheck) {
basePath = cwdPath;
basePath.append(subDir);
basePath.append(kTestDataSubDir);
basePath.normalize();

basePath.append("../+local_repos+valdi/snap_drawing/testdata");
basePath.append(path);
basePath.normalize();
if (DiskUtils::isDirectory(basePath)) {
return basePath;
}
}

return basePath;
}

} // namespace

Path resolveTestPath(const std::string& path) {
auto testPath = resolveRunfilesTestPath({".", "../+local_repos+valdi"});
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a side change: upstream broke snap drawing tests because they now require to run under bzlmod which is not setup in Valdi open source. This change fixes it by making the resolve runfiles test path resilient against either running in bzlmod or without.

testPath.append(path);
return testPath;
}

Valdi::Result<Valdi::BytesView> getTestData(const std::string& filename) {
auto path = resolveTestPath(filename);
return DiskUtils::load(path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,19 @@ interface LayoutChildrenAttributes {
*/
paddingLeft?: CSSValue;

/**
* Sets spacing between children on both axes.
*/
gap?: CSSValue;
/**
* Sets spacing between flex rows.
*/
rowGap?: CSSValue;
/**
* Sets spacing between flex columns.
*/
columnGap?: CSSValue;

/**
* Layout direction specifies the direction in which children and text in a hierarchy should be laid out.
* Layout direction also affects what edge start and end refer to.
Expand Down
Loading
Loading