Skip to content

Commit

Permalink
(Almost) align Android TextLayoutManager interface with iOS one (#48209)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #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
  • Loading branch information
christophpurrer authored and facebook-github-bot committed Dec 12, 2024
1 parent 26f4c78 commit 59c72e9
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@

#include "TextLayoutManager.h"

#include <limits>

#include <react/common/mapbuffer/JReadableMapBuffer.h>
#include <react/jni/ReadableNativeMap.h>
#include <react/renderer/attributedstring/conversions.h>
Expand All @@ -17,11 +15,11 @@
#include <react/renderer/mapbuffer/MapBufferBuilder.h>
#include <react/renderer/telemetry/TransactionTelemetry.h>

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()) {
Expand All @@ -46,7 +44,7 @@ Size measureAndroidComponent(
jfloatArray attachmentPositions) {
const jni::global_ref<jobject>& fabricUIManager =
contextContainer->at<jni::global_ref<jobject>>("FabricUIManager");
auto componentNameRef = make_jstring(componentName);
auto componentNameRef = jni::make_jstring(componentName);

static auto measure =
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
Expand Down Expand Up @@ -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<Float>::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),
Expand All @@ -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();
Expand All @@ -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;
Expand Down Expand Up @@ -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<Float>::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
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand Down

0 comments on commit 59c72e9

Please sign in to comment.