Redo FPDFText_GetLooseCharBox() top/bottom calculation

Undo the fix in https://pdfium-review.googlesource.com/128730, and
instead calculate the char box's top/bottom values using the font's
bounding box values. This makes the loose char box looser for
diacritics.

Bug: 42270568, 395640955
Change-Id: Ie2f7be699331f609dfab60104daf5c369cc94dff
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/128770
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
diff --git a/core/fpdftext/cpdf_textpage.cpp b/core/fpdftext/cpdf_textpage.cpp
index 4e63f15..47cff23 100644
--- a/core/fpdftext/cpdf_textpage.cpp
+++ b/core/fpdftext/cpdf_textpage.cpp
@@ -290,23 +290,22 @@
       return char_box;
     }
 
-    int ascent = charinfo.text_object()->GetFont()->GetTypeAscent();
-    int descent = charinfo.text_object()->GetFont()->GetTypeDescent();
-    if (ascent != descent) {
+    FX_RECT font_bbox = charinfo.text_object()->GetFont()->GetFontBBox();
+    if (font_bbox.Height() != 0) {
+      // Compute `left` and `right` based on the individual character's `width`.
       float width = charinfo.text_object()->GetCharWidth(charinfo.char_code());
-      float font_scale = font_size / (ascent - descent);
-
       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;
+
+      // Compute `bottom` and `top` based on the font bounding box. This allows
+      // the bounds to include diacritics, whereas using the ascent / descent
+      // values will not.
+      float bottom = font_bbox.bottom * font_size / 1000;
+      float top = font_bbox.top * font_size / 1000;
       CFX_FloatRect char_box(left, bottom, right, top);
-      char_box = charinfo.matrix().TransformRect(char_box);
-      char_box.Union(charinfo.char_box());
-      return char_box;
+      return charinfo.matrix().TransformRect(char_box);
     }
   }
 
diff --git a/fpdfsdk/fpdf_text_embeddertest.cpp b/fpdfsdk/fpdf_text_embeddertest.cpp
index b54bab7..e20360f 100644
--- a/fpdfsdk/fpdf_text_embeddertest.cpp
+++ b/fpdfsdk/fpdf_text_embeddertest.cpp
@@ -192,8 +192,8 @@
   EXPECT_TRUE(FPDFText_GetLooseCharBox(textpage.get(), 4, &rect));
   EXPECT_FLOAT_EQ(40.664001f, rect.left);
   EXPECT_FLOAT_EQ(46.664001f, rect.right);
-  EXPECT_FLOAT_EQ(47.667271f, rect.bottom);
-  EXPECT_FLOAT_EQ(59.667271f, rect.top);
+  EXPECT_FLOAT_EQ(46.375999f, rect.bottom);
+  EXPECT_FLOAT_EQ(61.771999f, rect.top);
 
   double x = 0.0;
   double y = 0.0;
@@ -1769,7 +1769,7 @@
   static constexpr double kExpectedCharWidth = 8.460;
   static constexpr double kExpectedCharHeight = 6.600;
   static constexpr float kExpectedLooseCharWidth = 8.664f;
-  static constexpr float kExpectedLooseCharHeight = 10.0f;
+  static constexpr float kExpectedLooseCharHeight = 12.82999f;
 
   ASSERT_TRUE(OpenDocument("font_matrix.pdf"));
   ScopedEmbedderTestPage page = LoadScopedPage(0);
@@ -1811,7 +1811,7 @@
   EXPECT_FLOAT_EQ(kExpectedLooseCharHeight, rect.top - rect.bottom);
   ASSERT_TRUE(FPDFText_GetLooseCharBox(text_page.get(), 4, &rect));
   EXPECT_FLOAT_EQ(kExpectedLooseCharWidth, rect.right - rect.left);
-  EXPECT_FLOAT_EQ(kExpectedLooseCharHeight, rect.top - rect.bottom);
+  EXPECT_NEAR(kExpectedLooseCharHeight, rect.top - rect.bottom, 0.00001);
   ASSERT_TRUE(FPDFText_GetLooseCharBox(text_page.get(), 8, &rect));
   EXPECT_FLOAT_EQ(kExpectedLooseCharWidth, rect.right - rect.left);
   EXPECT_NEAR(kExpectedLooseCharHeight, rect.top - rect.bottom, 0.00001);
@@ -1866,7 +1866,7 @@
   EXPECT_NEAR(10.055, top - bottom, 0.001);
 
   // Check the loose character box size.
-  static constexpr float kExpectedLooseCharDimension = 14.612f;
+  static constexpr float kExpectedLooseCharDimension = 17.013f;
   FS_RECTF rect;
   ASSERT_TRUE(FPDFText_GetLooseCharBox(
       text_page.get(), GetRotatedTextFirstCharIndexForQuadrant(0), &rect));
@@ -1936,7 +1936,7 @@
 
   // Check the loose character box size.
   static constexpr float kExpectedLooseCharWidth = 8.664f;
-  static constexpr float kExpectedLooseCharHeight = 12.0f;
+  static constexpr float kExpectedLooseCharHeight = 15.396f;
   FS_RECTF rect;
   ASSERT_TRUE(FPDFText_GetLooseCharBox(
       text_page.get(), GetRotatedText90FirstCharIndexForQuadrant(0), &rect));
@@ -1979,8 +1979,8 @@
   FS_RECTF rect;
   ASSERT_TRUE(FPDFText_GetLooseCharBox(text_page.get(), 0, &rect));
   EXPECT_NEAR(7.824f, rect.right - rect.left, 0.001f);
-  EXPECT_NEAR(12.988f, rect.top - rect.bottom, 0.001f);
-  EXPECT_NEAR(750.238f, rect.top, 0.001f);
+  EXPECT_NEAR(15.912f, rect.top - rect.bottom, 0.001f);
+  EXPECT_NEAR(752.422f, rect.top, 0.001f);
 
   EXPECT_EQ(u'Ă', FPDFText_GetUnicode(text_page.get(), 2));
 
@@ -1992,8 +1992,8 @@
 
   ASSERT_TRUE(FPDFText_GetLooseCharBox(text_page.get(), 2, &rect));
   EXPECT_NEAR(7.824f, rect.right - rect.left, 0.001f);
-  EXPECT_NEAR(13.24f, rect.top - rect.bottom, 0.001f);
-  EXPECT_NEAR(750.49f, rect.top, 0.001f);
+  EXPECT_NEAR(15.912f, rect.top - rect.bottom, 0.001f);
+  EXPECT_NEAR(752.422f, rect.top, 0.001f);
 }
 
 TEST_F(FPDFTextEmbedderTest, SmallType3Glyph) {