123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710 |
- /*
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
- #pragma once
- #include <better/map.h>
- #include <folly/Conv.h>
- #include <folly/dynamic.h>
- #include <glog/logging.h>
- #include <react/components/view/primitives.h>
- #include <react/core/LayoutMetrics.h>
- #include <react/graphics/Geometry.h>
- #include <react/graphics/Transform.h>
- #include <stdlib.h>
- #include <yoga/YGEnums.h>
- #include <yoga/YGNode.h>
- #include <yoga/Yoga.h>
- #include <cmath>
- namespace facebook {
- namespace react {
- /*
- * Yoga's `float` <-> React Native's `Float` (can be `double` or `float`)
- *
- * Regular Yoga `float` values represent some onscreen-position-related values.
- * They can be real numbers or special value `YGUndefined` (which actually is
- * `NaN`). Conceptually, layout computation process inside Yoga should never
- * produce `NaN` values from non-`NaN` values. At the same time, ` YGUndefined`
- * values have special "no limit" meaning in Yoga, therefore ` YGUndefined`
- * usually corresponds to `Infinity` value.
- */
- inline Float floatFromYogaFloat(float value) {
- static_assert(
- YGUndefined != YGUndefined,
- "The code of this function assumes that YGUndefined is NaN.");
- if (std::isnan(value) /* means: `value == YGUndefined` */) {
- return std::numeric_limits<Float>::infinity();
- }
- return (Float)value;
- }
- inline float yogaFloatFromFloat(Float value) {
- if (std::isinf(value)) {
- return YGUndefined;
- }
- return (float)value;
- }
- /*
- * `YGFloatOptional` <-> React Native's `Float`
- *
- * `YGFloatOptional` represents optional dimensionless float values in Yoga
- * Style object (e.g. `flex`). The most suitable analogy to empty
- * `YGFloatOptional` is `NaN` value.
- * `YGFloatOptional` values are usually parsed from some outside data source
- * which usually has some special corresponding representation for an empty
- * value.
- */
- inline Float floatFromYogaOptionalFloat(YGFloatOptional value) {
- if (value.isUndefined()) {
- return std::numeric_limits<Float>::quiet_NaN();
- }
- return floatFromYogaFloat(value.unwrap());
- }
- inline YGFloatOptional yogaOptionalFloatFromFloat(Float value) {
- if (std::isnan(value)) {
- return YGFloatOptional();
- }
- return YGFloatOptional((float)value);
- }
- /*
- * `YGValue` <-> `React Native's `Float`
- *
- * `YGValue` represents optional dimensionful (a real number and some unit, e.g.
- * pixels).
- */
- inline YGValue yogaStyleValueFromFloat(
- const Float &value,
- YGUnit unit = YGUnitPoint) {
- if (std::isnan(value)) {
- return YGValueUndefined;
- }
- return {(float)value, unit};
- }
- inline folly::Optional<Float> optionalFloatFromYogaValue(
- const YGValue value,
- folly::Optional<Float> base = {}) {
- switch (value.unit) {
- case YGUnitUndefined:
- return {};
- case YGUnitPoint:
- return floatFromYogaFloat(value.value);
- case YGUnitPercent:
- return base.has_value()
- ? folly::Optional<Float>(
- base.value() * floatFromYogaFloat(value.value))
- : folly::Optional<Float>();
- case YGUnitAuto:
- return {};
- }
- }
- inline LayoutMetrics layoutMetricsFromYogaNode(YGNode &yogaNode) {
- auto layoutMetrics = LayoutMetrics{};
- layoutMetrics.frame =
- Rect{Point{floatFromYogaFloat(YGNodeLayoutGetLeft(&yogaNode)),
- floatFromYogaFloat(YGNodeLayoutGetTop(&yogaNode))},
- Size{floatFromYogaFloat(YGNodeLayoutGetWidth(&yogaNode)),
- floatFromYogaFloat(YGNodeLayoutGetHeight(&yogaNode))}};
- layoutMetrics.borderWidth = EdgeInsets{
- floatFromYogaFloat(YGNodeLayoutGetBorder(&yogaNode, YGEdgeLeft)),
- floatFromYogaFloat(YGNodeLayoutGetBorder(&yogaNode, YGEdgeTop)),
- floatFromYogaFloat(YGNodeLayoutGetBorder(&yogaNode, YGEdgeRight)),
- floatFromYogaFloat(YGNodeLayoutGetBorder(&yogaNode, YGEdgeBottom))};
- layoutMetrics.contentInsets = EdgeInsets{
- layoutMetrics.borderWidth.left +
- floatFromYogaFloat(YGNodeLayoutGetPadding(&yogaNode, YGEdgeLeft)),
- layoutMetrics.borderWidth.top +
- floatFromYogaFloat(YGNodeLayoutGetPadding(&yogaNode, YGEdgeTop)),
- layoutMetrics.borderWidth.right +
- floatFromYogaFloat(YGNodeLayoutGetPadding(&yogaNode, YGEdgeRight)),
- layoutMetrics.borderWidth.bottom +
- floatFromYogaFloat(YGNodeLayoutGetPadding(&yogaNode, YGEdgeBottom))};
- layoutMetrics.displayType = yogaNode.getStyle().display() == YGDisplayNone
- ? DisplayType::None
- : DisplayType::Flex;
- layoutMetrics.layoutDirection =
- YGNodeLayoutGetDirection(&yogaNode) == YGDirectionRTL
- ? LayoutDirection::RightToLeft
- : LayoutDirection::LeftToRight;
- return layoutMetrics;
- }
- inline YGDirection yogaDirectionFromLayoutDirection(LayoutDirection direction) {
- switch (direction) {
- case LayoutDirection::Undefined:
- return YGDirectionInherit;
- case LayoutDirection::LeftToRight:
- return YGDirectionLTR;
- case LayoutDirection::RightToLeft:
- return YGDirectionRTL;
- }
- }
- inline void fromRawValue(const RawValue &value, YGDirection &result) {
- assert(value.hasType<std::string>());
- auto stringValue = (std::string)value;
- if (stringValue == "inherit") {
- result = YGDirectionInherit;
- return;
- }
- if (stringValue == "ltr") {
- result = YGDirectionLTR;
- return;
- }
- if (stringValue == "rtl") {
- result = YGDirectionRTL;
- return;
- }
- LOG(FATAL) << "Could not parse YGDirection:" << stringValue;
- assert(false);
- }
- inline void fromRawValue(const RawValue &value, YGFlexDirection &result) {
- assert(value.hasType<std::string>());
- auto stringValue = (std::string)value;
- if (stringValue == "row") {
- result = YGFlexDirectionRow;
- return;
- }
- if (stringValue == "column") {
- result = YGFlexDirectionColumn;
- return;
- }
- if (stringValue == "column-reverse") {
- result = YGFlexDirectionColumnReverse;
- return;
- }
- if (stringValue == "row-reverse") {
- result = YGFlexDirectionRowReverse;
- return;
- }
- LOG(FATAL) << "Could not parse YGFlexDirection:" << stringValue;
- assert(false);
- }
- inline void fromRawValue(const RawValue &value, YGJustify &result) {
- assert(value.hasType<std::string>());
- auto stringValue = (std::string)value;
- if (stringValue == "flex-start") {
- result = YGJustifyFlexStart;
- return;
- }
- if (stringValue == "center") {
- result = YGJustifyCenter;
- return;
- }
- if (stringValue == "flex-end") {
- result = YGJustifyFlexEnd;
- return;
- }
- if (stringValue == "space-between") {
- result = YGJustifySpaceBetween;
- return;
- }
- if (stringValue == "space-around") {
- result = YGJustifySpaceAround;
- return;
- }
- if (stringValue == "space-evenly") {
- result = YGJustifySpaceEvenly;
- return;
- }
- LOG(FATAL) << "Could not parse YGJustify:" << stringValue;
- assert(false);
- }
- inline void fromRawValue(const RawValue &value, YGAlign &result) {
- assert(value.hasType<std::string>());
- auto stringValue = (std::string)value;
- if (stringValue == "auto") {
- result = YGAlignAuto;
- return;
- }
- if (stringValue == "flex-start") {
- result = YGAlignFlexStart;
- return;
- }
- if (stringValue == "center") {
- result = YGAlignCenter;
- return;
- }
- if (stringValue == "flex-end") {
- result = YGAlignFlexEnd;
- return;
- }
- if (stringValue == "stretch") {
- result = YGAlignStretch;
- return;
- }
- if (stringValue == "baseline") {
- result = YGAlignBaseline;
- return;
- }
- if (stringValue == "between") {
- result = YGAlignSpaceBetween;
- return;
- }
- if (stringValue == "space-around") {
- result = YGAlignSpaceAround;
- return;
- }
- LOG(FATAL) << "Could not parse YGAlign:" << stringValue;
- assert(false);
- }
- inline void fromRawValue(const RawValue &value, YGPositionType &result) {
- assert(value.hasType<std::string>());
- auto stringValue = (std::string)value;
- if (stringValue == "relative") {
- result = YGPositionTypeRelative;
- return;
- }
- if (stringValue == "absolute") {
- result = YGPositionTypeAbsolute;
- return;
- }
- LOG(FATAL) << "Could not parse YGPositionType:" << stringValue;
- assert(false);
- }
- inline void fromRawValue(const RawValue &value, YGWrap &result) {
- assert(value.hasType<std::string>());
- auto stringValue = (std::string)value;
- if (stringValue == "nowrap") {
- result = YGWrapNoWrap;
- return;
- }
- if (stringValue == "wrap") {
- result = YGWrapWrap;
- return;
- }
- if (stringValue == "wrap-reverse") {
- result = YGWrapWrapReverse;
- return;
- }
- LOG(FATAL) << "Could not parse YGWrap:" << stringValue;
- assert(false);
- }
- inline void fromRawValue(const RawValue &value, YGOverflow &result) {
- assert(value.hasType<std::string>());
- auto stringValue = (std::string)value;
- if (stringValue == "visible") {
- result = YGOverflowVisible;
- return;
- }
- if (stringValue == "hidden") {
- result = YGOverflowHidden;
- return;
- }
- if (stringValue == "scroll") {
- result = YGOverflowScroll;
- return;
- }
- LOG(FATAL) << "Could not parse YGOverflow:" << stringValue;
- assert(false);
- }
- inline void fromRawValue(const RawValue &value, YGDisplay &result) {
- assert(value.hasType<std::string>());
- auto stringValue = (std::string)value;
- if (stringValue == "flex") {
- result = YGDisplayFlex;
- return;
- }
- if (stringValue == "none") {
- result = YGDisplayNone;
- return;
- }
- LOG(FATAL) << "Could not parse YGDisplay:" << stringValue;
- assert(false);
- }
- inline void fromRawValue(const RawValue &value, YGStyle::ValueRepr &result) {
- if (value.hasType<Float>()) {
- result = yogaStyleValueFromFloat((Float)value);
- return;
- } else if (value.hasType<std::string>()) {
- const auto stringValue = (std::string)value;
- if (stringValue == "auto") {
- result = YGValueUndefined;
- return;
- } else {
- if (stringValue.back() == '%') {
- result = YGValue{
- folly::to<float>(stringValue.substr(0, stringValue.length() - 1)),
- YGUnitPercent};
- return;
- } else {
- result = YGValue{folly::to<float>(stringValue), YGUnitPoint};
- return;
- }
- }
- }
- result = YGValueUndefined;
- }
- inline void fromRawValue(const RawValue &value, YGFloatOptional &result) {
- if (value.hasType<float>()) {
- result = YGFloatOptional((float)value);
- return;
- } else if (value.hasType<std::string>()) {
- const auto stringValue = (std::string)value;
- if (stringValue == "auto") {
- result = YGFloatOptional();
- return;
- }
- }
- LOG(FATAL) << "Could not parse YGFloatOptional";
- assert(false);
- }
- inline Float toRadians(const RawValue &value) {
- if (value.hasType<Float>()) {
- return (Float)value;
- }
- assert(value.hasType<std::string>());
- auto stringValue = (std::string)value;
- char *suffixStart;
- double num = strtod(
- stringValue.c_str(), &suffixStart); // can't use std::stod, probably
- // because of old Android NDKs
- if (0 == strncmp(suffixStart, "deg", 3)) {
- return num * M_PI / 180;
- }
- return num; // assume suffix is "rad"
- }
- inline void fromRawValue(const RawValue &value, Transform &result) {
- assert(value.hasType<std::vector<RawValue>>());
- auto transformMatrix = Transform{};
- auto configurations = static_cast<std::vector<RawValue>>(value);
- for (const auto &configuration : configurations) {
- if (!configuration.hasType<better::map<std::string, RawValue>>()) {
- // TODO: The following checks have to be removed after codegen is shipped.
- // See T45151459.
- continue;
- }
- auto configurationPair =
- static_cast<better::map<std::string, RawValue>>(configuration);
- auto pair = configurationPair.begin();
- auto operation = pair->first;
- auto ¶meters = pair->second;
- if (operation == "matrix") {
- assert(parameters.hasType<std::vector<Float>>());
- auto numbers = (std::vector<Float>)parameters;
- assert(numbers.size() == transformMatrix.matrix.size());
- auto i = 0;
- for (auto number : numbers) {
- transformMatrix.matrix[i++] = number;
- }
- } else if (operation == "perspective") {
- transformMatrix =
- transformMatrix * Transform::Perspective((Float)parameters);
- } else if (operation == "rotateX") {
- transformMatrix =
- transformMatrix * Transform::Rotate(toRadians(parameters), 0, 0);
- } else if (operation == "rotateY") {
- transformMatrix =
- transformMatrix * Transform::Rotate(0, toRadians(parameters), 0);
- } else if (operation == "rotateZ" || operation == "rotate") {
- transformMatrix =
- transformMatrix * Transform::Rotate(0, 0, toRadians(parameters));
- } else if (operation == "scale") {
- auto number = (Float)parameters;
- transformMatrix =
- transformMatrix * Transform::Scale(number, number, number);
- } else if (operation == "scaleX") {
- transformMatrix =
- transformMatrix * Transform::Scale((Float)parameters, 1, 1);
- } else if (operation == "scaleY") {
- transformMatrix =
- transformMatrix * Transform::Scale(1, (Float)parameters, 1);
- } else if (operation == "scaleZ") {
- transformMatrix =
- transformMatrix * Transform::Scale(1, 1, (Float)parameters);
- } else if (operation == "translate") {
- auto numbers = (std::vector<Float>)parameters;
- transformMatrix = transformMatrix *
- Transform::Translate(numbers.at(0), numbers.at(1), 0);
- } else if (operation == "translateX") {
- transformMatrix =
- transformMatrix * Transform::Translate((Float)parameters, 0, 0);
- } else if (operation == "translateY") {
- transformMatrix =
- transformMatrix * Transform::Translate(0, (Float)parameters, 0);
- } else if (operation == "skewX") {
- transformMatrix =
- transformMatrix * Transform::Skew(toRadians(parameters), 0);
- } else if (operation == "skewY") {
- transformMatrix =
- transformMatrix * Transform::Skew(0, toRadians(parameters));
- }
- }
- result = transformMatrix;
- }
- inline void fromRawValue(const RawValue &value, PointerEventsMode &result) {
- assert(value.hasType<std::string>());
- auto stringValue = (std::string)value;
- if (stringValue == "auto") {
- result = PointerEventsMode::Auto;
- return;
- }
- if (stringValue == "none") {
- result = PointerEventsMode::None;
- return;
- }
- if (stringValue == "box-none") {
- result = PointerEventsMode::BoxNone;
- return;
- }
- if (stringValue == "box-only") {
- result = PointerEventsMode::BoxOnly;
- return;
- }
- LOG(FATAL) << "Could not parse PointerEventsMode:" << stringValue;
- assert(false);
- }
- inline void fromRawValue(const RawValue &value, BackfaceVisibility &result) {
- assert(value.hasType<std::string>());
- auto stringValue = (std::string)value;
- if (stringValue == "auto") {
- result = BackfaceVisibility::Auto;
- return;
- }
- if (stringValue == "visible") {
- result = BackfaceVisibility::Visible;
- return;
- }
- if (stringValue == "hidden") {
- result = BackfaceVisibility::Hidden;
- return;
- }
- LOG(FATAL) << "Could not parse BackfaceVisibility:" << stringValue;
- assert(false);
- }
- inline void fromRawValue(const RawValue &value, BorderStyle &result) {
- assert(value.hasType<std::string>());
- auto stringValue = (std::string)value;
- if (stringValue == "solid") {
- result = BorderStyle::Solid;
- return;
- }
- if (stringValue == "dotted") {
- result = BorderStyle::Dotted;
- return;
- }
- if (stringValue == "dashed") {
- result = BorderStyle::Dashed;
- return;
- }
- LOG(FATAL) << "Could not parse BorderStyle:" << stringValue;
- assert(false);
- }
- inline std::string toString(
- const std::array<float, yoga::enums::count<YGDimension>()> &dimensions) {
- return "{" + folly::to<std::string>(dimensions[0]) + ", " +
- folly::to<std::string>(dimensions[1]) + "}";
- }
- inline std::string toString(const std::array<float, 4> &position) {
- return "{" + folly::to<std::string>(position[0]) + ", " +
- folly::to<std::string>(position[1]) + "}";
- }
- inline std::string toString(
- const std::array<float, yoga::enums::count<YGEdge>()> &edges) {
- return "{" + folly::to<std::string>(edges[0]) + ", " +
- folly::to<std::string>(edges[1]) + ", " +
- folly::to<std::string>(edges[2]) + ", " +
- folly::to<std::string>(edges[3]) + "}";
- }
- inline std::string toString(const YGDirection &value) {
- switch (value) {
- case YGDirectionInherit:
- return "inherit";
- case YGDirectionLTR:
- return "ltr";
- case YGDirectionRTL:
- return "rtl";
- }
- }
- inline std::string toString(const YGFlexDirection &value) {
- switch (value) {
- case YGFlexDirectionColumn:
- return "column";
- case YGFlexDirectionColumnReverse:
- return "column-reverse";
- case YGFlexDirectionRow:
- return "row";
- case YGFlexDirectionRowReverse:
- return "row-reverse";
- }
- }
- inline std::string toString(const YGJustify &value) {
- switch (value) {
- case YGJustifyFlexStart:
- return "flex-start";
- case YGJustifyCenter:
- return "center";
- case YGJustifyFlexEnd:
- return "flex-end";
- case YGJustifySpaceBetween:
- return "space-between";
- case YGJustifySpaceAround:
- return "space-around";
- case YGJustifySpaceEvenly:
- return "space-evenly";
- }
- }
- inline std::string toString(const YGAlign &value) {
- switch (value) {
- case YGAlignAuto:
- return "auto";
- case YGAlignFlexStart:
- return "flex-start";
- case YGAlignCenter:
- return "center";
- case YGAlignFlexEnd:
- return "flex-end";
- case YGAlignStretch:
- return "stretch";
- case YGAlignBaseline:
- return "baseline";
- case YGAlignSpaceBetween:
- return "space-between";
- case YGAlignSpaceAround:
- return "space-around";
- }
- }
- inline std::string toString(const YGPositionType &value) {
- switch (value) {
- case YGPositionTypeRelative:
- return "relative";
- case YGPositionTypeAbsolute:
- return "absolute";
- }
- }
- inline std::string toString(const YGWrap &value) {
- switch (value) {
- case YGWrapNoWrap:
- return "no-wrap";
- case YGWrapWrap:
- return "wrap";
- case YGWrapWrapReverse:
- return "wrap-reverse";
- }
- }
- inline std::string toString(const YGOverflow &value) {
- switch (value) {
- case YGOverflowVisible:
- return "visible";
- case YGOverflowScroll:
- return "scroll";
- case YGOverflowHidden:
- return "hidden";
- }
- }
- inline std::string toString(const YGDisplay &value) {
- switch (value) {
- case YGDisplayFlex:
- return "flex";
- case YGDisplayNone:
- return "none";
- }
- }
- inline std::string toString(const YGValue &value) {
- switch (value.unit) {
- case YGUnitUndefined:
- return "undefined";
- case YGUnitPoint:
- return folly::to<std::string>(value.value);
- case YGUnitPercent:
- return folly::to<std::string>(value.value) + "%";
- case YGUnitAuto:
- return "auto";
- }
- }
- inline std::string toString(const YGFloatOptional &value) {
- if (value.isUndefined()) {
- return "undefined";
- }
- return folly::to<std::string>(floatFromYogaFloat(value.unwrap()));
- }
- inline std::string toString(const YGStyle::Dimensions &value) {
- return "{" + toString(value[0]) + ", " + toString(value[1]) + "}";
- }
- inline std::string toString(const YGStyle::Edges &value) {
- static std::array<std::string, yoga::enums::count<YGEdge>()> names = {
- {"left",
- "top",
- "right",
- "bottom",
- "start",
- "end",
- "horizontal",
- "vertical",
- "all"}};
- auto result = std::string{};
- auto separator = std::string{", "};
- for (auto i = 0; i < yoga::enums::count<YGEdge>(); i++) {
- YGValue v = value[i];
- if (v.unit == YGUnitUndefined) {
- continue;
- }
- result += names[i] + ": " + toString(v) + separator;
- }
- if (!result.empty()) {
- result.erase(result.length() - separator.length());
- }
- return "{" + result + "}";
- }
- } // namespace react
- } // namespace facebook
|