Encapsulate more bounding box code in CFX_Face

Add GetCharBBox() and GetGlyphBBox() to CFX_Face. These methods move
existing FreeType calls into CFX_Face.

Bug: pdfium:2037
Change-Id: I05f9b1d90f142f914ff7f35ad748c3db87abbea0
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/114796
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
Reviewed-by: Dominik Röttsches <drott@chromium.org>
diff --git a/core/fpdfapi/font/cpdf_cidfont.cpp b/core/fpdfapi/font/cpdf_cidfont.cpp
index f540505..b0bcfd5 100644
--- a/core/fpdfapi/font/cpdf_cidfont.cpp
+++ b/core/fpdfapi/font/cpdf_cidfont.cpp
@@ -134,16 +134,6 @@
     {8818, 0, 129, 127, 0, 19, 114}, {8819, 0, 129, 127, 0, 218, 108},
 };
 
-// Boundary value to avoid integer overflow when adding 1/64th of the value.
-constexpr int kMaxRectTop = 2114445437;
-
-int FTPosToCBoxInt(FT_Pos pos) {
-  // Boundary values to avoid integer overflow when multiplied by 1000.
-  constexpr FT_Pos kMinCBox = -2147483;
-  constexpr FT_Pos kMaxCBox = 2147483;
-  return static_cast<int>(std::clamp(pos, kMinCBox, kMaxCBox));
-}
-
 #if !BUILDFLAG(IS_WIN)
 
 bool IsValidEmbeddedCharcodeFromUnicodeCharset(CIDSet charset) {
@@ -528,45 +518,7 @@
   int glyph_index = GlyphFromCharCode(charcode, &bVert);
   RetainPtr<CFX_Face> face = m_Font.GetFace();
   if (face) {
-    FXFT_FaceRec* face_rec = face->GetRec();
-    if (face->IsTricky()) {
-      int err = FT_Load_Glyph(face_rec, glyph_index,
-                              FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
-      if (!err) {
-        FT_Glyph glyph;
-        err = FT_Get_Glyph(face_rec->glyph, &glyph);
-        if (!err) {
-          FT_BBox cbox;
-          FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &cbox);
-          const int xMin = FTPosToCBoxInt(cbox.xMin);
-          const int xMax = FTPosToCBoxInt(cbox.xMax);
-          const int yMin = FTPosToCBoxInt(cbox.yMin);
-          const int yMax = FTPosToCBoxInt(cbox.yMax);
-          const int pixel_size_x = face_rec->size->metrics.x_ppem;
-          const int pixel_size_y = face_rec->size->metrics.y_ppem;
-          if (pixel_size_x == 0 || pixel_size_y == 0) {
-            rect = FX_RECT(xMin, yMax, xMax, yMin);
-          } else {
-            rect =
-                FX_RECT(xMin * 1000 / pixel_size_x, yMax * 1000 / pixel_size_y,
-                        xMax * 1000 / pixel_size_x, yMin * 1000 / pixel_size_y);
-          }
-          rect.top = std::min(rect.top, static_cast<int>(face->GetAscender()));
-          rect.bottom =
-              std::max(rect.bottom, static_cast<int>(face->GetDescender()));
-          FT_Done_Glyph(glyph);
-        }
-      }
-    } else {
-      int err = FT_Load_Glyph(face_rec, glyph_index, FT_LOAD_NO_SCALE);
-      if (err == 0) {
-        rect = GetCharBBoxForFace(face);
-        if (rect.top <= kMaxRectTop)
-          rect.top += rect.top / 64;
-        else
-          rect.top = std::numeric_limits<int>::max();
-      }
-    }
+    rect = face->GetCharBBox(charcode, glyph_index);
   }
   if (!m_pFontFile && m_Charset == CIDSET_JAPAN1) {
     uint16_t cid = CIDFromCharCode(charcode);
diff --git a/core/fpdfapi/font/cpdf_font.cpp b/core/fpdfapi/font/cpdf_font.cpp
index 7432814..66e385d 100644
--- a/core/fpdfapi/font/cpdf_font.cpp
+++ b/core/fpdfapi/font/cpdf_font.cpp
@@ -31,10 +31,8 @@
 #include "core/fxcrt/stl_util.h"
 #include "core/fxge/cfx_fontmapper.h"
 #include "core/fxge/cfx_substfont.h"
-#include "core/fxge/freetype/fx_freetype.h"
 #include "core/fxge/fx_font.h"
 #include "third_party/base/check.h"
-#include "third_party/base/numerics/clamped_math.h"
 
 namespace {
 
@@ -407,18 +405,6 @@
 }
 
 // static
-FX_RECT CPDF_Font::GetCharBBoxForFace(const RetainPtr<CFX_Face>& face) {
-  FXFT_FaceRec* rec = face->GetRec();
-  pdfium::base::ClampedNumeric<FT_Pos> left = FXFT_Get_Glyph_HoriBearingX(rec);
-  pdfium::base::ClampedNumeric<FT_Pos> top = FXFT_Get_Glyph_HoriBearingY(rec);
-  const uint16_t upem = face->GetUnitsPerEm();
-  return FX_RECT(NormalizeFontMetric(left, upem),
-                 NormalizeFontMetric(top, upem),
-                 NormalizeFontMetric(left + FXFT_Get_Glyph_Width(rec), upem),
-                 NormalizeFontMetric(top - FXFT_Get_Glyph_Height(rec), upem));
-}
-
-// static
 bool CPDF_Font::UseTTCharmap(const RetainPtr<CFX_Face>& face,
                              int platform_id,
                              int encoding_id) {
diff --git a/core/fpdfapi/font/cpdf_font.h b/core/fpdfapi/font/cpdf_font.h
index 84e45a9..af0a82b 100644
--- a/core/fpdfapi/font/cpdf_font.h
+++ b/core/fpdfapi/font/cpdf_font.h
@@ -22,7 +22,6 @@
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/unowned_ptr.h"
 #include "core/fxge/cfx_font.h"
-#include "core/fxge/freetype/fx_freetype.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
 class CFX_DIBitmap;
@@ -139,8 +138,6 @@
   CPDF_Font(CPDF_Document* pDocument, RetainPtr<CPDF_Dictionary> pFontDict);
   ~CPDF_Font() override;
 
-  static FX_RECT GetCharBBoxForFace(const RetainPtr<CFX_Face>& face);
-
   // Commonly used wrappers for UseTTCharmap().
   static bool UseTTCharmapMSUnicode(const RetainPtr<CFX_Face>& face) {
     return UseTTCharmap(face, 3, 1);
diff --git a/core/fpdfapi/font/cpdf_simplefont.cpp b/core/fpdfapi/font/cpdf_simplefont.cpp
index b411257..d740302 100644
--- a/core/fpdfapi/font/cpdf_simplefont.cpp
+++ b/core/fpdfapi/font/cpdf_simplefont.cpp
@@ -88,7 +88,7 @@
   if (err)
     return;
 
-  m_CharBBox[charcode] = GetCharBBoxForFace(face);
+  m_CharBBox[charcode] = face->GetGlyphBBox();
 
   if (m_bUseFontWidth) {
     int TT_Width = NormalizeFontMetric(FXFT_Get_Glyph_HoriAdvance(face_rec),
diff --git a/core/fxge/cfx_face.cpp b/core/fxge/cfx_face.cpp
index 265fa1b..2a565fa 100644
--- a/core/fxge/cfx_face.cpp
+++ b/core/fxge/cfx_face.cpp
@@ -18,11 +18,13 @@
 #include "core/fxge/cfx_substfont.h"
 #include "core/fxge/dib/cfx_dibitmap.h"
 #include "core/fxge/dib/fx_dib.h"
+#include "core/fxge/fx_font.h"
 #include "core/fxge/fx_fontencoding.h"
 #include "core/fxge/scoped_font_transform.h"
 #include "third_party/base/check.h"
 #include "third_party/base/check_op.h"
 #include "third_party/base/notreached.h"
+#include "third_party/base/numerics/clamped_math.h"
 #include "third_party/base/numerics/safe_conversions.h"
 #include "third_party/base/numerics/safe_math.h"
 
@@ -42,6 +44,9 @@
 
 constexpr int kMaxGlyphDimension = 2048;
 
+// Boundary value to avoid integer overflow when adding 1/64th of the value.
+constexpr int kMaxRectTop = 2114445437;
+
 constexpr uint8_t kWeightPow[] = {
     0,   6,   12,  14,  16,  18,  22,  24,  28,  30,  32,  34,  36,  38,  40,
     42,  44,  46,  48,  50,  52,  54,  56,  58,  60,  62,  64,  66,  68,  70,
@@ -104,6 +109,13 @@
   return kAngleSkew[-angle];
 }
 
+int FTPosToCBoxInt(FT_Pos pos) {
+  // Boundary values to avoid integer overflow when multiplied by 1000.
+  constexpr FT_Pos kMinCBox = -2147483;
+  constexpr FT_Pos kMaxCBox = 2147483;
+  return static_cast<int>(std::clamp(pos, kMinCBox, kMaxCBox));
+}
+
 void Outline_CheckEmptyContour(OUTLINE_PARAMS* param) {
   size_t size;
   {
@@ -652,6 +664,61 @@
   return FT_Get_Name_Index(GetRec(), name);
 }
 
+FX_RECT CFX_Face::GetCharBBox(uint32_t code, int glyph_index) {
+  FX_RECT rect;
+  FXFT_FaceRec* rec = GetRec();
+  if (IsTricky()) {
+    int err =
+        FT_Load_Glyph(rec, glyph_index, FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
+    if (!err) {
+      FT_Glyph glyph;
+      err = FT_Get_Glyph(rec->glyph, &glyph);
+      if (!err) {
+        FT_BBox cbox;
+        FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &cbox);
+        const int xMin = FTPosToCBoxInt(cbox.xMin);
+        const int xMax = FTPosToCBoxInt(cbox.xMax);
+        const int yMin = FTPosToCBoxInt(cbox.yMin);
+        const int yMax = FTPosToCBoxInt(cbox.yMax);
+        const int pixel_size_x = rec->size->metrics.x_ppem;
+        const int pixel_size_y = rec->size->metrics.y_ppem;
+        if (pixel_size_x == 0 || pixel_size_y == 0) {
+          rect = FX_RECT(xMin, yMax, xMax, yMin);
+        } else {
+          rect =
+              FX_RECT(xMin * 1000 / pixel_size_x, yMax * 1000 / pixel_size_y,
+                      xMax * 1000 / pixel_size_x, yMin * 1000 / pixel_size_y);
+        }
+        rect.top = std::min(rect.top, static_cast<int>(GetAscender()));
+        rect.bottom = std::max(rect.bottom, static_cast<int>(GetDescender()));
+        FT_Done_Glyph(glyph);
+      }
+    }
+  } else {
+    int err = FT_Load_Glyph(rec, glyph_index, FT_LOAD_NO_SCALE);
+    if (err == 0) {
+      rect = GetGlyphBBox();
+      if (rect.top <= kMaxRectTop) {
+        rect.top += rect.top / 64;
+      } else {
+        rect.top = std::numeric_limits<int>::max();
+      }
+    }
+  }
+  return rect;
+}
+
+FX_RECT CFX_Face::GetGlyphBBox() const {
+  const auto* glyph = GetRec()->glyph;
+  pdfium::base::ClampedNumeric<FT_Pos> left = glyph->metrics.horiBearingX;
+  pdfium::base::ClampedNumeric<FT_Pos> top = glyph->metrics.horiBearingY;
+  const uint16_t upem = GetUnitsPerEm();
+  return FX_RECT(NormalizeFontMetric(left, upem),
+                 NormalizeFontMetric(top, upem),
+                 NormalizeFontMetric(left + glyph->metrics.width, upem),
+                 NormalizeFontMetric(top - glyph->metrics.height, upem));
+}
+
 std::vector<CFX_Face::CharCodeAndIndex> CFX_Face::GetCharCodesAndIndices(
     char32_t max_char) {
   CharCodeAndIndex char_code_and_index;
diff --git a/core/fxge/cfx_face.h b/core/fxge/cfx_face.h
index 944d731..bc3d71f 100644
--- a/core/fxge/cfx_face.h
+++ b/core/fxge/cfx_face.h
@@ -84,6 +84,8 @@
   absl::optional<std::array<uint8_t, 2>> GetOs2Panose();
 
   int GetGlyphCount() const;
+  // TODO(crbug.com/pdfium/2037): Can this method be private?
+  FX_RECT GetGlyphBBox() const;
   std::unique_ptr<CFX_GlyphBitmap> RenderGlyph(const CFX_Font* pFont,
                                                uint32_t glyph_index,
                                                bool bFontStyle,
@@ -102,6 +104,8 @@
   int GetCharIndex(uint32_t code);
   int GetNameIndex(const char* name);
 
+  FX_RECT GetCharBBox(uint32_t code, int glyph_index);
+
   std::vector<CharCodeAndIndex> GetCharCodesAndIndices(char32_t max_char);
 
   CharMap GetCurrentCharMap() const;