Further improve RTL /ActualText handling in CPDF_TextPage Refactor CPDF_TextPage::ProcessMarkedContent() to return a boolean indicating whether marked content text is RTL or preceded by an RTL text object. Then call ReverseTempTextBufs() in its caller to reorder if needed to ensure /ActualText characters are processed in logical forward order. This better aligns the ProcessMarkedContent() behavior with the ProcessTextObjectItems() behavior. Then update FPDFTextEmbedderTest.ActualTextRtl test expectations to match. TAG=agy CONV=117163e4-c12b-43d7-9709-b718d4450d3e Bug: 525087036 Change-Id: Ia87c2ff5f52f056e73abea7b0245999ff0c53131 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/152930 Reviewed-by: Andy Phan <andyphan@chromium.org> Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdftext/cpdf_textpage.cpp b/core/fpdftext/cpdf_textpage.cpp index 50647ac..8b02e87 100644 --- a/core/fpdftext/cpdf_textpage.cpp +++ b/core/fpdftext/cpdf_textpage.cpp
@@ -995,7 +995,7 @@ return MarkedContentState::kDelay; } -void CPDF_TextPage::ProcessMarkedContent(const TransformedTextObject& obj) { +bool CPDF_TextPage::ProcessMarkedContent(const TransformedTextObject& obj) { CPDF_TextObject* const text_obj = obj.text_obj_; const CPDF_ContentMarks* marks = text_obj->GetContentMarks(); const size_t content_marks_count = marks->CountItems(); @@ -1008,10 +1008,14 @@ } } if (actual_text.IsEmpty()) { - return; + return false; } - const bool is_rtl = IsRightToLeft(*text_obj); + const bool is_rtl = + IsRightToLeft(*text_obj) || + (prev_text_obj_ && IsRightToLeft(*prev_text_obj_) && + CFX_BidiString(actual_text, /*auto_order=*/true).OverallDirection() == + CFX_BidiChar::Direction::kRight); CFX_Matrix matrix = text_obj->GetTextMatrix() * obj.form_matrix_; CFX_FloatRect rect = text_obj->GetRect(); float step = 0; @@ -1041,6 +1045,7 @@ CharInfo(CharType::kActualText, CPDF_Font::kInvalidCharCode, wc, text_obj->GetPos(), char_box, matrix, text_obj)); } + return is_rtl; } void CPDF_TextPage::FindPreviousTextObject() { @@ -1100,8 +1105,16 @@ curline_rect_ = text_obj->GetRect(); } + // Save these before ProcessMarkedContent() or ProcessTextObjectItems() + // modifies the containers. + const size_t orig_char_list_index = temp_char_list_.size(); + const size_t orig_buf_index = temp_text_buf_.GetLength(); if (ePreMKC == MarkedContentState::kDelay) { - ProcessMarkedContent(obj); + if (ProcessMarkedContent(obj)) { + // TODO(thestig): It would be nicer if there was a way to avoid doing + // this second reversal. + ReverseTempTextBufs(orig_char_list_index, orig_buf_index); + } prev_text_obj_ = text_obj; prev_matrix_ = form_matrix; continue; @@ -1111,10 +1124,6 @@ prev_matrix_ = form_matrix; const CFX_Matrix matrix = text_obj->GetTextMatrix() * form_matrix; - // Save these before ProcessTextObjectItems() modifies the containers. - const size_t orig_char_list_index = temp_char_list_.size(); - const size_t orig_buf_index = temp_text_buf_.GetLength(); - if (ProcessTextObjectItems(text_obj, form_matrix, matrix)) { ReverseTempTextBufs(orig_char_list_index, orig_buf_index); }
diff --git a/core/fpdftext/cpdf_textpage.h b/core/fpdftext/cpdf_textpage.h index be83cc9..e941a19 100644 --- a/core/fpdftext/cpdf_textpage.h +++ b/core/fpdftext/cpdf_textpage.h
@@ -173,7 +173,11 @@ CPDF_TextObject* text_obj2) const; void CloseTempLine(); MarkedContentState PreMarkedContent(const CPDF_TextObject* text_obj); - void ProcessMarkedContent(const TransformedTextObject& obj); + // Processes `/ActualText` marked content for `obj` and appends character info + // and text to `temp_char_list_` and `temp_text_buf_`. + // Returns true if the caller needs to call ReverseTempTextBufs() because the + // text is RTL, requiring the newly appended character order to be reversed. + bool ProcessMarkedContent(const TransformedTextObject& obj); void FindPreviousTextObject(); void AddCharInfo(wchar_t wc, const CharInfo& info, bool is_rtl); TextOrientation GetTextObjectWritingMode(
diff --git a/fpdfsdk/fpdf_text_embeddertest.cpp b/fpdfsdk/fpdf_text_embeddertest.cpp index f55d823..89db486 100644 --- a/fpdfsdk/fpdf_text_embeddertest.cpp +++ b/fpdfsdk/fpdf_text_embeddertest.cpp
@@ -2564,9 +2564,8 @@ // מים (logical order): 0x05de, 0x05d9, 0x05dd, '\r', '\n', // Literal RTL text followed by RTL /ActualText case: - // TODO(crbug.com/525087036): Should be in logical order. - // םולש (/ActualText): - 0x05dd, 0x05d5, 0x05dc, 0x05e9, + // שלום (/ActualText, logical order): + 0x05e9, 0x05dc, 0x05d5, 0x05dd, // בן (literal text): 0x05d1, 0x05df, '\0'}); static constexpr int kExpectedTextSize = std::size(kExpectedText);