Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Partial implementation of TextLayoutManager::measureLines #12930

Merged
merged 3 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Partial implementation of TextLayoutManager::measureLines",
"packageName": "react-native-windows",
"email": "30809111+acoates-ms@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,11 @@
namespace facebook::react {

void TextLayoutManager::GetTextLayout(
AttributedStringBox attributedStringBox,
ParagraphAttributes paragraphAttributes,
LayoutConstraints layoutConstraints,
const AttributedString &attributedString,
const ParagraphAttributes &paragraphAttributes,
Size size,
winrt::com_ptr<IDWriteTextLayout> &spTextLayout) noexcept {
if (attributedStringBox.getValue().isEmpty())
return;

auto fragments = attributedStringBox.getValue().getFragments();
auto fragments = attributedString.getFragments();
auto outerFragment = fragments[0];

DWRITE_FONT_STYLE style = DWRITE_FONT_STYLE_NORMAL;
Expand Down Expand Up @@ -86,14 +83,14 @@ void TextLayoutManager::GetTextLayout(
}
winrt::check_hresult(spTextFormat->SetTextAlignment(alignment));

auto str = GetTransformedText(attributedStringBox);
auto str = GetTransformedText(attributedString);

winrt::check_hresult(Microsoft::ReactNative::DWriteFactory()->CreateTextLayout(
str.c_str(), // The string to be laid out and formatted.
static_cast<UINT32>(str.size()), // The length of the string.
spTextFormat.get(), // The text format to apply to the string (contains font information, etc).
layoutConstraints.maximumSize.width, // The width of the layout box.
layoutConstraints.maximumSize.height, // The height of the layout box.
size.width, // The width of the layout box.
size.height, // The height of the layout box.
spTextLayout.put() // The IDWriteTextLayout interface pointer.
));

Expand Down Expand Up @@ -129,9 +126,20 @@ void TextLayoutManager::GetTextLayout(
}
}

void TextLayoutManager::GetTextLayout(
const AttributedStringBox &attributedStringBox,
const ParagraphAttributes &paragraphAttributes,
LayoutConstraints layoutConstraints,
winrt::com_ptr<IDWriteTextLayout> &spTextLayout) noexcept {
if (attributedStringBox.getValue().isEmpty())
return;

GetTextLayout(attributedStringBox.getValue(), paragraphAttributes, layoutConstraints.maximumSize, spTextLayout);
}

TextMeasurement TextLayoutManager::measure(
AttributedStringBox attributedStringBox,
ParagraphAttributes paragraphAttributes,
const AttributedStringBox &attributedStringBox,
const ParagraphAttributes &paragraphAttributes,
const TextLayoutContext &layoutContext,
LayoutConstraints layoutConstraints,
std::shared_ptr<void> /* hostTextStorage */) const {
Expand Down Expand Up @@ -185,31 +193,12 @@ TextMeasurement TextLayoutManager::measure(
*/
TextMeasurement TextLayoutManager::measureCachedSpannableById(
int64_t cacheId,
ParagraphAttributes const &paragraphAttributes,
const ParagraphAttributes &paragraphAttributes,
LayoutConstraints layoutConstraints) const {
assert(false);
return {};
}

LinesMeasurements TextLayoutManager::measureLines(
AttributedString attributedString,
ParagraphAttributes paragraphAttributes,
Size size) const {
assert(false);
return {};
}

std::shared_ptr<void> TextLayoutManager::getHostTextStorage(
AttributedString attributedString,
ParagraphAttributes paragraphAttributes,
LayoutConstraints layoutConstraints) const {
return nullptr;
}

void *TextLayoutManager::getNativeTextLayoutManager() const {
return (void *)this;
}

Microsoft::ReactNative::TextTransform ConvertTextTransform(std::optional<TextTransform> const &transform) {
if (transform) {
switch (transform.value()) {
Expand All @@ -229,9 +218,92 @@ Microsoft::ReactNative::TextTransform ConvertTextTransform(std::optional<TextTra
return Microsoft::ReactNative::TextTransform::Undefined;
}

winrt::hstring TextLayoutManager::GetTransformedText(AttributedStringBox const &attributedStringBox) {
LinesMeasurements TextLayoutManager::measureLines(
const AttributedString &attributedString,
const ParagraphAttributes &paragraphAttributes,
Size size) const {
LinesMeasurements lineMeasurements{};

winrt::com_ptr<IDWriteTextLayout> spTextLayout;

GetTextLayout(attributedString, paragraphAttributes, size, spTextLayout);

if (spTextLayout) {
std::vector<DWRITE_LINE_METRICS> lineMetrics;
uint32_t actualLineCount;
spTextLayout->GetLineMetrics(nullptr, 0, &actualLineCount);
lineMetrics.resize(static_cast<size_t>(actualLineCount));
winrt::check_hresult(spTextLayout->GetLineMetrics(lineMetrics.data(), actualLineCount, &actualLineCount));
uint32_t startRange = 0;
const auto count = (paragraphAttributes.maximumNumberOfLines > 0)
? std::min(static_cast<uint32_t>(paragraphAttributes.maximumNumberOfLines), actualLineCount)
: actualLineCount;
for (uint32_t i = 0; i < count; ++i) {
UINT32 actualHitTestCount = 0;
spTextLayout->HitTestTextRange(
startRange,
lineMetrics[i].length,
0, // x
0, // y
NULL,
0, // metrics count
&actualHitTestCount);

// Allocate enough room to return all hit-test metrics.
std::vector<DWRITE_HIT_TEST_METRICS> hitTestMetrics(actualHitTestCount);
spTextLayout->HitTestTextRange(
startRange,
lineMetrics[i].length,
0, // x
0, // y
&hitTestMetrics[0],
static_cast<UINT32>(hitTestMetrics.size()),
&actualHitTestCount);

float width = 0;
for (auto tm : hitTestMetrics) {
width += tm.width;
}

std::string str;
for (const auto &fragment : attributedString.getFragments()) {
str = str +
winrt::to_string(Microsoft::ReactNative::TransformableText::TransformText(
winrt::hstring{Microsoft::Common::Unicode::Utf8ToUtf16(fragment.string)},
ConvertTextTransform(fragment.textAttributes.textTransform)));
}

lineMeasurements.emplace_back(LineMeasurement(
str.substr(startRange, lineMetrics[i].length),
{{hitTestMetrics[0].left, hitTestMetrics[0].top}, // origin
{width, lineMetrics[i].height}},
0.0f, // TODO descender
0.0f, // TODO: capHeight
0.0f, // TODO ascender
0.0f // TODO: xHeight
));

startRange += lineMetrics[i].length;
}
}

return lineMeasurements;
}

std::shared_ptr<void> TextLayoutManager::getHostTextStorage(
const AttributedString &attributedString,
const ParagraphAttributes &paragraphAttributes,
LayoutConstraints layoutConstraints) const {
return nullptr;
}

void *TextLayoutManager::getNativeTextLayoutManager() const {
return (void *)this;
}

winrt::hstring TextLayoutManager::GetTransformedText(const AttributedString &attributedString) {
winrt::hstring result{};
for (const auto &fragment : attributedStringBox.getValue().getFragments()) {
for (const auto &fragment : attributedString.getFragments()) {
result = result +
Microsoft::ReactNative::TransformableText::TransformText(
winrt::hstring{Microsoft::Common::Unicode::Utf8ToUtf16(fragment.string)},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ class TextLayoutManager {
* Measures `attributedStringBox` using native text rendering infrastructure.
*/
TextMeasurement measure(
AttributedStringBox attributedStringBox,
ParagraphAttributes paragraphAttributes,
const AttributedStringBox &attributedStringBox,
const ParagraphAttributes &paragraphAttributes,
const TextLayoutContext &layoutContext,
LayoutConstraints layoutConstraints,
std::shared_ptr<void> /* hostTextStorage */) const;
Expand All @@ -45,12 +45,14 @@ class TextLayoutManager {
* Measures lines of `attributedString` using native text rendering
* infrastructure.
*/
LinesMeasurements measureLines(AttributedString attributedString, ParagraphAttributes paragraphAttributes, Size size)
const;
LinesMeasurements measureLines(
const AttributedString &attributedString,
const ParagraphAttributes &paragraphAttributes,
Size size) const;

std::shared_ptr<void> getHostTextStorage(
AttributedString attributedString,
ParagraphAttributes paragraphAttributes,
const AttributedString &attributedString,
const ParagraphAttributes &paragraphAttributes,
LayoutConstraints layoutConstraints) const;

/**
Expand All @@ -59,7 +61,7 @@ class TextLayoutManager {
*/
TextMeasurement measureCachedSpannableById(
int64_t cacheId,
ParagraphAttributes const &paragraphAttributes,
const ParagraphAttributes &paragraphAttributes,
LayoutConstraints layoutConstraints) const;

/*
Expand All @@ -69,15 +71,20 @@ class TextLayoutManager {
void *getNativeTextLayoutManager() const;

static void GetTextLayout(
AttributedStringBox attributedStringBox,
ParagraphAttributes paragraphAttributes,
const AttributedStringBox &attributedStringBox,
const ParagraphAttributes &paragraphAttributes,
LayoutConstraints layoutConstraints,
winrt::com_ptr<IDWriteTextLayout> &spTextLayout) noexcept;

#pragma endregion

private:
static winrt::hstring GetTransformedText(AttributedStringBox const &attributedStringBox);
static winrt::hstring GetTransformedText(const AttributedString &attributedString);
static void GetTextLayout(
const AttributedString &attributedString,
const ParagraphAttributes &paragraphAttributes,
Size size,
winrt::com_ptr<IDWriteTextLayout> &spTextLayout) noexcept;

ContextContainer::Shared m_contextContainer;
#pragma warning(push)
Expand Down
Loading