Skip to content

Commit

Permalink
Partial implementation of TextLayoutManager::measureLines (#12930)
Browse files Browse the repository at this point in the history
* Partial implementation of TextLayoutManager::measureLines

* Change files

* format
  • Loading branch information
acoates-ms authored Apr 9, 2024
1 parent effde14 commit 3067b5a
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 44 deletions.
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

0 comments on commit 3067b5a

Please sign in to comment.