mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
9864586b21
Summary: A follow up to D38708718 (https://github.com/facebook/react-native/commit/403fea25f65a38f4b4d8e0edcf89741b29e62059) review, this factors feature flags for Fabric core code into a separate file, `CoreFeatures`. Keeping them together is arguably better for maintenance and makes code easier to reason about. Changelog: [Internal] Reviewed By: sammy-SC Differential Revision: D40007784 fbshipit-source-id: 1885d5d6200575c6015f063d8b05813b18b47ffb
474 lines
21 KiB
C++
474 lines
21 KiB
C++
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#include "ViewProps.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <react/renderer/components/view/conversions.h>
|
|
#include <react/renderer/components/view/propsConversions.h>
|
|
#include <react/renderer/core/CoreFeatures.h>
|
|
#include <react/renderer/core/propsConversions.h>
|
|
#include <react/renderer/debug/debugStringConvertibleUtils.h>
|
|
#include <react/renderer/graphics/conversions.h>
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
ViewProps::ViewProps(
|
|
const PropsParserContext &context,
|
|
ViewProps const &sourceProps,
|
|
RawProps const &rawProps,
|
|
bool shouldSetRawProps)
|
|
: YogaStylableProps(context, sourceProps, rawProps, shouldSetRawProps),
|
|
AccessibilityProps(context, sourceProps, rawProps),
|
|
opacity(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.opacity
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"opacity",
|
|
sourceProps.opacity,
|
|
(Float)1.0)),
|
|
foregroundColor(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.foregroundColor
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"foregroundColor",
|
|
sourceProps.foregroundColor,
|
|
{})),
|
|
backgroundColor(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.backgroundColor
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"backgroundColor",
|
|
sourceProps.backgroundColor,
|
|
{})),
|
|
borderRadii(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.borderRadii
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"border",
|
|
"Radius",
|
|
sourceProps.borderRadii,
|
|
{})),
|
|
borderColors(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.borderColors
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"border",
|
|
"Color",
|
|
sourceProps.borderColors,
|
|
{})),
|
|
borderCurves(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.borderCurves
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"border",
|
|
"Curve",
|
|
sourceProps.borderCurves,
|
|
{})),
|
|
borderStyles(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.borderStyles
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"border",
|
|
"Style",
|
|
sourceProps.borderStyles,
|
|
{})),
|
|
shadowColor(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.shadowColor
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"shadowColor",
|
|
sourceProps.shadowColor,
|
|
{})),
|
|
shadowOffset(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.shadowOffset
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"shadowOffset",
|
|
sourceProps.shadowOffset,
|
|
{})),
|
|
shadowOpacity(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.shadowOpacity
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"shadowOpacity",
|
|
sourceProps.shadowOpacity,
|
|
{})),
|
|
shadowRadius(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.shadowRadius
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"shadowRadius",
|
|
sourceProps.shadowRadius,
|
|
{})),
|
|
transform(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.transform
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"transform",
|
|
sourceProps.transform,
|
|
{})),
|
|
backfaceVisibility(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.backfaceVisibility
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"backfaceVisibility",
|
|
sourceProps.backfaceVisibility,
|
|
{})),
|
|
shouldRasterize(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.shouldRasterize
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"shouldRasterize",
|
|
sourceProps.shouldRasterize,
|
|
{})),
|
|
zIndex(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.zIndex
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"zIndex",
|
|
sourceProps.zIndex,
|
|
{})),
|
|
pointerEvents(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.pointerEvents
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"pointerEvents",
|
|
sourceProps.pointerEvents,
|
|
{})),
|
|
hitSlop(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.hitSlop
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"hitSlop",
|
|
sourceProps.hitSlop,
|
|
{})),
|
|
onLayout(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.onLayout
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"onLayout",
|
|
sourceProps.onLayout,
|
|
{})),
|
|
events(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.events
|
|
: convertRawProp(context, rawProps, sourceProps.events, {})),
|
|
collapsable(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.collapsable
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"collapsable",
|
|
sourceProps.collapsable,
|
|
true)),
|
|
removeClippedSubviews(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.removeClippedSubviews
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"removeClippedSubviews",
|
|
sourceProps.removeClippedSubviews,
|
|
false))
|
|
#ifdef ANDROID
|
|
,
|
|
elevation(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.elevation
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"elevation",
|
|
sourceProps.elevation,
|
|
{})),
|
|
nativeBackground(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.nativeBackground
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"nativeBackgroundAndroid",
|
|
sourceProps.nativeBackground,
|
|
{})),
|
|
nativeForeground(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.nativeForeground
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"nativeForegroundAndroid",
|
|
sourceProps.nativeForeground,
|
|
{})),
|
|
focusable(
|
|
CoreFeatures::enablePropIteratorSetter ? sourceProps.focusable
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"focusable",
|
|
sourceProps.focusable,
|
|
{})),
|
|
hasTVPreferredFocus(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.hasTVPreferredFocus
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"hasTVPreferredFocus",
|
|
sourceProps.hasTVPreferredFocus,
|
|
{})),
|
|
needsOffscreenAlphaCompositing(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.needsOffscreenAlphaCompositing
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"needsOffscreenAlphaCompositing",
|
|
sourceProps.needsOffscreenAlphaCompositing,
|
|
{})),
|
|
renderToHardwareTextureAndroid(
|
|
CoreFeatures::enablePropIteratorSetter
|
|
? sourceProps.renderToHardwareTextureAndroid
|
|
: convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"renderToHardwareTextureAndroid",
|
|
sourceProps.renderToHardwareTextureAndroid,
|
|
{}))
|
|
|
|
#endif
|
|
{};
|
|
|
|
#define VIEW_EVENT_CASE(eventType, eventString) \
|
|
case CONSTEXPR_RAW_PROPS_KEY_HASH(eventString): { \
|
|
ViewEvents defaultViewEvents{}; \
|
|
bool res = defaultViewEvents[eventType]; \
|
|
if (value.hasValue()) { \
|
|
fromRawValue(context, value, res); \
|
|
} \
|
|
events[eventType] = res; \
|
|
return; \
|
|
}
|
|
|
|
void ViewProps::setProp(
|
|
const PropsParserContext &context,
|
|
RawPropsPropNameHash hash,
|
|
const char *propName,
|
|
RawValue const &value) {
|
|
// All Props structs setProp methods must always, unconditionally,
|
|
// call all super::setProp methods, since multiple structs may
|
|
// reuse the same values.
|
|
YogaStylableProps::setProp(context, hash, propName, value);
|
|
AccessibilityProps::setProp(context, hash, propName, value);
|
|
|
|
switch (hash) {
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(opacity, (Float)1.0);
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(foregroundColor, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(backgroundColor, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(shadowColor, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(shadowOffset, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(shadowOpacity, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(shadowRadius, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(transform, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(backfaceVisibility, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(shouldRasterize, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(zIndex, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(pointerEvents, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(hitSlop, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(onLayout, {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(collapsable, true);
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(removeClippedSubviews, false);
|
|
// events field
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::PointerEnter, "onPointerEnter");
|
|
VIEW_EVENT_CASE(
|
|
ViewEvents::Offset::PointerEnterCapture, "onPointerEnterCapture");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::PointerMove, "onPointerMove");
|
|
VIEW_EVENT_CASE(
|
|
ViewEvents::Offset::PointerMoveCapture, "onPointerMoveCapture");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::PointerLeave, "onPointerLeave");
|
|
VIEW_EVENT_CASE(
|
|
ViewEvents::Offset::PointerLeaveCapture, "onPointerLeaveCapture");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::PointerOver, "onPointerOver");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::PointerOut, "onPointerOut");
|
|
VIEW_EVENT_CASE(
|
|
ViewEvents::Offset::MoveShouldSetResponder, "onMoveShouldSetResponder");
|
|
VIEW_EVENT_CASE(
|
|
ViewEvents::Offset::MoveShouldSetResponderCapture,
|
|
"onMoveShouldSetResponderCapture");
|
|
VIEW_EVENT_CASE(
|
|
ViewEvents::Offset::StartShouldSetResponder,
|
|
"onStartShouldSetResponder");
|
|
VIEW_EVENT_CASE(
|
|
ViewEvents::Offset::StartShouldSetResponderCapture,
|
|
"onStartShouldSetResponderCapture");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::ResponderGrant, "onResponderGrant");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::ResponderReject, "onResponderReject");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::ResponderStart, "onResponderStart");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::ResponderEnd, "onResponderEnd");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::ResponderRelease, "onResponderRelease");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::ResponderMove, "ResponderMove");
|
|
VIEW_EVENT_CASE(
|
|
ViewEvents::Offset::ResponderTerminate, "onResponderTerminate");
|
|
VIEW_EVENT_CASE(
|
|
ViewEvents::Offset::ResponderTerminationRequest,
|
|
"onResponderTerminationRequest");
|
|
VIEW_EVENT_CASE(
|
|
ViewEvents::Offset::ShouldBlockNativeResponder,
|
|
"onShouldBlockNativeResponder");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::TouchStart, "onTouchStart");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::TouchMove, "onTouchMove");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::TouchEnd, "onTouchEnd");
|
|
VIEW_EVENT_CASE(ViewEvents::Offset::TouchCancel, "onTouchCancel");
|
|
#ifdef ANDROID
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(elevation, {});
|
|
RAW_SET_PROP_SWITCH_CASE(nativeBackground, "nativeBackgroundAndroid", {});
|
|
RAW_SET_PROP_SWITCH_CASE(nativeForeground, "nativeForegroundAndroid", {});
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(focusable, false);
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(hasTVPreferredFocus, false);
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(needsOffscreenAlphaCompositing, false);
|
|
RAW_SET_PROP_SWITCH_CASE_BASIC(renderToHardwareTextureAndroid, false);
|
|
#endif
|
|
// BorderRadii
|
|
SET_CASCADED_RECTANGLE_CORNERS(borderRadii, "border", "Radius", value);
|
|
SET_CASCADED_RECTANGLE_EDGES(borderColors, "border", "Color", value);
|
|
SET_CASCADED_RECTANGLE_EDGES(borderStyles, "border", "Style", value);
|
|
}
|
|
}
|
|
|
|
#pragma mark - Convenience Methods
|
|
|
|
static BorderRadii ensureNoOverlap(BorderRadii const &radii, Size const &size) {
|
|
// "Corner curves must not overlap: When the sum of any two adjacent border
|
|
// radii exceeds the size of the border box, UAs must proportionally reduce
|
|
// the used values of all border radii until none of them overlap."
|
|
// Source: https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
|
|
|
|
auto insets = EdgeInsets{
|
|
/* .left = */ radii.topLeft + radii.bottomLeft,
|
|
/* .top = */ radii.topLeft + radii.topRight,
|
|
/* .right = */ radii.topRight + radii.bottomRight,
|
|
/* .bottom = */ radii.bottomLeft + radii.bottomRight,
|
|
};
|
|
|
|
auto insetsScale = EdgeInsets{
|
|
/* .left = */
|
|
insets.left > 0 ? std::min((Float)1.0, size.height / insets.left) : 0,
|
|
/* .top = */
|
|
insets.top > 0 ? std::min((Float)1.0, size.width / insets.top) : 0,
|
|
/* .right = */
|
|
insets.right > 0 ? std::min((Float)1.0, size.height / insets.right) : 0,
|
|
/* .bottom = */
|
|
insets.bottom > 0 ? std::min((Float)1.0, size.width / insets.bottom) : 0,
|
|
};
|
|
|
|
return BorderRadii{
|
|
/* topLeft = */
|
|
radii.topLeft * std::min(insetsScale.top, insetsScale.left),
|
|
/* topRight = */
|
|
radii.topRight * std::min(insetsScale.top, insetsScale.right),
|
|
/* bottomLeft = */
|
|
radii.bottomLeft * std::min(insetsScale.bottom, insetsScale.left),
|
|
/* bottomRight = */
|
|
radii.bottomRight * std::min(insetsScale.bottom, insetsScale.right),
|
|
};
|
|
}
|
|
|
|
BorderMetrics ViewProps::resolveBorderMetrics(
|
|
LayoutMetrics const &layoutMetrics) const {
|
|
auto isRTL =
|
|
bool{layoutMetrics.layoutDirection == LayoutDirection::RightToLeft};
|
|
|
|
auto borderWidths = CascadedBorderWidths{
|
|
/* .left = */ optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeLeft]),
|
|
/* .top = */ optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeTop]),
|
|
/* .right = */
|
|
optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeRight]),
|
|
/* .bottom = */
|
|
optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeBottom]),
|
|
/* .start = */
|
|
optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeStart]),
|
|
/* .end = */ optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeEnd]),
|
|
/* .horizontal = */
|
|
optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeHorizontal]),
|
|
/* .vertical = */
|
|
optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeVertical]),
|
|
/* .all = */ optionalFloatFromYogaValue(yogaStyle.border()[YGEdgeAll]),
|
|
};
|
|
|
|
return {
|
|
/* .borderColors = */ borderColors.resolve(isRTL, {}),
|
|
/* .borderWidths = */ borderWidths.resolve(isRTL, 0),
|
|
/* .borderRadii = */
|
|
ensureNoOverlap(borderRadii.resolve(isRTL, 0), layoutMetrics.frame.size),
|
|
/* .borderCurves = */ borderCurves.resolve(isRTL, BorderCurve::Circular),
|
|
/* .borderStyles = */ borderStyles.resolve(isRTL, BorderStyle::Solid),
|
|
};
|
|
}
|
|
|
|
bool ViewProps::getClipsContentToBounds() const {
|
|
return yogaStyle.overflow() != YGOverflowVisible;
|
|
}
|
|
|
|
#ifdef ANDROID
|
|
bool ViewProps::getProbablyMoreHorizontalThanVertical_DEPRECATED() const {
|
|
return yogaStyle.flexDirection() == YGFlexDirectionRow;
|
|
}
|
|
#endif
|
|
|
|
#pragma mark - DebugStringConvertible
|
|
|
|
#if RN_DEBUG_STRING_CONVERTIBLE
|
|
SharedDebugStringConvertibleList ViewProps::getDebugProps() const {
|
|
const auto &defaultViewProps = ViewProps();
|
|
|
|
return AccessibilityProps::getDebugProps() +
|
|
YogaStylableProps::getDebugProps() +
|
|
SharedDebugStringConvertibleList{
|
|
debugStringConvertibleItem(
|
|
"opacity", opacity, defaultViewProps.opacity),
|
|
debugStringConvertibleItem(
|
|
"foregroundColor",
|
|
foregroundColor,
|
|
defaultViewProps.foregroundColor),
|
|
debugStringConvertibleItem(
|
|
"backgroundColor",
|
|
backgroundColor,
|
|
defaultViewProps.backgroundColor),
|
|
debugStringConvertibleItem(
|
|
"zIndex", zIndex, defaultViewProps.zIndex.value_or(0)),
|
|
};
|
|
}
|
|
#endif
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|