From 110b191b14e3cb692bb6a33f0f129b4f0215f9a6 Mon Sep 17 00:00:00 2001 From: Ruslan Shestopalyuk Date: Mon, 3 Oct 2022 04:11:02 -0700 Subject: [PATCH] Refactor ViewPropsMapBuffer -> general MapBuffer props mechanism Summary: Previously, ViewPropsMapBuffer conversions were hardcoded deep in Android infrastructrue. I've generalized this into a different mechanism to allow any Props struct to support MapBuffer props. There are still some things that need to be cleaned up and this should be treated as experimental. One thing we likely want to do is remove the hardcoded IDs (fine for codegen'd code; less so for handwritten) and use compile-time-hashed IDs instead with human-readable string names. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D38708719 fbshipit-source-id: 64603dee7f21828be31346c555d99862dab304ea --- .../views/view/ReactMapBufferPropSetter.kt | 10 +- .../react/fabric/FabricMountingManager.cpp | 12 +- .../jni/react/fabric/viewPropConversions.h | 342 +----------------- .../components/view/AccessibilityProps.h | 5 + .../view/AccessibilityPropsMapBuffer.cpp | 168 +++++++++ .../view/AccessibilityPropsMapBuffer.h | 33 ++ .../renderer/components/view/ViewProps.h | 7 +- .../components/view/ViewPropsMapBuffer.cpp | 202 +++++++++++ .../components/view/ViewPropsMapBuffer.h | 56 +++ .../components/view/YogaStylableProps.h | 7 +- .../view/YogaStylablePropsMapBuffer.cpp | 87 +++++ .../view/YogaStylablePropsMapBuffer.h | 24 ++ .../components/view/viewPropConversions.h | 198 ++++++++++ .../react/renderer/core/CMakeLists.txt | 1 + ReactCommon/react/renderer/core/Props.cpp | 1 + ReactCommon/react/renderer/core/Props.h | 8 + .../react/renderer/core/PropsMapBuffer.cpp | 37 ++ .../react/renderer/core/PropsMapBuffer.h | 23 ++ 18 files changed, 870 insertions(+), 351 deletions(-) create mode 100644 ReactCommon/react/renderer/components/view/AccessibilityPropsMapBuffer.cpp create mode 100644 ReactCommon/react/renderer/components/view/AccessibilityPropsMapBuffer.h create mode 100644 ReactCommon/react/renderer/components/view/ViewPropsMapBuffer.cpp create mode 100644 ReactCommon/react/renderer/components/view/ViewPropsMapBuffer.h create mode 100644 ReactCommon/react/renderer/components/view/YogaStylablePropsMapBuffer.cpp create mode 100644 ReactCommon/react/renderer/components/view/YogaStylablePropsMapBuffer.h create mode 100644 ReactCommon/react/renderer/components/view/viewPropConversions.h create mode 100644 ReactCommon/react/renderer/core/PropsMapBuffer.cpp create mode 100644 ReactCommon/react/renderer/core/PropsMapBuffer.h diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactMapBufferPropSetter.kt b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactMapBufferPropSetter.kt index 97c9fb513b0..7218daf70cf 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactMapBufferPropSetter.kt +++ b/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactMapBufferPropSetter.kt @@ -62,6 +62,8 @@ object ReactMapBufferPropSetter { private const val VP_POINTER_OUT_CAPTURE = 42 private const val VP_POINTER_OVER = 43 private const val VP_POINTER_OVER_CAPTURE = 44 + private const val VP_BORDER_CURVES = 45 // iOS only + private const val VP_FG_COLOR = 46 // iOS only? // Yoga values private const val YG_BORDER_WIDTH = 100 @@ -141,6 +143,9 @@ object ReactMapBufferPropSetter { // TODO: color for some reason can be object in Java but not in C++ viewManager.backgroundColor(view, entry.intValue) } + VP_FG_COLOR -> { + // Prop not used on Android? + } VP_BORDER_COLOR -> { viewManager.borderColor(view, entry.mapBufferValue) } @@ -148,7 +153,10 @@ object ReactMapBufferPropSetter { viewManager.borderRadius(view, entry.mapBufferValue) } VP_BORDER_STYLE -> { - viewManager.borderStyle(view, entry.intValue) + val styleBuffer = entry.mapBufferValue + if (styleBuffer.contains(CORNER_ALL)) { + viewManager.borderStyle(view, (styleBuffer.getDouble(CORNER_ALL)).toInt()) + } } VP_ELEVATION -> { viewManager.setElevation(view, entry.doubleValue.toFloat()) diff --git a/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp b/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp index 4d11993a38e..a26aeeb4895 100644 --- a/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp +++ b/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp @@ -9,7 +9,6 @@ #include "CppViewMutationsWrapper.h" #include "EventEmitterWrapper.h" #include "StateWrapperImpl.h" -#include "viewPropConversions.h" #include #include @@ -264,12 +263,11 @@ local_ref FabricMountingManager::getProps( react_native_assert( newShadowView.props->rawProps.empty() && "Raw props must be empty when views are using mapbuffer"); - auto oldProps = oldShadowView.props != nullptr - ? static_cast(*oldShadowView.props) - : ViewProps{}; - auto newProps = static_cast(*newShadowView.props); - return JReadableMapBuffer::createWithContents( - viewPropsDiff(oldProps, newProps)); + + // MapBufferBuilder must be constructed and live in this scope, + MapBufferBuilder builder; + newShadowView.props->propsDiffMapBuffer(&*oldShadowView.props, builder); + return JReadableMapBuffer::createWithContents(builder.build()); } else { return ReadableNativeMap::newObjectCxxArgs(newShadowView.props->rawProps); } diff --git a/ReactAndroid/src/main/jni/react/fabric/viewPropConversions.h b/ReactAndroid/src/main/jni/react/fabric/viewPropConversions.h index 1271fe3e903..fe44e662340 100644 --- a/ReactAndroid/src/main/jni/react/fabric/viewPropConversions.h +++ b/ReactAndroid/src/main/jni/react/fabric/viewPropConversions.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include #include @@ -19,58 +20,6 @@ namespace facebook { namespace react { namespace { -// ViewProps values -constexpr MapBuffer::Key VP_ACCESSIBILITY_ACTIONS = 0; -constexpr MapBuffer::Key VP_ACCESSIBILITY_HINT = 1; -constexpr MapBuffer::Key VP_ACCESSIBILITY_LABEL = 2; -constexpr MapBuffer::Key VP_ACCESSIBILITY_LABELLED_BY = 3; -constexpr MapBuffer::Key VP_ACCESSIBILITY_LIVE_REGION = 4; -constexpr MapBuffer::Key VP_ACCESSIBILITY_ROLE = 5; -constexpr MapBuffer::Key VP_ACCESSIBILITY_STATE = 6; -constexpr MapBuffer::Key VP_ACCESSIBILITY_VALUE = 7; -constexpr MapBuffer::Key VP_ACCESSIBLE = 8; -constexpr MapBuffer::Key VP_BACKFACE_VISIBILITY = 9; -constexpr MapBuffer::Key VP_BG_COLOR = 10; -constexpr MapBuffer::Key VP_BORDER_COLOR = 11; -constexpr MapBuffer::Key VP_BORDER_RADII = 12; -constexpr MapBuffer::Key VP_BORDER_STYLE = 13; -constexpr MapBuffer::Key VP_COLLAPSABLE = 14; -constexpr MapBuffer::Key VP_ELEVATION = 15; -constexpr MapBuffer::Key VP_FOCUSABLE = 16; -constexpr MapBuffer::Key VP_HAS_TV_FOCUS = 17; -constexpr MapBuffer::Key VP_HIT_SLOP = 18; -constexpr MapBuffer::Key VP_IMPORTANT_FOR_ACCESSIBILITY = 19; -constexpr MapBuffer::Key VP_NATIVE_BACKGROUND = 20; -constexpr MapBuffer::Key VP_NATIVE_FOREGROUND = 21; -constexpr MapBuffer::Key VP_NATIVE_ID = 22; -constexpr MapBuffer::Key VP_OFFSCREEN_ALPHA_COMPOSITING = 23; -constexpr MapBuffer::Key VP_OPACITY = 24; -constexpr MapBuffer::Key VP_POINTER_EVENTS = 25; -constexpr MapBuffer::Key VP_POINTER_ENTER = 26; -constexpr MapBuffer::Key VP_POINTER_LEAVE = 27; -constexpr MapBuffer::Key VP_POINTER_MOVE = 28; -constexpr MapBuffer::Key VP_REMOVE_CLIPPED_SUBVIEW = 29; -constexpr MapBuffer::Key VP_RENDER_TO_HARDWARE_TEXTURE = 30; -constexpr MapBuffer::Key VP_SHADOW_COLOR = 31; -constexpr MapBuffer::Key VP_TEST_ID = 32; -constexpr MapBuffer::Key VP_TRANSFORM = 33; -constexpr MapBuffer::Key VP_ZINDEX = 34; -constexpr MapBuffer::Key VP_POINTER_ENTER_CAPTURE = 38; -constexpr MapBuffer::Key VP_POINTER_LEAVE_CAPTURE = 39; -constexpr MapBuffer::Key VP_POINTER_MOVE_CAPTURE = 40; -constexpr MapBuffer::Key VP_POINTER_OVER = 41; -constexpr MapBuffer::Key VP_POINTER_OVER_CAPTURE = 42; -constexpr MapBuffer::Key VP_POINTER_OUT = 43; -constexpr MapBuffer::Key VP_POINTER_OUT_CAPTURE = 44; - -// Yoga values -constexpr MapBuffer::Key YG_BORDER_WIDTH = 100; -constexpr MapBuffer::Key YG_OVERFLOW = 101; - -// AccessibilityAction values -constexpr MapBuffer::Key ACCESSIBILITY_ACTION_NAME = 0; -constexpr MapBuffer::Key ACCESSIBILITY_ACTION_LABEL = 1; - static MapBuffer convertAccessibilityActions( std::vector const &actions) { MapBufferBuilder builder(actions.size()); @@ -262,294 +211,5 @@ MapBuffer convertTransform(Transform const &transform) { } } // namespace -/** - * Diffs two sets of ViewProps into MapBuffer. - * TODO: Currently unsupported: nextFocusForward/Left/Up/Right/Down - */ -static inline MapBuffer viewPropsDiff( - ViewProps const &oldProps, - ViewProps const &newProps) { - MapBufferBuilder builder; - if (oldProps.accessibilityActions != newProps.accessibilityActions) { - builder.putMapBuffer( - VP_ACCESSIBILITY_ACTIONS, - convertAccessibilityActions(newProps.accessibilityActions)); - } - - if (oldProps.accessibilityHint != newProps.accessibilityHint) { - builder.putString(VP_ACCESSIBILITY_HINT, newProps.accessibilityHint); - } - - if (oldProps.accessibilityLabel != newProps.accessibilityLabel) { - builder.putString(VP_ACCESSIBILITY_LABEL, newProps.accessibilityLabel); - } - - if (oldProps.accessibilityLabelledBy != newProps.accessibilityLabelledBy) { - builder.putMapBuffer( - VP_ACCESSIBILITY_LABELLED_BY, - convertAccessibilityLabelledBy(newProps.accessibilityLabelledBy)); - } - - if (oldProps.accessibilityLiveRegion != newProps.accessibilityLiveRegion) { - int value; - switch (newProps.accessibilityLiveRegion) { - case AccessibilityLiveRegion::None: - value = 0; - break; - case AccessibilityLiveRegion::Polite: - value = 1; - break; - case AccessibilityLiveRegion::Assertive: - value = 2; - break; - } - builder.putInt(VP_ACCESSIBILITY_LIVE_REGION, value); - } - - if (oldProps.accessibilityRole != newProps.accessibilityRole) { - builder.putString(VP_ACCESSIBILITY_ROLE, newProps.accessibilityRole); - } - - if (oldProps.accessibilityState != newProps.accessibilityState) { - builder.putMapBuffer( - VP_ACCESSIBILITY_STATE, - convertAccessibilityState(newProps.accessibilityState)); - } - - if (oldProps.accessibilityValue != newProps.accessibilityValue) { - builder.putString( - VP_ACCESSIBILITY_VALUE, newProps.accessibilityValue.text.value_or("")); - } - - if (oldProps.accessible != newProps.accessible) { - builder.putBool(VP_ACCESSIBLE, newProps.accessible); - } - - if (oldProps.backfaceVisibility != newProps.backfaceVisibility) { - int value; - switch (newProps.backfaceVisibility) { - case BackfaceVisibility::Auto: - value = 0; - break; - case BackfaceVisibility::Visible: - value = 1; - break; - case BackfaceVisibility::Hidden: - value = 2; - break; - } - builder.putInt(VP_BACKFACE_VISIBILITY, value); - } - - if (oldProps.backgroundColor != newProps.backgroundColor) { - builder.putInt(VP_BG_COLOR, toAndroidRepr(newProps.backgroundColor)); - } - - if (oldProps.borderColors != newProps.borderColors) { - builder.putMapBuffer( - VP_BORDER_COLOR, convertBorderColors(newProps.borderColors)); - } - - if (oldProps.borderRadii != newProps.borderRadii) { - builder.putMapBuffer( - VP_BORDER_RADII, convertBorderRadii(newProps.borderRadii)); - } - - if (oldProps.borderStyles != newProps.borderStyles) { - int value = -1; - if (newProps.borderStyles.all.has_value()) { - switch (newProps.borderStyles.all.value()) { - case BorderStyle::Solid: - value = 0; - break; - case BorderStyle::Dotted: - value = 1; - break; - case BorderStyle::Dashed: - value = 2; - break; - } - } - builder.putInt(VP_BORDER_STYLE, value); - } - - if (oldProps.elevation != newProps.elevation) { - builder.putDouble(VP_ELEVATION, newProps.elevation); - } - -#ifdef ANDROID - if (oldProps.focusable != newProps.focusable) { - builder.putBool(VP_FOCUSABLE, newProps.focusable); - } - - if (oldProps.hasTVPreferredFocus != newProps.hasTVPreferredFocus) { - builder.putBool(VP_HAS_TV_FOCUS, newProps.hasTVPreferredFocus); - } -#endif - - if (oldProps.hitSlop != newProps.hitSlop) { - builder.putMapBuffer(VP_HIT_SLOP, convertEdgeInsets(newProps.hitSlop)); - } - - if (oldProps.importantForAccessibility != - newProps.importantForAccessibility) { - int value; - switch (newProps.importantForAccessibility) { - case ImportantForAccessibility::Auto: - value = 0; - break; - case ImportantForAccessibility::Yes: - value = 1; - break; - case ImportantForAccessibility::No: - value = 2; - break; - case ImportantForAccessibility::NoHideDescendants: - value = 3; - break; - } - builder.putInt(VP_IMPORTANT_FOR_ACCESSIBILITY, value); - } - -#ifdef ANDROID - if (oldProps.nativeBackground != newProps.nativeBackground) { - builder.putMapBuffer( - VP_NATIVE_BACKGROUND, - convertNativeBackground(newProps.nativeBackground)); - } - - if (oldProps.nativeForeground != newProps.nativeForeground) { - builder.putMapBuffer( - VP_NATIVE_FOREGROUND, - convertNativeBackground(newProps.nativeForeground)); - } -#endif - - if (oldProps.nativeId != newProps.nativeId) { - builder.putString(VP_NATIVE_ID, newProps.nativeId); - } - -#ifdef ANDROID - if (oldProps.needsOffscreenAlphaCompositing != - newProps.needsOffscreenAlphaCompositing) { - builder.putBool( - VP_OFFSCREEN_ALPHA_COMPOSITING, - newProps.needsOffscreenAlphaCompositing); - } -#endif - - if (oldProps.opacity != newProps.opacity) { - builder.putDouble(VP_OPACITY, newProps.opacity); - } - - if (oldProps.pointerEvents != newProps.pointerEvents) { - int value; - switch (newProps.pointerEvents) { - case PointerEventsMode::Auto: - value = 0; - break; - case PointerEventsMode::None: - value = 1; - break; - case PointerEventsMode::BoxNone: - value = 2; - break; - case PointerEventsMode::BoxOnly: - value = 3; - break; - } - - builder.putInt(VP_POINTER_EVENTS, value); - } - - if (oldProps.events != newProps.events) { - builder.putBool( - VP_POINTER_ENTER, newProps.events[ViewEvents::Offset::PointerEnter]); - builder.putBool( - VP_POINTER_LEAVE, newProps.events[ViewEvents::Offset::PointerLeave]); - builder.putBool( - VP_POINTER_MOVE, newProps.events[ViewEvents::Offset::PointerMove]); - - builder.putBool( - VP_POINTER_ENTER_CAPTURE, - newProps.events[ViewEvents::Offset::PointerEnterCapture]); - builder.putBool( - VP_POINTER_LEAVE_CAPTURE, - newProps.events[ViewEvents::Offset::PointerLeaveCapture]); - builder.putBool( - VP_POINTER_MOVE_CAPTURE, - newProps.events[ViewEvents::Offset::PointerMoveCapture]); - builder.putBool( - VP_POINTER_OVER, newProps.events[ViewEvents::Offset::PointerOver]); - builder.putBool( - VP_POINTER_OVER_CAPTURE, - newProps.events[ViewEvents::Offset::PointerOverCapture]); - - builder.putBool( - VP_POINTER_OUT, newProps.events[ViewEvents::Offset::PointerOut]); - builder.putBool( - VP_POINTER_OUT_CAPTURE, - newProps.events[ViewEvents::Offset::PointerOutCapture]); - } - - if (oldProps.removeClippedSubviews != newProps.removeClippedSubviews) { - builder.putBool(VP_REMOVE_CLIPPED_SUBVIEW, newProps.removeClippedSubviews); - } - -#ifdef ANDROID - if (oldProps.renderToHardwareTextureAndroid != - newProps.renderToHardwareTextureAndroid) { - builder.putBool( - VP_RENDER_TO_HARDWARE_TEXTURE, newProps.renderToHardwareTextureAndroid); - } -#endif - - if (oldProps.shadowColor != newProps.shadowColor) { - builder.putInt(VP_SHADOW_COLOR, toAndroidRepr(newProps.shadowColor)); - } - - if (oldProps.testId != newProps.testId) { - builder.putString(VP_TEST_ID, newProps.testId); - } - - // TODO: seems like transform covers rotation/translate/scale/skew? - - if (oldProps.transform != newProps.transform) { - builder.putMapBuffer(VP_TRANSFORM, convertTransform(newProps.transform)); - } - - if (oldProps.zIndex != newProps.zIndex) { - builder.putInt(VP_ZINDEX, newProps.zIndex.value_or(0)); - } - - if (oldProps.yogaStyle != newProps.yogaStyle) { - auto const &oldStyle = oldProps.yogaStyle; - auto const &newStyle = newProps.yogaStyle; - - if (!(oldStyle.border() == newStyle.border())) { - builder.putMapBuffer( - YG_BORDER_WIDTH, convertBorderWidths(newStyle.border())); - } - - if (oldStyle.overflow() != newStyle.overflow()) { - int value; - switch (newStyle.overflow()) { - case YGOverflowVisible: - value = 0; - break; - case YGOverflowHidden: - value = 1; - break; - case YGOverflowScroll: - value = 2; - break; - } - builder.putInt(YG_OVERFLOW, value); - } - } - - return builder.build(); -} - } // namespace react } // namespace facebook diff --git a/ReactCommon/react/renderer/components/view/AccessibilityProps.h b/ReactCommon/react/renderer/components/view/AccessibilityProps.h index e9e6aa7b3f0..a2ee2f2d08c 100644 --- a/ReactCommon/react/renderer/components/view/AccessibilityProps.h +++ b/ReactCommon/react/renderer/components/view/AccessibilityProps.h @@ -32,6 +32,11 @@ class AccessibilityProps { static bool enablePropIteratorSetter; +#ifdef ANDROID + void propsDiffMapBuffer(Props const *oldProps, MapBufferBuilder &builder) + const; +#endif + #pragma mark - Props bool accessible{false}; diff --git a/ReactCommon/react/renderer/components/view/AccessibilityPropsMapBuffer.cpp b/ReactCommon/react/renderer/components/view/AccessibilityPropsMapBuffer.cpp new file mode 100644 index 00000000000..31f34b3e75b --- /dev/null +++ b/ReactCommon/react/renderer/components/view/AccessibilityPropsMapBuffer.cpp @@ -0,0 +1,168 @@ +/* + * 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 "AccessibilityPropsMapBuffer.h" +#include "AccessibilityProps.h" + +#include + +namespace facebook { +namespace react { + +#ifdef ANDROID + +static MapBuffer convertAccessibilityActions( + std::vector const &actions) { + MapBufferBuilder builder(actions.size()); + for (auto i = 0; i < actions.size(); i++) { + auto const &action = actions[i]; + MapBufferBuilder actionsBuilder(2); + actionsBuilder.putString(ACCESSIBILITY_ACTION_NAME, action.name); + if (action.label.has_value()) { + actionsBuilder.putString( + ACCESSIBILITY_ACTION_LABEL, action.label.value()); + } + builder.putMapBuffer(i, actionsBuilder.build()); + } + return builder.build(); +} + +static MapBuffer convertAccessibilityLabelledBy( + AccessibilityLabelledBy const &labelledBy) { + MapBufferBuilder builder(labelledBy.value.size()); + for (auto i = 0; i < labelledBy.value.size(); i++) { + builder.putString(i, labelledBy.value[i]); + } + return builder.build(); +} + +// AccessibilityState values +constexpr MapBuffer::Key ACCESSIBILITY_STATE_BUSY = 0; +constexpr MapBuffer::Key ACCESSIBILITY_STATE_DISABLED = 1; +constexpr MapBuffer::Key ACCESSIBILITY_STATE_EXPANDED = 2; +constexpr MapBuffer::Key ACCESSIBILITY_STATE_SELECTED = 3; +constexpr MapBuffer::Key ACCESSIBILITY_STATE_CHECKED = 4; + +MapBuffer convertAccessibilityState(AccessibilityState const &state) { + MapBufferBuilder builder(5); + builder.putBool(ACCESSIBILITY_STATE_BUSY, state.busy); + builder.putBool(ACCESSIBILITY_STATE_DISABLED, state.disabled); + builder.putBool(ACCESSIBILITY_STATE_EXPANDED, state.expanded); + builder.putBool(ACCESSIBILITY_STATE_SELECTED, state.selected); + int checked; + switch (state.checked) { + case AccessibilityState::Unchecked: + checked = 0; + break; + case AccessibilityState::Checked: + checked = 1; + break; + case AccessibilityState::Mixed: + checked = 2; + break; + case AccessibilityState::None: + checked = 3; + break; + } + builder.putInt(ACCESSIBILITY_STATE_CHECKED, checked); + return builder.build(); +} + +// TODO: Currently unsupported: nextFocusForward/Left/Up/Right/Down +void AccessibilityProps::propsDiffMapBuffer( + Props const *oldPropsPtr, + MapBufferBuilder &builder) const { + // Call with default props if necessary + if (oldPropsPtr == nullptr) { + AccessibilityProps defaultProps{}; + propsDiffMapBuffer(reinterpret_cast(&defaultProps), builder); + return; + } + + AccessibilityProps const &oldProps = + *(reinterpret_cast(oldPropsPtr)); + AccessibilityProps const &newProps = *this; + + if (oldProps.accessibilityActions != newProps.accessibilityActions) { + builder.putMapBuffer( + AP_ACCESSIBILITY_ACTIONS, + convertAccessibilityActions(newProps.accessibilityActions)); + } + + if (oldProps.accessibilityHint != newProps.accessibilityHint) { + builder.putString(AP_ACCESSIBILITY_HINT, newProps.accessibilityHint); + } + + if (oldProps.accessibilityLabel != newProps.accessibilityLabel) { + builder.putString(AP_ACCESSIBILITY_LABEL, newProps.accessibilityLabel); + } + + if (oldProps.accessibilityLabelledBy != newProps.accessibilityLabelledBy) { + builder.putMapBuffer( + AP_ACCESSIBILITY_LABELLED_BY, + convertAccessibilityLabelledBy(newProps.accessibilityLabelledBy)); + } + + if (oldProps.accessibilityLiveRegion != newProps.accessibilityLiveRegion) { + int value; + switch (newProps.accessibilityLiveRegion) { + case AccessibilityLiveRegion::None: + value = 0; + break; + case AccessibilityLiveRegion::Polite: + value = 1; + break; + case AccessibilityLiveRegion::Assertive: + value = 2; + break; + } + builder.putInt(AP_ACCESSIBILITY_LIVE_REGION, value); + } + + if (oldProps.accessibilityRole != newProps.accessibilityRole) { + builder.putString(AP_ACCESSIBILITY_ROLE, newProps.accessibilityRole); + } + + if (oldProps.accessibilityState != newProps.accessibilityState) { + builder.putMapBuffer( + AP_ACCESSIBILITY_STATE, + convertAccessibilityState(newProps.accessibilityState)); + } + + if (oldProps.accessibilityValue != newProps.accessibilityValue) { + builder.putString( + AP_ACCESSIBILITY_VALUE, newProps.accessibilityValue.text.value_or("")); + } + + if (oldProps.accessible != newProps.accessible) { + builder.putBool(AP_ACCESSIBLE, newProps.accessible); + } + + if (oldProps.importantForAccessibility != + newProps.importantForAccessibility) { + int value; + switch (newProps.importantForAccessibility) { + case ImportantForAccessibility::Auto: + value = 0; + break; + case ImportantForAccessibility::Yes: + value = 1; + break; + case ImportantForAccessibility::No: + value = 2; + break; + case ImportantForAccessibility::NoHideDescendants: + value = 3; + break; + } + builder.putInt(AP_IMPORTANT_FOR_ACCESSIBILITY, value); + } +} +#endif + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/react/renderer/components/view/AccessibilityPropsMapBuffer.h b/ReactCommon/react/renderer/components/view/AccessibilityPropsMapBuffer.h new file mode 100644 index 00000000000..a4aa6c927ad --- /dev/null +++ b/ReactCommon/react/renderer/components/view/AccessibilityPropsMapBuffer.h @@ -0,0 +1,33 @@ +/* + * 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 + +namespace facebook { +namespace react { + +#ifdef ANDROID +constexpr MapBuffer::Key AP_ACCESSIBILITY_ACTIONS = 0; +constexpr MapBuffer::Key AP_ACCESSIBILITY_HINT = 1; +constexpr MapBuffer::Key AP_ACCESSIBILITY_LABEL = 2; +constexpr MapBuffer::Key AP_ACCESSIBILITY_LABELLED_BY = 3; +constexpr MapBuffer::Key AP_ACCESSIBILITY_LIVE_REGION = 4; +constexpr MapBuffer::Key AP_ACCESSIBILITY_ROLE = 5; +constexpr MapBuffer::Key AP_ACCESSIBILITY_STATE = 6; +constexpr MapBuffer::Key AP_ACCESSIBILITY_VALUE = 7; +constexpr MapBuffer::Key AP_ACCESSIBLE = 8; +constexpr MapBuffer::Key AP_IMPORTANT_FOR_ACCESSIBILITY = 19; + +// AccessibilityAction values +constexpr MapBuffer::Key ACCESSIBILITY_ACTION_NAME = 0; +constexpr MapBuffer::Key ACCESSIBILITY_ACTION_LABEL = 1; +#endif + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/react/renderer/components/view/ViewProps.h b/ReactCommon/react/renderer/components/view/ViewProps.h index cc09768ad73..ea08ea8defb 100644 --- a/ReactCommon/react/renderer/components/view/ViewProps.h +++ b/ReactCommon/react/renderer/components/view/ViewProps.h @@ -41,6 +41,11 @@ class ViewProps : public YogaStylableProps, public AccessibilityProps { const char *propName, RawValue const &value); +#ifdef ANDROID + void propsDiffMapBuffer(Props const *oldProps, MapBufferBuilder &builder) + const override; +#endif + #pragma mark - Props // Color @@ -51,7 +56,7 @@ class ViewProps : public YogaStylableProps, public AccessibilityProps { // Borders CascadedBorderRadii borderRadii{}; CascadedBorderColors borderColors{}; - CascadedBorderCurves borderCurves{}; + CascadedBorderCurves borderCurves{}; // iOS only? CascadedBorderStyles borderStyles{}; // Shadow diff --git a/ReactCommon/react/renderer/components/view/ViewPropsMapBuffer.cpp b/ReactCommon/react/renderer/components/view/ViewPropsMapBuffer.cpp new file mode 100644 index 00000000000..4136842c3b8 --- /dev/null +++ b/ReactCommon/react/renderer/components/view/ViewPropsMapBuffer.cpp @@ -0,0 +1,202 @@ +/* + * 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. + */ + +#ifdef ANDROID + +#include "ViewPropsMapBuffer.h" +#include "ViewProps.h" + +#include "viewPropConversions.h" + +#include +#include + +namespace facebook { +namespace react { + +// TODO: Currently unsupported: nextFocusForward/Left/Up/Right/Down +void ViewProps::propsDiffMapBuffer( + Props const *oldPropsPtr, + MapBufferBuilder &builder) const { + // Call with default props if necessary + if (oldPropsPtr == nullptr) { + ViewProps defaultProps{}; + propsDiffMapBuffer(&defaultProps, builder); + return; + } + + // Delegate to base classes + YogaStylableProps::propsDiffMapBuffer(oldPropsPtr, builder); + AccessibilityProps::propsDiffMapBuffer(oldPropsPtr, builder); + + ViewProps const &oldProps = *(static_cast(oldPropsPtr)); + ViewProps const &newProps = *this; + + if (oldProps.backfaceVisibility != newProps.backfaceVisibility) { + int value; + switch (newProps.backfaceVisibility) { + case BackfaceVisibility::Auto: + value = 0; + break; + case BackfaceVisibility::Visible: + value = 1; + break; + case BackfaceVisibility::Hidden: + value = 2; + break; + } + builder.putInt(VP_BACKFACE_VISIBILITY, value); + } + + if (oldProps.backgroundColor != newProps.backgroundColor) { + builder.putInt(VP_BG_COLOR, toAndroidRepr(newProps.backgroundColor)); + } + + if (oldProps.foregroundColor != newProps.foregroundColor) { + builder.putInt(VP_FG_COLOR, toAndroidRepr(newProps.foregroundColor)); + } + + if (oldProps.borderCurves != newProps.borderCurves) { + builder.putMapBuffer( + VP_BORDER_CURVES, convertCascadedCorners(newProps.borderCurves)); + } + + if (oldProps.borderColors != newProps.borderColors) { + builder.putMapBuffer( + VP_BORDER_COLOR, convertBorderColors(newProps.borderColors)); + } + + if (oldProps.borderRadii != newProps.borderRadii) { + builder.putMapBuffer( + VP_BORDER_RADII, convertCascadedCorners(newProps.borderRadii)); + } + + if (oldProps.borderStyles != newProps.borderStyles) { + builder.putMapBuffer( + VP_BORDER_STYLE, convertCascadedEdges(newProps.borderStyles)); + } + + if (oldProps.elevation != newProps.elevation) { + builder.putDouble(VP_ELEVATION, newProps.elevation); + } + + if (oldProps.focusable != newProps.focusable) { + builder.putBool(VP_FOCUSABLE, newProps.focusable); + } + + if (oldProps.hasTVPreferredFocus != newProps.hasTVPreferredFocus) { + builder.putBool(VP_HAS_TV_FOCUS, newProps.hasTVPreferredFocus); + } + + if (oldProps.hitSlop != newProps.hitSlop) { + builder.putMapBuffer(VP_HIT_SLOP, convertEdgeInsets(newProps.hitSlop)); + } + + if (oldProps.nativeBackground != newProps.nativeBackground) { + builder.putMapBuffer( + VP_NATIVE_BACKGROUND, + convertNativeBackground(newProps.nativeBackground)); + } + + if (oldProps.nativeForeground != newProps.nativeForeground) { + builder.putMapBuffer( + VP_NATIVE_FOREGROUND, + convertNativeBackground(newProps.nativeForeground)); + } + + if (oldProps.needsOffscreenAlphaCompositing != + newProps.needsOffscreenAlphaCompositing) { + builder.putBool( + VP_OFFSCREEN_ALPHA_COMPOSITING, + newProps.needsOffscreenAlphaCompositing); + } + + if (oldProps.opacity != newProps.opacity) { + builder.putDouble(VP_OPACITY, newProps.opacity); + } + + if (oldProps.pointerEvents != newProps.pointerEvents) { + int value; + switch (newProps.pointerEvents) { + case PointerEventsMode::Auto: + value = 0; + break; + case PointerEventsMode::None: + value = 1; + break; + case PointerEventsMode::BoxNone: + value = 2; + break; + case PointerEventsMode::BoxOnly: + value = 3; + break; + } + + builder.putInt(VP_POINTER_EVENTS, value); + } + + if (oldProps.events != newProps.events) { + builder.putBool( + VP_POINTER_ENTER, newProps.events[ViewEvents::Offset::PointerEnter]); + builder.putBool( + VP_POINTER_LEAVE, newProps.events[ViewEvents::Offset::PointerLeave]); + builder.putBool( + VP_POINTER_MOVE, newProps.events[ViewEvents::Offset::PointerMove]); + + builder.putBool( + VP_POINTER_ENTER_CAPTURE, + newProps.events[ViewEvents::Offset::PointerEnterCapture]); + builder.putBool( + VP_POINTER_LEAVE_CAPTURE, + newProps.events[ViewEvents::Offset::PointerLeaveCapture]); + builder.putBool( + VP_POINTER_MOVE_CAPTURE, + newProps.events[ViewEvents::Offset::PointerMoveCapture]); + builder.putBool( + VP_POINTER_OVER, newProps.events[ViewEvents::Offset::PointerOver]); + builder.putBool( + VP_POINTER_OVER_CAPTURE, + newProps.events[ViewEvents::Offset::PointerOverCapture]); + + builder.putBool( + VP_POINTER_OUT, newProps.events[ViewEvents::Offset::PointerOut]); + builder.putBool( + VP_POINTER_OUT_CAPTURE, + newProps.events[ViewEvents::Offset::PointerOutCapture]); + } + + if (oldProps.removeClippedSubviews != newProps.removeClippedSubviews) { + builder.putBool(VP_REMOVE_CLIPPED_SUBVIEW, newProps.removeClippedSubviews); + } + + if (oldProps.renderToHardwareTextureAndroid != + newProps.renderToHardwareTextureAndroid) { + builder.putBool( + VP_RENDER_TO_HARDWARE_TEXTURE, newProps.renderToHardwareTextureAndroid); + } + + if (oldProps.shadowColor != newProps.shadowColor) { + builder.putInt(VP_SHADOW_COLOR, toAndroidRepr(newProps.shadowColor)); + } + + if (oldProps.testId != newProps.testId) { + builder.putString(VP_TEST_ID, newProps.testId); + } + + if (oldProps.transform != newProps.transform) { + builder.putMapBuffer(VP_TRANSFORM, convertTransform(newProps.transform)); + } + + if (oldProps.zIndex != newProps.zIndex) { + builder.putInt(VP_ZINDEX, newProps.zIndex.value_or(0)); + } +} + +} // namespace react +} // namespace facebook + +#endif diff --git a/ReactCommon/react/renderer/components/view/ViewPropsMapBuffer.h b/ReactCommon/react/renderer/components/view/ViewPropsMapBuffer.h new file mode 100644 index 00000000000..45a583575ae --- /dev/null +++ b/ReactCommon/react/renderer/components/view/ViewPropsMapBuffer.h @@ -0,0 +1,56 @@ +/* + * 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 + +namespace facebook { +namespace react { + +#ifdef ANDROID +constexpr MapBuffer::Key VP_BACKFACE_VISIBILITY = 9; +constexpr MapBuffer::Key VP_BG_COLOR = 10; +constexpr MapBuffer::Key VP_BORDER_COLOR = 11; +constexpr MapBuffer::Key VP_BORDER_RADII = 12; +constexpr MapBuffer::Key VP_BORDER_STYLE = 13; +constexpr MapBuffer::Key VP_COLLAPSABLE = 14; +constexpr MapBuffer::Key VP_ELEVATION = 15; +constexpr MapBuffer::Key VP_FOCUSABLE = 16; +constexpr MapBuffer::Key VP_HAS_TV_FOCUS = 17; +constexpr MapBuffer::Key VP_HIT_SLOP = 18; +constexpr MapBuffer::Key VP_NATIVE_BACKGROUND = 20; +constexpr MapBuffer::Key VP_NATIVE_FOREGROUND = 21; +constexpr MapBuffer::Key VP_OFFSCREEN_ALPHA_COMPOSITING = 23; +constexpr MapBuffer::Key VP_OPACITY = 24; +constexpr MapBuffer::Key VP_POINTER_EVENTS = 25; +constexpr MapBuffer::Key VP_POINTER_ENTER = 26; +constexpr MapBuffer::Key VP_POINTER_LEAVE = 27; +constexpr MapBuffer::Key VP_POINTER_MOVE = 28; +constexpr MapBuffer::Key VP_REMOVE_CLIPPED_SUBVIEW = 29; +constexpr MapBuffer::Key VP_RENDER_TO_HARDWARE_TEXTURE = 30; +constexpr MapBuffer::Key VP_SHADOW_COLOR = 31; +constexpr MapBuffer::Key VP_TEST_ID = 32; +constexpr MapBuffer::Key VP_TRANSFORM = 33; +constexpr MapBuffer::Key VP_ZINDEX = 34; +constexpr MapBuffer::Key VP_POINTER_ENTER_CAPTURE = 38; +constexpr MapBuffer::Key VP_POINTER_LEAVE_CAPTURE = 39; +constexpr MapBuffer::Key VP_POINTER_MOVE_CAPTURE = 40; +constexpr MapBuffer::Key VP_POINTER_OVER = 41; +constexpr MapBuffer::Key VP_POINTER_OVER_CAPTURE = 42; +constexpr MapBuffer::Key VP_POINTER_OUT = 43; +constexpr MapBuffer::Key VP_POINTER_OUT_CAPTURE = 44; +constexpr MapBuffer::Key VP_BORDER_CURVES = 45; +constexpr MapBuffer::Key VP_FG_COLOR = 46; + +// Yoga values +constexpr MapBuffer::Key YG_BORDER_WIDTH = 100; +constexpr MapBuffer::Key YG_OVERFLOW = 101; +#endif + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/react/renderer/components/view/YogaStylableProps.h b/ReactCommon/react/renderer/components/view/YogaStylableProps.h index 86cf60e81be..b19a90df2f0 100644 --- a/ReactCommon/react/renderer/components/view/YogaStylableProps.h +++ b/ReactCommon/react/renderer/components/view/YogaStylableProps.h @@ -31,6 +31,11 @@ class YogaStylableProps : public Props { const char *propName, RawValue const &value); +#ifdef ANDROID + void propsDiffMapBuffer(Props const *oldProps, MapBufferBuilder &builder) + const override; +#endif + #pragma mark - Props YGStyle yogaStyle{}; @@ -39,7 +44,7 @@ class YogaStylableProps : public Props { #pragma mark - DebugStringConvertible (Partial) - SharedDebugStringConvertibleList getDebugProps() const; + SharedDebugStringConvertibleList getDebugProps() const override; #endif }; diff --git a/ReactCommon/react/renderer/components/view/YogaStylablePropsMapBuffer.cpp b/ReactCommon/react/renderer/components/view/YogaStylablePropsMapBuffer.cpp new file mode 100644 index 00000000000..ac8a3c2ad55 --- /dev/null +++ b/ReactCommon/react/renderer/components/view/YogaStylablePropsMapBuffer.cpp @@ -0,0 +1,87 @@ +/* + * 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. + */ + +#ifdef ANDROID + +#include "ViewProps.h" +#include "ViewPropsMapBuffer.h" + +#include "viewPropConversions.h" + +#include + +namespace facebook { +namespace react { + +MapBuffer convertBorderWidths(YGStyle::Edges const &border) { + MapBufferBuilder builder(7); + putOptionalFloat( + builder, EDGE_TOP, optionalFloatFromYogaValue(border[YGEdgeTop])); + putOptionalFloat( + builder, EDGE_RIGHT, optionalFloatFromYogaValue(border[YGEdgeRight])); + putOptionalFloat( + builder, EDGE_BOTTOM, optionalFloatFromYogaValue(border[YGEdgeBottom])); + putOptionalFloat( + builder, EDGE_LEFT, optionalFloatFromYogaValue(border[YGEdgeLeft])); + putOptionalFloat( + builder, EDGE_START, optionalFloatFromYogaValue(border[YGEdgeStart])); + putOptionalFloat( + builder, EDGE_END, optionalFloatFromYogaValue(border[YGEdgeEnd])); + putOptionalFloat( + builder, EDGE_ALL, optionalFloatFromYogaValue(border[YGEdgeAll])); + return builder.build(); +} + +// TODO: Currently unsupported: nextFocusForward/Left/Up/Right/Down +void YogaStylableProps::propsDiffMapBuffer( + Props const *oldPropsPtr, + MapBufferBuilder &builder) const { + // Call with default props if necessary + if (oldPropsPtr == nullptr) { + YogaStylableProps defaultProps{}; + propsDiffMapBuffer(&defaultProps, builder); + return; + } + + // Delegate to base classes + Props::propsDiffMapBuffer(oldPropsPtr, builder); + + YogaStylableProps const &oldProps = + *(static_cast(oldPropsPtr)); + YogaStylableProps const &newProps = *this; + + if (oldProps.yogaStyle != newProps.yogaStyle) { + auto const &oldStyle = oldProps.yogaStyle; + auto const &newStyle = newProps.yogaStyle; + + if (!(oldStyle.border() == newStyle.border())) { + builder.putMapBuffer( + YG_BORDER_WIDTH, convertBorderWidths(newStyle.border())); + } + + if (oldStyle.overflow() != newStyle.overflow()) { + int value; + switch (newStyle.overflow()) { + case YGOverflowVisible: + value = 0; + break; + case YGOverflowHidden: + value = 1; + break; + case YGOverflowScroll: + value = 2; + break; + } + builder.putInt(YG_OVERFLOW, value); + } + } +} + +} // namespace react +} // namespace facebook + +#endif diff --git a/ReactCommon/react/renderer/components/view/YogaStylablePropsMapBuffer.h b/ReactCommon/react/renderer/components/view/YogaStylablePropsMapBuffer.h new file mode 100644 index 00000000000..69b0e419b71 --- /dev/null +++ b/ReactCommon/react/renderer/components/view/YogaStylablePropsMapBuffer.h @@ -0,0 +1,24 @@ +/* + * 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 + +#ifdef ANDROID + +#include + +namespace facebook { +namespace react { + +// Yoga values +constexpr MapBuffer::Key YG_BORDER_WIDTH = 100; +constexpr MapBuffer::Key YG_OVERFLOW = 101; + +} // namespace react +} // namespace facebook + +#endif diff --git a/ReactCommon/react/renderer/components/view/viewPropConversions.h b/ReactCommon/react/renderer/components/view/viewPropConversions.h new file mode 100644 index 00000000000..6a672aef01a --- /dev/null +++ b/ReactCommon/react/renderer/components/view/viewPropConversions.h @@ -0,0 +1,198 @@ +/* + * 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 +#include + +#include + +namespace facebook { +namespace react { + +namespace { + +constexpr MapBuffer::Key EDGE_TOP = 0; +constexpr MapBuffer::Key EDGE_LEFT = 1; +constexpr MapBuffer::Key EDGE_RIGHT = 2; +constexpr MapBuffer::Key EDGE_BOTTOM = 3; +constexpr MapBuffer::Key EDGE_START = 4; +constexpr MapBuffer::Key EDGE_END = 5; +constexpr MapBuffer::Key EDGE_ALL = 6; + +constexpr MapBuffer::Key CORNER_TOP_LEFT = 0; +constexpr MapBuffer::Key CORNER_TOP_RIGHT = 1; +constexpr MapBuffer::Key CORNER_BOTTOM_RIGHT = 2; +constexpr MapBuffer::Key CORNER_BOTTOM_LEFT = 3; +constexpr MapBuffer::Key CORNER_TOP_START = 4; +constexpr MapBuffer::Key CORNER_TOP_END = 5; +constexpr MapBuffer::Key CORNER_BOTTOM_END = 6; +constexpr MapBuffer::Key CORNER_BOTTOM_START = 7; +constexpr MapBuffer::Key CORNER_ALL = 8; + +inline void putOptionalFloat( + MapBufferBuilder &builder, + MapBuffer::Key key, + std::optional const &value) { + builder.putDouble(key, value.value_or(NAN)); +} + +inline std::optional optionalFromValue( + std::optional const &value) { + if (!value) { + return {}; + } + + return {value.value() == BorderCurve::Circular ? 1 : 2}; +} + +inline std::optional optionalFromValue( + std::optional const &value) { + return value; +} + +inline std::optional optionalFromValue( + std::optional const &value) { + if (!value) { + return {}; + } + + int intValue = -1; + switch (value.value()) { + case BorderStyle::Solid: + intValue = 0; + break; + case BorderStyle::Dotted: + intValue = 1; + break; + case BorderStyle::Dashed: + intValue = 2; + break; + } + + return {intValue}; +} + +inline void putOptionalColor( + MapBufferBuilder &builder, + MapBuffer::Key key, + std::optional const &color) { + builder.putInt(key, color.has_value() ? toAndroidRepr(color.value()) : -1); +} + +inline MapBuffer convertBorderColors(CascadedBorderColors const &colors) { + MapBufferBuilder builder(7); + putOptionalColor(builder, EDGE_TOP, colors.top); + putOptionalColor(builder, EDGE_RIGHT, colors.right); + putOptionalColor(builder, EDGE_BOTTOM, colors.bottom); + putOptionalColor(builder, EDGE_LEFT, colors.left); + putOptionalColor(builder, EDGE_START, colors.start); + putOptionalColor(builder, EDGE_END, colors.end); + putOptionalColor(builder, EDGE_ALL, colors.all); + return builder.build(); +} + +template +MapBuffer convertCascadedEdges(CascadedRectangleEdges const &edges) { + MapBufferBuilder builder(7); + putOptionalFloat(builder, EDGE_TOP, optionalFromValue(edges.top)); + putOptionalFloat(builder, EDGE_RIGHT, optionalFromValue(edges.right)); + putOptionalFloat(builder, EDGE_BOTTOM, optionalFromValue(edges.bottom)); + putOptionalFloat(builder, EDGE_LEFT, optionalFromValue(edges.left)); + putOptionalFloat(builder, EDGE_START, optionalFromValue(edges.start)); + putOptionalFloat(builder, EDGE_END, optionalFromValue(edges.end)); + putOptionalFloat(builder, EDGE_ALL, optionalFromValue(edges.all)); + return builder.build(); +} + +template +MapBuffer convertCascadedCorners(CascadedRectangleCorners const &corners) { + MapBufferBuilder builder(9); + putOptionalFloat( + builder, CORNER_TOP_LEFT, optionalFromValue(corners.topLeft)); + putOptionalFloat( + builder, CORNER_TOP_RIGHT, optionalFromValue(corners.topRight)); + putOptionalFloat( + builder, CORNER_BOTTOM_RIGHT, optionalFromValue(corners.bottomRight)); + putOptionalFloat( + builder, CORNER_BOTTOM_LEFT, optionalFromValue(corners.bottomLeft)); + putOptionalFloat( + builder, CORNER_TOP_START, optionalFromValue(corners.topStart)); + putOptionalFloat(builder, CORNER_TOP_END, optionalFromValue(corners.topEnd)); + putOptionalFloat( + builder, CORNER_BOTTOM_END, optionalFromValue(corners.bottomEnd)); + putOptionalFloat( + builder, CORNER_BOTTOM_START, optionalFromValue(corners.bottomStart)); + putOptionalFloat(builder, CORNER_ALL, optionalFromValue(corners.all)); + return builder.build(); +} + +inline MapBuffer convertEdgeInsets(EdgeInsets const &insets) { + MapBufferBuilder builder(4); + builder.putDouble(EDGE_TOP, insets.top); + builder.putDouble(EDGE_RIGHT, insets.right); + builder.putDouble(EDGE_BOTTOM, insets.bottom); + builder.putDouble(EDGE_LEFT, insets.left); + return builder.build(); +} + +#ifdef ANDROID + +constexpr MapBuffer::Key NATIVE_DRAWABLE_KIND = 0; +constexpr MapBuffer::Key NATIVE_DRAWABLE_ATTRIBUTE = 1; +constexpr MapBuffer::Key NATIVE_DRAWABLE_COLOR = 2; +constexpr MapBuffer::Key NATIVE_DRAWABLE_BORDERLESS = 3; +constexpr MapBuffer::Key NATIVE_DRAWABLE_RIPPLE_RADIUS = 4; + +inline MapBuffer convertNativeBackground( + std::optional const &value) { + if (!value.has_value()) { + return MapBufferBuilder::EMPTY(); + } + + auto const &drawable = value.value(); + MapBufferBuilder builder(4); + switch (drawable.kind) { + case NativeDrawable::Kind::ThemeAttr: + builder.putInt(NATIVE_DRAWABLE_KIND, 0); + builder.putString(NATIVE_DRAWABLE_ATTRIBUTE, drawable.themeAttr); + break; + case NativeDrawable::Kind::Ripple: + builder.putInt(NATIVE_DRAWABLE_KIND, 1); + if (drawable.ripple.color.has_value()) { + builder.putInt(NATIVE_DRAWABLE_COLOR, drawable.ripple.color.value()); + } + + builder.putBool(NATIVE_DRAWABLE_BORDERLESS, drawable.ripple.borderless); + if (drawable.ripple.rippleRadius.has_value()) { + builder.putDouble( + NATIVE_DRAWABLE_RIPPLE_RADIUS, + drawable.ripple.rippleRadius.value()); + } + break; + } + return builder.build(); +} + +#endif + +inline MapBuffer convertTransform(Transform const &transform) { + MapBufferBuilder builder(16); + for (int32_t i = 0; i < transform.matrix.size(); i++) { + builder.putDouble(i, transform.matrix[i]); + } + return builder.build(); +} +} // namespace + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/react/renderer/core/CMakeLists.txt b/ReactCommon/react/renderer/core/CMakeLists.txt index 09627498c93..d776881dda1 100644 --- a/ReactCommon/react/renderer/core/CMakeLists.txt +++ b/ReactCommon/react/renderer/core/CMakeLists.txt @@ -26,4 +26,5 @@ target_link_libraries(react_render_core react_debug react_render_debug react_render_graphics + react_render_mapbuffer react_utils) diff --git a/ReactCommon/react/renderer/core/Props.cpp b/ReactCommon/react/renderer/core/Props.cpp index cdca7cc8fbe..e78db62c209 100644 --- a/ReactCommon/react/renderer/core/Props.cpp +++ b/ReactCommon/react/renderer/core/Props.cpp @@ -6,6 +6,7 @@ */ #include "Props.h" +#include "PropsMapBuffer.h" #include #include diff --git a/ReactCommon/react/renderer/core/Props.h b/ReactCommon/react/renderer/core/Props.h index a6f4113caad..8daeb35dbe5 100644 --- a/ReactCommon/react/renderer/core/Props.h +++ b/ReactCommon/react/renderer/core/Props.h @@ -16,6 +16,10 @@ #include #include +#ifdef ANDROID +#include +#endif + namespace facebook { namespace react { @@ -71,6 +75,10 @@ class Props : public virtual Sealable, public virtual DebugStringConvertible { #ifdef ANDROID folly::dynamic rawProps = folly::dynamic::object(); + + virtual void propsDiffMapBuffer( + Props const *oldProps, + MapBufferBuilder &builder) const; #endif }; diff --git a/ReactCommon/react/renderer/core/PropsMapBuffer.cpp b/ReactCommon/react/renderer/core/PropsMapBuffer.cpp new file mode 100644 index 00000000000..6ce2241ef46 --- /dev/null +++ b/ReactCommon/react/renderer/core/PropsMapBuffer.cpp @@ -0,0 +1,37 @@ +/* + * 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 "PropsMapBuffer.h" +#include "Props.h" + +#include + +namespace facebook { +namespace react { + +#ifdef ANDROID +void Props::propsDiffMapBuffer( + Props const *oldPropsPtr, + MapBufferBuilder &builder) const { + // Call with default props if necessary + if (oldPropsPtr == nullptr) { + Props defaultProps{}; + propsDiffMapBuffer(&defaultProps, builder); + return; + } + + Props const &oldProps = *oldPropsPtr; + Props const &newProps = *this; + + if (oldProps.nativeId != newProps.nativeId) { + builder.putString(PROPS_NATIVE_ID, nativeId); + } +} +#endif + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/react/renderer/core/PropsMapBuffer.h b/ReactCommon/react/renderer/core/PropsMapBuffer.h new file mode 100644 index 00000000000..ad6b9bd08df --- /dev/null +++ b/ReactCommon/react/renderer/core/PropsMapBuffer.h @@ -0,0 +1,23 @@ +/* + * 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 + +#ifdef ANDROID + +#include + +namespace facebook { +namespace react { + +constexpr MapBuffer::Key PROPS_MAX = 1; +constexpr MapBuffer::Key PROPS_NATIVE_ID = 1; + +} // namespace react +} // namespace facebook + +#endif