Fix FPDFText_GetLooseCharBox() to handle rotation Change the cpdf_textpage.cpp code that implements the character box calculations used by FPDFText_GetLooseCharBox() to properly handle the transformation matrix. Then FPDFText_GetLooseCharBox() will no longer return dimensions of 0 when matrix.a is 0, and it will no longer return negative dimensions when the text is flipped. Bug: 42270642 Change-Id: Iab85cbf64cd1f8266ab20b63ad35bddefd05733c Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/127995 Commit-Queue: Lei Zhang <thestig@chromium.org> Reviewed-by: Tom Sepez <tsepez@chromium.org> Reviewed-by: Thomas Sepez <tsepez@google.com>
diff --git a/core/fpdftext/cpdf_textpage.cpp b/core/fpdftext/cpdf_textpage.cpp index 518b744..6d982d4 100644 --- a/core/fpdftext/cpdf_textpage.cpp +++ b/core/fpdftext/cpdf_textpage.cpp
@@ -290,15 +290,18 @@ int ascent = charinfo.text_object()->GetFont()->GetTypeAscent(); int descent = charinfo.text_object()->GetFont()->GetTypeDescent(); if (ascent != descent) { - float width = charinfo.matrix().a * - charinfo.text_object()->GetCharWidth(charinfo.char_code()); - float font_scale = charinfo.matrix().a * font_size / (ascent - descent); + float width = charinfo.text_object()->GetCharWidth(charinfo.char_code()); + float font_scale = font_size / (ascent - descent); - float left = charinfo.origin().x; - float right = charinfo.origin().x + (is_vert_writing ? -width : width); - float bottom = charinfo.origin().y + descent * font_scale; - float top = charinfo.origin().y + ascent * font_scale; - return CFX_FloatRect(left, bottom, right, top); + CFX_Matrix inverse_matrix = charinfo.matrix().GetInverse(); + CFX_PointF original_origin = inverse_matrix.Transform(charinfo.origin()); + + float left = original_origin.x; + float right = original_origin.x + (is_vert_writing ? -width : width); + float bottom = original_origin.y + descent * font_scale; + float top = original_origin.y + ascent * font_scale; + CFX_FloatRect char_box(left, bottom, right, top); + return charinfo.matrix().TransformRect(char_box); } }
diff --git a/fpdfsdk/fpdf_text_embeddertest.cpp b/fpdfsdk/fpdf_text_embeddertest.cpp index fde1b18..92ac221 100644 --- a/fpdfsdk/fpdf_text_embeddertest.cpp +++ b/fpdfsdk/fpdf_text_embeddertest.cpp
@@ -1736,7 +1736,7 @@ static constexpr double kExpectedCharWidth = 8.460; static constexpr double kExpectedCharHeight = 6.600; static constexpr float kExpectedLooseCharWidth = 8.664f; - static constexpr float kExpectedLooseCharHeight = 12.0f; + static constexpr float kExpectedLooseCharHeight = 10.0f; ASSERT_TRUE(OpenDocument("font_matrix.pdf")); ScopedEmbedderTestPage page = LoadScopedPage(0); @@ -1833,25 +1833,24 @@ EXPECT_NEAR(10.055, top - bottom, 0.001); // Check the loose character box size. - // TODO(crbug.com/42270642): Sizes should be bigger than the - // FPDFText_GetCharBox() sizes, and certainly not negative. + static constexpr float kExpectedLooseCharDimension = 14.612f; FS_RECTF rect; ASSERT_TRUE(FPDFText_GetLooseCharBox( text_page.get(), GetRotatedTextFirstCharIndexForQuadrant(0), &rect)); - EXPECT_NEAR(6.126f, rect.right - rect.left, 0.001f); - EXPECT_NEAR(8.485f, rect.top - rect.bottom, 0.001f); + EXPECT_NEAR(kExpectedLooseCharDimension, rect.right - rect.left, 0.001f); + EXPECT_NEAR(kExpectedLooseCharDimension, rect.top - rect.bottom, 0.001f); ASSERT_TRUE(FPDFText_GetLooseCharBox( text_page.get(), GetRotatedTextFirstCharIndexForQuadrant(1), &rect)); - EXPECT_NEAR(-6.126f, rect.right - rect.left, 0.001f); - EXPECT_NEAR(-8.485f, rect.top - rect.bottom, 0.001f); + EXPECT_NEAR(kExpectedLooseCharDimension, rect.right - rect.left, 0.001f); + EXPECT_NEAR(kExpectedLooseCharDimension, rect.top - rect.bottom, 0.001f); ASSERT_TRUE(FPDFText_GetLooseCharBox( text_page.get(), GetRotatedTextFirstCharIndexForQuadrant(2), &rect)); - EXPECT_NEAR(-6.126f, rect.right - rect.left, 0.001f); - EXPECT_NEAR(-8.485f, rect.top - rect.bottom, 0.001f); + EXPECT_NEAR(kExpectedLooseCharDimension, rect.right - rect.left, 0.001f); + EXPECT_NEAR(kExpectedLooseCharDimension, rect.top - rect.bottom, 0.001f); ASSERT_TRUE(FPDFText_GetLooseCharBox( text_page.get(), GetRotatedTextFirstCharIndexForQuadrant(3), &rect)); - EXPECT_NEAR(6.126f, rect.right - rect.left, 0.001f); - EXPECT_NEAR(8.485f, rect.top - rect.bottom, 0.001f); + EXPECT_NEAR(kExpectedLooseCharDimension, rect.right - rect.left, 0.001f); + EXPECT_NEAR(kExpectedLooseCharDimension, rect.top - rect.bottom, 0.001f); } TEST_F(FPDFTextEmbedderTest, CharBoxForRotated90DegreesText) { @@ -1903,25 +1902,25 @@ EXPECT_NEAR(8.604, top - bottom, 0.001); // Check the loose character box size. - // TODO(crbug.com/42270642): Sizes should be bigger than the - // FPDFText_GetCharBox() sizes, and certainly not negative nor zero. + static constexpr float kExpectedLooseCharWidth = 8.664f; + static constexpr float kExpectedLooseCharHeight = 12.0f; FS_RECTF rect; ASSERT_TRUE(FPDFText_GetLooseCharBox( text_page.get(), GetRotatedText90FirstCharIndexForQuadrant(0), &rect)); - EXPECT_NEAR(8.664f, rect.right - rect.left, 0.001f); - EXPECT_NEAR(12.0f, rect.top - rect.bottom, 0.001f); + EXPECT_NEAR(kExpectedLooseCharWidth, rect.right - rect.left, 0.001f); + EXPECT_NEAR(kExpectedLooseCharHeight, rect.top - rect.bottom, 0.001f); ASSERT_TRUE(FPDFText_GetLooseCharBox( text_page.get(), GetRotatedText90FirstCharIndexForQuadrant(1), &rect)); - EXPECT_NEAR(0.0f, rect.right - rect.left, 0.001f); - EXPECT_NEAR(0.0f, rect.top - rect.bottom, 0.001f); + EXPECT_NEAR(kExpectedLooseCharHeight, rect.right - rect.left, 0.001f); + EXPECT_NEAR(kExpectedLooseCharWidth, rect.top - rect.bottom, 0.001f); ASSERT_TRUE(FPDFText_GetLooseCharBox( text_page.get(), GetRotatedText90FirstCharIndexForQuadrant(2), &rect)); - EXPECT_NEAR(-8.664f, rect.right - rect.left, 0.001f); - EXPECT_NEAR(-12.0f, rect.top - rect.bottom, 0.001f); + EXPECT_NEAR(kExpectedLooseCharWidth, rect.right - rect.left, 0.001f); + EXPECT_NEAR(kExpectedLooseCharHeight, rect.top - rect.bottom, 0.001f); ASSERT_TRUE(FPDFText_GetLooseCharBox( text_page.get(), GetRotatedText90FirstCharIndexForQuadrant(3), &rect)); - EXPECT_NEAR(0.0f, rect.right - rect.left, 0.001f); - EXPECT_NEAR(0.0f, rect.top - rect.bottom, 0.001f); + EXPECT_NEAR(kExpectedLooseCharHeight, rect.right - rect.left, 0.001f); + EXPECT_NEAR(kExpectedLooseCharWidth, rect.top - rect.bottom, 0.001f); } TEST_F(FPDFTextEmbedderTest, SmallType3Glyph) {