Fabric: Proper way to represent (and parse) borders in ViewProps
Summary: @public Previously, ViewProps class coundn't represent whole spectre of possible values of border metrics (e.g. the border color was unified). Now it's complete and direction-specific. Reviewed By: sahrens Differential Revision: D9628361 fbshipit-source-id: 6d3b3d4d7e3008e2168cbca732ff99fe5ea595e8
This commit is contained in:
parent
6e7ffff4a5
commit
ca1e9032a4
|
@ -137,10 +137,10 @@ using namespace facebook::react;
|
|||
|
||||
// `border`
|
||||
if (
|
||||
oldViewProps.borderWidth != newViewProps.borderWidth ||
|
||||
oldViewProps.borderStyle != newViewProps.borderStyle ||
|
||||
oldViewProps.borderRadius != newViewProps.borderRadius ||
|
||||
oldViewProps.borderColor != newViewProps.borderColor
|
||||
oldViewProps.borderWidths != newViewProps.borderWidths ||
|
||||
oldViewProps.borderStyles != newViewProps.borderStyles ||
|
||||
oldViewProps.borderRadii != newViewProps.borderRadii ||
|
||||
oldViewProps.borderColors != newViewProps.borderColors
|
||||
) {
|
||||
[self invalidateBorder];
|
||||
}
|
||||
|
@ -174,10 +174,15 @@ using namespace facebook::react;
|
|||
{
|
||||
const auto &props = *std::dynamic_pointer_cast<const ViewProps>(_props);
|
||||
|
||||
bool useCoreAnimationBorderRendering =
|
||||
props.borderStyle == BorderStyle::Solid &&
|
||||
props.borderWidth.isUniform() &&
|
||||
props.borderRadius.isUniform();
|
||||
const auto borderMetrics =
|
||||
props.resolveBorderMetrics(_layoutMetrics.layoutDirection == LayoutDirection::RightToLeft);
|
||||
|
||||
const bool useCoreAnimationBorderRendering =
|
||||
borderMetrics.borderColors.isUniform() &&
|
||||
borderMetrics.borderWidths.isUniform() &&
|
||||
borderMetrics.borderStyles.isUniform() &&
|
||||
borderMetrics.borderRadii.isUniform() &&
|
||||
borderMetrics.borderStyles.left == BorderStyle::Solid;
|
||||
|
||||
CALayer *layer = self.layer;
|
||||
if (_isCoreAnimationBorderRenderingEnabled != useCoreAnimationBorderRendering) {
|
||||
|
@ -190,11 +195,10 @@ using namespace facebook::react;
|
|||
}
|
||||
|
||||
if (useCoreAnimationBorderRendering) {
|
||||
layer.borderWidth = (CGFloat)props.borderWidth.left;
|
||||
layer.borderColor = RCTCGColorRefFromSharedColor(props.borderColor);
|
||||
layer.cornerRadius = (CGFloat)props.borderRadius.topLeft;
|
||||
_contentView.layer.cornerRadius = (CGFloat)props.borderRadius.topLeft;
|
||||
_contentView.layer.masksToBounds = YES;
|
||||
layer.borderWidth = (CGFloat)borderMetrics.borderWidths.left;
|
||||
layer.borderColor = RCTCGColorRefFromSharedColor(borderMetrics.borderColors.left);
|
||||
layer.cornerRadius = (CGFloat)borderMetrics.borderRadii.topLeft;
|
||||
_contentView.layer.cornerRadius = (CGFloat)borderMetrics.borderRadii.topLeft;
|
||||
} else {
|
||||
// Not supported yet.
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "ViewProps.h"
|
||||
|
||||
#include <fabric/components/view/conversions.h>
|
||||
#include <fabric/components/view/propsConversions.h>
|
||||
#include <fabric/core/propsConversions.h>
|
||||
#include <fabric/debug/debugStringConvertibleUtils.h>
|
||||
#include <fabric/graphics/conversions.h>
|
||||
|
@ -24,10 +25,10 @@ ViewProps::ViewProps(const ViewProps &sourceProps, const RawProps &rawProps):
|
|||
opacity(convertRawProp(rawProps, "opacity", sourceProps.opacity, (Float)1.0)),
|
||||
foregroundColor(convertRawProp(rawProps, "foregroundColor", sourceProps.foregroundColor)),
|
||||
backgroundColor(convertRawProp(rawProps, "backgroundColor", sourceProps.backgroundColor)),
|
||||
borderWidth(convertRawProp(rawProps, "borderWidth", sourceProps.borderWidth)),
|
||||
borderRadius(convertRawProp(rawProps, "borderRadius", sourceProps.borderRadius)),
|
||||
borderColor(convertRawProp(rawProps, "borderColor", sourceProps.borderColor)),
|
||||
borderStyle(convertRawProp(rawProps, "borderStyle", sourceProps.borderStyle)),
|
||||
borderWidths(convertRawProp(rawProps, "border", "Width", sourceProps.borderWidths)),
|
||||
borderRadii(convertRawProp(rawProps, "border", "Radius", sourceProps.borderRadii)),
|
||||
borderColors(convertRawProp(rawProps, "border", "Color", sourceProps.borderColors)),
|
||||
borderStyles(convertRawProp(rawProps, "border", "Style", sourceProps.borderStyles)),
|
||||
shadowColor(convertRawProp(rawProps, "shadowColor", sourceProps.shadowColor)),
|
||||
shadowOffset(convertRawProp(rawProps, "shadowOffset", sourceProps.shadowOffset)),
|
||||
shadowOpacity(convertRawProp(rawProps, "shadowOpacity", sourceProps.shadowOpacity)),
|
||||
|
@ -40,6 +41,17 @@ ViewProps::ViewProps(const ViewProps &sourceProps, const RawProps &rawProps):
|
|||
hitSlop(convertRawProp(rawProps, "hitSlop", sourceProps.hitSlop)),
|
||||
onLayout(convertRawProp(rawProps, "onLayout", sourceProps.onLayout)) {};
|
||||
|
||||
#pragma mark - Convenience Methods
|
||||
|
||||
BorderMetrics ViewProps::resolveBorderMetrics(bool isRTL) const {
|
||||
return {
|
||||
.borderColors = borderColors.resolve(isRTL, {}),
|
||||
.borderWidths = borderWidths.resolve(isRTL, 0),
|
||||
.borderRadii = borderRadii.resolve(isRTL, 0),
|
||||
.borderStyles = borderStyles.resolve(isRTL, BorderStyle::Solid)
|
||||
};
|
||||
}
|
||||
|
||||
#pragma mark - DebugStringConvertible
|
||||
|
||||
SharedDebugStringConvertibleList ViewProps::getDebugProps() const {
|
||||
|
|
|
@ -39,10 +39,10 @@ public:
|
|||
const SharedColor backgroundColor {};
|
||||
|
||||
// Borders
|
||||
const EdgeInsets borderWidth {};
|
||||
const CornerInsets borderRadius {};
|
||||
const SharedColor borderColor {};
|
||||
const BorderStyle borderStyle {};
|
||||
const CascadedBorderWidths borderWidths {};
|
||||
const CascadedBorderRadii borderRadii {};
|
||||
const CascadedBorderColors borderColors {};
|
||||
const CascadedBorderStyles borderStyles {};
|
||||
|
||||
// Shadow
|
||||
const SharedColor shadowColor {};
|
||||
|
@ -61,6 +61,10 @@ public:
|
|||
const EdgeInsets hitSlop {};
|
||||
const bool onLayout {};
|
||||
|
||||
#pragma mark - Convenience Methods
|
||||
|
||||
BorderMetrics resolveBorderMetrics(bool isRTL) const;
|
||||
|
||||
#pragma mark - DebugStringConvertible
|
||||
|
||||
SharedDebugStringConvertibleList getDebugProps() const override;
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <fabric/graphics/Color.h>
|
||||
#include <fabric/graphics/Geometry.h>
|
||||
#include <folly/Optional.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
@ -157,5 +159,112 @@ enum class BorderStyle {
|
|||
Dashed
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CascadedRectangleEdges {
|
||||
using Counterpart = RectangleEdges<T>;
|
||||
using OptionalT = folly::Optional<T>;
|
||||
|
||||
OptionalT left {};
|
||||
OptionalT top {};
|
||||
OptionalT right {};
|
||||
OptionalT bottom {};
|
||||
OptionalT start {};
|
||||
OptionalT end {};
|
||||
OptionalT horizontal {};
|
||||
OptionalT vertical {};
|
||||
OptionalT all {};
|
||||
|
||||
Counterpart resolve(bool isRTL, T defaults) const {
|
||||
const auto leading = isRTL ? end : start;
|
||||
const auto trailing = isRTL ? start : end;
|
||||
const auto horizontalOrAllOrDefault = horizontal.value_or(all.value_or(defaults));
|
||||
const auto verticalOrAllOrDefault = vertical.value_or(all.value_or(defaults));
|
||||
|
||||
return Counterpart {
|
||||
.left = left.value_or(leading.value_or(horizontalOrAllOrDefault)),
|
||||
.right = right.value_or(trailing.value_or(horizontalOrAllOrDefault)),
|
||||
.top = top.value_or(verticalOrAllOrDefault),
|
||||
.bottom = bottom.value_or(verticalOrAllOrDefault)
|
||||
};
|
||||
}
|
||||
|
||||
bool operator==(const CascadedRectangleEdges<T> &rhs) const {
|
||||
return
|
||||
std::tie(this->left, this->top, this->right, this->bottom, this->start, this->end, this->horizontal, this->vertical, this->all) ==
|
||||
std::tie(rhs.left, rhs.top, rhs.right, rhs.bottom, rhs.start, rhs.end, rhs.horizontal, rhs.vertical, rhs.all);
|
||||
}
|
||||
|
||||
bool operator!=(const CascadedRectangleEdges<T> &rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CascadedRectangleCorners {
|
||||
using Counterpart = RectangleCorners<T>;
|
||||
using OptionalT = folly::Optional<T>;
|
||||
|
||||
OptionalT topLeft {};
|
||||
OptionalT topRight {};
|
||||
OptionalT bottomLeft {};
|
||||
OptionalT bottomRight {};
|
||||
OptionalT topStart {};
|
||||
OptionalT topEnd {};
|
||||
OptionalT bottomStart {};
|
||||
OptionalT bottomEnd {};
|
||||
OptionalT all {};
|
||||
|
||||
Counterpart resolve(bool isRTL, T defaults) const {
|
||||
const auto topLeading = isRTL ? topEnd : topStart;
|
||||
const auto topTrailing = isRTL ? topStart : topEnd;
|
||||
const auto bottomLeading = isRTL ? bottomEnd : bottomStart;
|
||||
const auto bottomTrailing = isRTL ? bottomStart : bottomEnd;
|
||||
|
||||
return Counterpart {
|
||||
.topLeft = topLeft.value_or(topLeading.value_or(all.value_or(defaults))),
|
||||
.topRight = topRight.value_or(topTrailing.value_or(all.value_or(defaults))),
|
||||
.bottomLeft = bottomLeft.value_or(topLeading.value_or(all.value_or(defaults))),
|
||||
.bottomRight = bottomRight.value_or(topTrailing.value_or(all.value_or(defaults)))
|
||||
};
|
||||
}
|
||||
|
||||
bool operator==(const CascadedRectangleCorners<T> &rhs) const {
|
||||
return
|
||||
std::tie(this->topLeft, this->topRight, this->bottomLeft, this->bottomRight, this->topStart, this->topEnd, this->bottomStart, this->bottomEnd, this->all) ==
|
||||
std::tie(rhs.topLeft, rhs.topRight, rhs.bottomLeft, rhs.bottomRight, rhs.topStart, rhs.topEnd, rhs.bottomStart, rhs.bottomEnd, rhs.all);
|
||||
}
|
||||
|
||||
bool operator!=(const CascadedRectangleCorners<T> &rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
using BorderWidths = RectangleEdges<Float>;
|
||||
using BorderStyles = RectangleEdges<BorderStyle>;
|
||||
using BorderColors = RectangleEdges<SharedColor>;
|
||||
using BorderRadii = RectangleCorners<Float>;
|
||||
|
||||
using CascadedBorderWidths = CascadedRectangleEdges<Float>;
|
||||
using CascadedBorderStyles = CascadedRectangleEdges<BorderStyle>;
|
||||
using CascadedBorderColors = CascadedRectangleEdges<SharedColor>;
|
||||
using CascadedBorderRadii = CascadedRectangleCorners<Float>;
|
||||
|
||||
struct BorderMetrics {
|
||||
BorderColors borderColors {};
|
||||
BorderWidths borderWidths {};
|
||||
BorderRadii borderRadii {};
|
||||
BorderStyles borderStyles {};
|
||||
|
||||
bool operator==(const BorderMetrics &rhs) const {
|
||||
return
|
||||
std::tie(this->borderColors, this->borderWidths, this->borderRadii, this->borderStyles) ==
|
||||
std::tie(rhs.borderColors, rhs.borderWidths, rhs.borderRadii, rhs.borderStyles);
|
||||
}
|
||||
|
||||
bool operator!=(const BorderMetrics &rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
static std::array<YGValue, 2> convertRawProp(
|
||||
static inline std::array<YGValue, 2> convertRawProp(
|
||||
const RawProps &rawProps,
|
||||
const std::string &widthName,
|
||||
const std::string &heightName,
|
||||
|
@ -26,7 +26,7 @@ static std::array<YGValue, 2> convertRawProp(
|
|||
return dimentions;
|
||||
}
|
||||
|
||||
static std::array<YGValue, YGEdgeCount> convertRawProp(
|
||||
static inline std::array<YGValue, YGEdgeCount> convertRawProp(
|
||||
const RawProps &rawProps,
|
||||
const std::string &prefix,
|
||||
const std::string &suffix,
|
||||
|
@ -46,7 +46,7 @@ static std::array<YGValue, YGEdgeCount> convertRawProp(
|
|||
return result;
|
||||
}
|
||||
|
||||
static std::array<YGValue, YGEdgeCount> convertRawProp(
|
||||
static inline std::array<YGValue, YGEdgeCount> convertRawProp(
|
||||
const RawProps &rawProps,
|
||||
const std::array<YGValue, YGEdgeCount> &sourceValue,
|
||||
const std::array<YGValue, YGEdgeCount> &defaultValue
|
||||
|
@ -61,7 +61,7 @@ static std::array<YGValue, YGEdgeCount> convertRawProp(
|
|||
return result;
|
||||
}
|
||||
|
||||
static YGStyle convertRawProp(const RawProps &rawProps, const YGStyle &sourceValue) {
|
||||
static inline YGStyle convertRawProp(const RawProps &rawProps, const YGStyle &sourceValue) {
|
||||
YGStyle yogaStyle;
|
||||
yogaStyle.direction = convertRawProp(rawProps, "direction", sourceValue.direction, yogaStyle.direction);
|
||||
yogaStyle.flexDirection = convertRawProp(rawProps, "flexDirection", sourceValue.flexDirection, yogaStyle.flexDirection);
|
||||
|
@ -88,5 +88,53 @@ static YGStyle convertRawProp(const RawProps &rawProps, const YGStyle &sourceVal
|
|||
return yogaStyle;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline CascadedRectangleCorners<T> convertRawProp(
|
||||
const RawProps &rawProps,
|
||||
const std::string &prefix,
|
||||
const std::string &suffix,
|
||||
const CascadedRectangleCorners<T> &sourceValue
|
||||
) {
|
||||
CascadedRectangleCorners<T> result;
|
||||
|
||||
result.topLeft = convertRawProp(rawProps, prefix + "TopLeft" + suffix, sourceValue.topLeft);
|
||||
result.topRight = convertRawProp(rawProps, prefix + "TopRight" + suffix, sourceValue.topRight);
|
||||
result.bottomLeft = convertRawProp(rawProps, prefix + "BottomLeft" + suffix, sourceValue.bottomLeft);
|
||||
result.bottomRight = convertRawProp(rawProps, prefix + "BottomRight" + suffix, sourceValue.bottomRight);
|
||||
|
||||
result.topStart = convertRawProp(rawProps, prefix + "TopStart" + suffix, sourceValue.topStart);
|
||||
result.topEnd = convertRawProp(rawProps, prefix + "TopEnd" + suffix, sourceValue.topEnd);
|
||||
result.bottomStart = convertRawProp(rawProps, prefix + "BottomStart" + suffix, sourceValue.bottomStart);
|
||||
result.bottomEnd = convertRawProp(rawProps, prefix + "BottomEnd" + suffix, sourceValue.bottomEnd);
|
||||
|
||||
result.all = convertRawProp(rawProps, prefix + suffix, sourceValue.all);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline CascadedRectangleEdges<T> convertRawProp(
|
||||
const RawProps &rawProps,
|
||||
const std::string &prefix,
|
||||
const std::string &suffix,
|
||||
const CascadedRectangleEdges<T> &sourceValue
|
||||
) {
|
||||
CascadedRectangleEdges<T> result;
|
||||
|
||||
result.left = convertRawProp(rawProps, prefix + "Left" + suffix, sourceValue.left);
|
||||
result.right = convertRawProp(rawProps, prefix + "Right" + suffix, sourceValue.right);
|
||||
result.top = convertRawProp(rawProps, prefix + "Top" + suffix, sourceValue.top);
|
||||
result.bottom = convertRawProp(rawProps, prefix + "Bottom" + suffix, sourceValue.bottom);
|
||||
|
||||
result.start = convertRawProp(rawProps, prefix + "Start" + suffix, sourceValue.start);
|
||||
result.end = convertRawProp(rawProps, prefix + "End" + suffix, sourceValue.end);
|
||||
result.horizontal = convertRawProp(rawProps, prefix + "Horizontal" + suffix, sourceValue.horizontal);
|
||||
result.vertical = convertRawProp(rawProps, prefix + "Vertical" + suffix, sourceValue.vertical);
|
||||
|
||||
result.all = convertRawProp(rawProps, prefix + suffix, sourceValue.all);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
|
Loading…
Reference in New Issue