Skip to content

Commit c000be0

Browse files
Copilotacoates-ms
andcommitted
Implement proper Natural writing direction detection and improve WritingDirection handling
Co-authored-by: acoates-ms <30809111+acoates-ms@users.noreply.github.com>
1 parent a29b115 commit c000be0

2 files changed

Lines changed: 54 additions & 3 deletions

File tree

vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/WindowsTextLayoutManager.cpp

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,20 @@ void WindowsTextLayoutManager::GetTextLayout(
159159
winrt::check_hresult(spTextFormat->SetTextAlignment(alignment));
160160

161161
// Set reading direction based on baseWritingDirection
162-
if (outerFragment.textAttributes.baseWritingDirection &&
163-
*outerFragment.textAttributes.baseWritingDirection == facebook::react::WritingDirection::RightToLeft) {
164-
winrt::check_hresult(spTextFormat->SetReadingDirection(DWRITE_READING_DIRECTION_RIGHT_TO_LEFT));
162+
if (outerFragment.textAttributes.baseWritingDirection) {
163+
DWRITE_READING_DIRECTION readingDirection = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
164+
165+
// Handle explicit RightToLeft
166+
if (*outerFragment.textAttributes.baseWritingDirection == facebook::react::WritingDirection::RightToLeft) {
167+
readingDirection = DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
168+
}
169+
// For all other cases (including Natural), use context-aware detection
170+
else {
171+
// For Natural direction, detect from text content
172+
readingDirection = GetNaturalReadingDirection(attributedStringBox);
173+
}
174+
175+
winrt::check_hresult(spTextFormat->SetReadingDirection(readingDirection));
165176
}
166177

167178
// Get text with Object Replacement Characters for attachments
@@ -553,4 +564,43 @@ winrt::hstring WindowsTextLayoutManager::GetTransformedText(const AttributedStri
553564
return result;
554565
}
555566

567+
DWRITE_READING_DIRECTION WindowsTextLayoutManager::GetNaturalReadingDirection(const AttributedStringBox &attributedStringBox) noexcept {
568+
const auto &attributedString = attributedStringBox.getValue();
569+
570+
// Analyze the text content to determine the natural reading direction
571+
// Look for the first strong directional character
572+
for (const auto &fragment : attributedString.getFragments()) {
573+
if (!fragment.isAttachment()) {
574+
auto fragmentText = Microsoft::Common::Unicode::Utf8ToUtf16(fragment.string);
575+
576+
for (wchar_t ch : fragmentText) {
577+
// Check for strong RTL characters (Arabic, Hebrew ranges)
578+
if ((ch >= 0x0590 && ch <= 0x05FF) || // Hebrew
579+
(ch >= 0x0600 && ch <= 0x06FF) || // Arabic
580+
(ch >= 0x0750 && ch <= 0x077F) || // Arabic Supplement
581+
(ch >= 0x08A0 && ch <= 0x08FF) || // Arabic Extended-A
582+
(ch >= 0xFB1D && ch <= 0xFB4F) || // Hebrew Presentation Forms
583+
(ch >= 0xFB50 && ch <= 0xFDFF) || // Arabic Presentation Forms-A
584+
(ch >= 0xFE70 && ch <= 0xFEFF)) { // Arabic Presentation Forms-B
585+
return DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
586+
}
587+
// Check for strong LTR characters (Latin, Cyrillic, etc.)
588+
else if ((ch >= 0x0041 && ch <= 0x005A) || // Latin uppercase
589+
(ch >= 0x0061 && ch <= 0x007A) || // Latin lowercase
590+
(ch >= 0x00C0 && ch <= 0x00D6) || // Latin extended
591+
(ch >= 0x00D8 && ch <= 0x00F6) || // Latin extended
592+
(ch >= 0x00F8 && ch <= 0x00FF) || // Latin extended
593+
(ch >= 0x0100 && ch <= 0x017F) || // Latin Extended-A
594+
(ch >= 0x0180 && ch <= 0x024F) || // Latin Extended-B
595+
(ch >= 0x0400 && ch <= 0x04FF)) { // Cyrillic
596+
return DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
597+
}
598+
}
599+
}
600+
}
601+
602+
// If no strong directional characters found, use system default (LTR)
603+
return DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
604+
}
605+
556606
} // namespace facebook::react

vnext/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/WindowsTextLayoutManager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class WindowsTextLayoutManager : public TextLayoutManager {
5858

5959
private:
6060
static winrt::hstring GetTransformedText(const AttributedStringBox &attributedStringBox);
61+
static DWRITE_READING_DIRECTION GetNaturalReadingDirection(const AttributedStringBox &attributedStringBox) noexcept;
6162
static void GetTextLayout(
6263
const AttributedStringBox &attributedStringBox,
6364
const ParagraphAttributes &paragraphAttributes,

0 commit comments

Comments
 (0)