From 59c72e9d297ef1b95b4b74e06d4d8f71ffa33d56 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Thu, 12 Dec 2024 10:22:25 -0800 Subject: [PATCH] (Almost) align Android TextLayoutManager interface with iOS one (#48209) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/48209 [Changelog] [Internal] - (Almost) align Android TextLayoutManager interface with iOS one This change aligns the public API surface of `TextLayoutManager` from RN Android closer to the RN iOS one. Reviewed By: javache Differential Revision: D67061225 fbshipit-source-id: b06f47c7e322bdac429cefb85bf2f2a80210a64f --- .../textlayoutmanager/TextLayoutManager.cpp | 148 +++++++++--------- .../textlayoutmanager/TextLayoutManager.h | 5 - 2 files changed, 77 insertions(+), 76 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.cpp b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.cpp index 70defbdf564..507403cd178 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.cpp +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.cpp @@ -7,8 +7,6 @@ #include "TextLayoutManager.h" -#include - #include #include #include @@ -17,11 +15,11 @@ #include #include -using namespace facebook::jni; - namespace facebook::react { -static int countAttachments(const AttributedString& attributedString) { +namespace { + +int countAttachments(const AttributedString& attributedString) { int count = 0; for (const auto& fragment : attributedString.getFragments()) { @@ -46,7 +44,7 @@ Size measureAndroidComponent( jfloatArray attachmentPositions) { const jni::global_ref& fabricUIManager = contextContainer->at>("FabricUIManager"); - auto componentNameRef = make_jstring(componentName); + auto componentNameRef = jni::make_jstring(componentName); static auto measure = jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") @@ -86,6 +84,73 @@ Size measureAndroidComponent( return size; } +TextMeasurement doMeasure( + const ContextContainer::Shared& contextContainer, + const AttributedString& attributedString, + const ParagraphAttributes& paragraphAttributes, + const LayoutConstraints& layoutConstraints) { + const int attachmentCount = countAttachments(attributedString); + auto env = jni::Environment::current(); + auto attachmentPositions = env->NewFloatArray(attachmentCount * 2); + + auto minimumSize = layoutConstraints.minimumSize; + auto maximumSize = layoutConstraints.maximumSize; + + // We assume max height will have no effect on measurement, so we override it + // with a constant value with no constraints, to enable cache reuse later down + // in the stack. + // TODO: This is suss, and not at the right layer + maximumSize.height = std::numeric_limits::infinity(); + + auto attributedStringMap = toMapBuffer(attributedString); + auto paragraphAttributesMap = toMapBuffer(paragraphAttributes); + + auto size = measureAndroidComponent( + contextContainer, + -1, // TODO: we should pass rootTag in + "RCTText", + std::move(attributedStringMap), + std::move(paragraphAttributesMap), + minimumSize.width, + maximumSize.width, + minimumSize.height, + maximumSize.height, + attachmentPositions); + + jfloat* attachmentData = + env->GetFloatArrayElements(attachmentPositions, nullptr); + + auto attachments = TextMeasurement::Attachments{}; + if (attachmentCount > 0) { + int attachmentIndex = 0; + for (const auto& fragment : attributedString.getFragments()) { + if (fragment.isAttachment()) { + float top = attachmentData[attachmentIndex * 2]; + float left = attachmentData[attachmentIndex * 2 + 1]; + float width = fragment.parentShadowView.layoutMetrics.frame.size.width; + float height = + fragment.parentShadowView.layoutMetrics.frame.size.height; + + auto rect = facebook::react::Rect{ + .origin = {.x = left, .y = top}, + .size = facebook::react::Size{.width = width, .height = height}}; + attachments.push_back( + TextMeasurement::Attachment{.frame = rect, .isClipped = false}); + attachmentIndex++; + } + } + } + + // Clean up allocated ref + env->ReleaseFloatArrayElements( + attachmentPositions, attachmentData, JNI_ABORT); + env->DeleteLocalRef(attachmentPositions); + + return TextMeasurement{.size = size, .attachments = attachments}; +} + +} // namespace + TextLayoutManager::TextLayoutManager( const ContextContainer::Shared& contextContainer) : contextContainer_(contextContainer), @@ -107,8 +172,11 @@ TextMeasurement TextLayoutManager::measure( telemetry->willMeasureText(); } - auto measurement = - doMeasure(attributedString, paragraphAttributes, layoutConstraints); + auto measurement = doMeasure( + contextContainer_, + attributedString, + paragraphAttributes, + layoutConstraints); if (telemetry != nullptr) { telemetry->didMeasureText(); @@ -125,7 +193,7 @@ TextMeasurement TextLayoutManager::measureCachedSpannableById( int64_t cacheId, const ParagraphAttributes& paragraphAttributes, const LayoutConstraints& layoutConstraints) const { - auto env = Environment::current(); + auto env = jni::Environment::current(); auto attachmentPositions = env->NewFloatArray(0); auto minimumSize = layoutConstraints.minimumSize; auto maximumSize = layoutConstraints.maximumSize; @@ -223,66 +291,4 @@ Float TextLayoutManager::baseline( } } -TextMeasurement TextLayoutManager::doMeasure( - const AttributedString& attributedString, - const ParagraphAttributes& paragraphAttributes, - const LayoutConstraints& layoutConstraints) const { - const int attachmentCount = countAttachments(attributedString); - auto env = Environment::current(); - auto attachmentPositions = env->NewFloatArray(attachmentCount * 2); - - auto minimumSize = layoutConstraints.minimumSize; - auto maximumSize = layoutConstraints.maximumSize; - - // We assume max height will have no effect on measurement, so we override it - // with a constant value with no constraints, to enable cache reuse later down - // in the stack. - // TODO: This is suss, and not at the right layer - maximumSize.height = std::numeric_limits::infinity(); - - auto attributedStringMap = toMapBuffer(attributedString); - auto paragraphAttributesMap = toMapBuffer(paragraphAttributes); - - auto size = measureAndroidComponent( - contextContainer_, - -1, // TODO: we should pass rootTag in - "RCTText", - std::move(attributedStringMap), - std::move(paragraphAttributesMap), - minimumSize.width, - maximumSize.width, - minimumSize.height, - maximumSize.height, - attachmentPositions); - - jfloat* attachmentData = - env->GetFloatArrayElements(attachmentPositions, nullptr); - - auto attachments = TextMeasurement::Attachments{}; - if (attachmentCount > 0) { - int attachmentIndex = 0; - for (const auto& fragment : attributedString.getFragments()) { - if (fragment.isAttachment()) { - float top = attachmentData[attachmentIndex * 2]; - float left = attachmentData[attachmentIndex * 2 + 1]; - float width = fragment.parentShadowView.layoutMetrics.frame.size.width; - float height = - fragment.parentShadowView.layoutMetrics.frame.size.height; - - auto rect = facebook::react::Rect{ - {left, top}, facebook::react::Size{width, height}}; - attachments.push_back(TextMeasurement::Attachment{rect, false}); - attachmentIndex++; - } - } - } - - // Clean up allocated ref - env->ReleaseFloatArrayElements( - attachmentPositions, attachmentData, JNI_ABORT); - env->DeleteLocalRef(attachmentPositions); - - return TextMeasurement{size, attachments}; -} - } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.h b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.h index 845fbabb05f..ebc93341739 100644 --- a/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.h +++ b/packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.h @@ -74,11 +74,6 @@ class TextLayoutManager { const Size& size) const; private: - TextMeasurement doMeasure( - const AttributedString& attributedString, - const ParagraphAttributes& paragraphAttributes, - const LayoutConstraints& layoutConstraints) const; - ContextContainer::Shared contextContainer_; TextMeasureCache textMeasureCache_; LineMeasureCache lineMeasureCache_;