Move CFX_GlyphBitmap creation code into CFX_Face::RenderGlyph()

Instead of calling FreeType code to create a CFX_GlyphBitmap in
CFX_GlyphCache::RenderGlyph(), delegate the work to CFX_Face.
Then many FXFT_ macros go away. As part of simplifying the code to use
FreeType structs directly inside CFX_Face, remove some unsigned int to
int conversions. Then many for-loops in CFX_Face::RenderGlyph() can use
more unsigned values when indexing into arrays.

Bug: pdfium:2037
Change-Id: Ia49f85179da87e7aa15ad1063685cb8513d1307a
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/114790
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Dominik Röttsches <drott@chromium.org>
diff --git a/core/fxge/cfx_face.cpp b/core/fxge/cfx_face.cpp
index 44df5a2..24baa8f 100644
--- a/core/fxge/cfx_face.cpp
+++ b/core/fxge/cfx_face.cpp
@@ -4,11 +4,28 @@
 
 #include "core/fxge/cfx_face.h"
 
+#include <algorithm>
+#include <memory>
 #include <utility>
 
+#include "core/fxge/cfx_font.h"
+#include "core/fxge/cfx_fontmgr.h"
+#include "core/fxge/cfx_gemodule.h"
+#include "core/fxge/cfx_glyphbitmap.h"
+#include "core/fxge/cfx_substfont.h"
+#include "core/fxge/dib/cfx_dibitmap.h"
+#include "core/fxge/dib/fx_dib.h"
 #include "core/fxge/fx_fontencoding.h"
+#include "core/fxge/scoped_font_transform.h"
 #include "third_party/base/check.h"
 #include "third_party/base/numerics/safe_conversions.h"
+#include "third_party/base/numerics/safe_math.h"
+
+namespace {
+
+constexpr int kMaxGlyphDimension = 2048;
+
+}  // namespace
 
 // static
 RetainPtr<CFX_Face> CFX_Face::New(FT_Library library,
@@ -108,6 +125,127 @@
   return {GetRec()->stream->base, GetRec()->stream->size};
 }
 
+std::unique_ptr<CFX_GlyphBitmap> CFX_Face::RenderGlyph(const CFX_Font* pFont,
+                                                       uint32_t glyph_index,
+                                                       bool bFontStyle,
+                                                       const CFX_Matrix& matrix,
+                                                       int dest_width,
+                                                       int anti_alias) {
+  FT_Matrix ft_matrix;
+  ft_matrix.xx = matrix.a / 64 * 65536;
+  ft_matrix.xy = matrix.c / 64 * 65536;
+  ft_matrix.yx = matrix.b / 64 * 65536;
+  ft_matrix.yy = matrix.d / 64 * 65536;
+  bool bUseCJKSubFont = false;
+  const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
+  if (pSubstFont) {
+    bUseCJKSubFont = pSubstFont->m_bSubstCJK && bFontStyle;
+    int angle;
+    if (bUseCJKSubFont) {
+      angle = pSubstFont->m_bItalicCJK ? -15 : 0;
+    } else {
+      angle = pSubstFont->m_ItalicAngle;
+    }
+    if (angle) {
+      int skew = CFX_Font::GetSkewFromAngle(angle);
+      if (pFont->IsVertical()) {
+        ft_matrix.yx += ft_matrix.yy * skew / 100;
+      } else {
+        ft_matrix.xy -= ft_matrix.xx * skew / 100;
+      }
+    }
+    if (pSubstFont->IsBuiltInGenericFont()) {
+      pFont->AdjustMMParams(glyph_index, dest_width,
+                            pFont->GetSubstFont()->m_Weight);
+    }
+  }
+
+  ScopedFontTransform scoped_transform(pdfium::WrapRetain(this), &ft_matrix);
+  int load_flags = FT_LOAD_NO_BITMAP | FT_LOAD_PEDANTIC;
+  if (!IsTtOt()) {
+    load_flags |= FT_LOAD_NO_HINTING;
+  }
+  FXFT_FaceRec* rec = GetRec();
+  int error = FT_Load_Glyph(rec, glyph_index, load_flags);
+  if (error) {
+    // if an error is returned, try to reload glyphs without hinting.
+    if (load_flags & FT_LOAD_NO_HINTING) {
+      return nullptr;
+    }
+
+    load_flags |= FT_LOAD_NO_HINTING;
+    load_flags &= ~FT_LOAD_PEDANTIC;
+    error = FT_Load_Glyph(rec, glyph_index, load_flags);
+    if (error) {
+      return nullptr;
+    }
+  }
+
+  auto* glyph = rec->glyph;
+  int weight;
+  if (bUseCJKSubFont) {
+    weight = pSubstFont->m_WeightCJK;
+  } else {
+    weight = pSubstFont ? pSubstFont->m_Weight : 0;
+  }
+  if (pSubstFont && !pSubstFont->IsBuiltInGenericFont() && weight > 400) {
+    uint32_t index = (weight - 400) / 10;
+    pdfium::base::CheckedNumeric<signed long> level =
+        CFX_Font::GetWeightLevel(pSubstFont->m_Charset, index);
+    if (level.ValueOrDefault(-1) < 0) {
+      return nullptr;
+    }
+
+    level = level *
+            (abs(static_cast<int>(ft_matrix.xx)) +
+             abs(static_cast<int>(ft_matrix.xy))) /
+            36655;
+    FT_Outline_Embolden(&glyph->outline, level.ValueOrDefault(0));
+  }
+  FT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->GetFTLibrary(),
+                          FT_LCD_FILTER_DEFAULT);
+  error = FT_Render_Glyph(glyph, static_cast<FT_Render_Mode>(anti_alias));
+  if (error) {
+    return nullptr;
+  }
+
+  const FT_Bitmap& bitmap = glyph->bitmap;
+  if (bitmap.width > kMaxGlyphDimension || bitmap.rows > kMaxGlyphDimension) {
+    return nullptr;
+  }
+  int dib_width = bitmap.width;
+  auto pGlyphBitmap =
+      std::make_unique<CFX_GlyphBitmap>(glyph->bitmap_left, glyph->bitmap_top);
+  pGlyphBitmap->GetBitmap()->Create(dib_width, bitmap.rows,
+                                    anti_alias == FT_RENDER_MODE_MONO
+                                        ? FXDIB_Format::k1bppMask
+                                        : FXDIB_Format::k8bppMask);
+  int dest_pitch = pGlyphBitmap->GetBitmap()->GetPitch();
+  uint8_t* pDestBuf = pGlyphBitmap->GetBitmap()->GetWritableBuffer().data();
+  const uint8_t* pSrcBuf = bitmap.buffer;
+  if (anti_alias != FT_RENDER_MODE_MONO &&
+      bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
+    unsigned int bytes = anti_alias == FT_RENDER_MODE_LCD ? 3 : 1;
+    for (unsigned int i = 0; i < bitmap.rows; i++) {
+      for (unsigned int n = 0; n < bitmap.width; n++) {
+        uint8_t data =
+            (pSrcBuf[i * bitmap.pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
+        for (unsigned int b = 0; b < bytes; b++) {
+          pDestBuf[i * dest_pitch + n * bytes + b] = data;
+        }
+      }
+    }
+  } else {
+    FXSYS_memset(pDestBuf, 0, dest_pitch * bitmap.rows);
+    int rowbytes = std::min(abs(bitmap.pitch), dest_pitch);
+    for (unsigned int row = 0; row < bitmap.rows; row++) {
+      FXSYS_memcpy(pDestBuf + row * dest_pitch, pSrcBuf + row * bitmap.pitch,
+                   rowbytes);
+    }
+  }
+  return pGlyphBitmap;
+}
+
 bool CFX_Face::SelectCharMap(fxge::FontEncoding encoding) {
   FT_Error error =
       FT_Select_Charmap(GetRec(), static_cast<FT_Encoding>(encoding));
diff --git a/core/fxge/cfx_face.h b/core/fxge/cfx_face.h
index d8f96c0..1c85af1 100644
--- a/core/fxge/cfx_face.h
+++ b/core/fxge/cfx_face.h
@@ -7,6 +7,8 @@
 
 #include <stdint.h>
 
+#include <memory>
+
 #include "build/build_config.h"
 #include "core/fxcrt/bytestring.h"
 #include "core/fxcrt/fx_coordinates.h"
@@ -19,6 +21,9 @@
 enum class FontEncoding : uint32_t;
 }
 
+class CFX_Font;
+class CFX_GlyphBitmap;
+
 class CFX_Face final : public Retainable, public Observable {
  public:
   static RetainPtr<CFX_Face> New(FT_Library library,
@@ -56,6 +61,13 @@
 
   pdfium::span<uint8_t> GetData() const;
 
+  std::unique_ptr<CFX_GlyphBitmap> RenderGlyph(const CFX_Font* pFont,
+                                               uint32_t glyph_index,
+                                               bool bFontStyle,
+                                               const CFX_Matrix& matrix,
+                                               int dest_width,
+                                               int anti_alias);
+
   bool SelectCharMap(fxge::FontEncoding encoding);
 
   FXFT_FaceRec* GetRec() { return m_pRec.get(); }
diff --git a/core/fxge/cfx_glyphcache.cpp b/core/fxge/cfx_glyphcache.cpp
index 076ddbb..a5610c6 100644
--- a/core/fxge/cfx_glyphcache.cpp
+++ b/core/fxge/cfx_glyphcache.cpp
@@ -8,8 +8,6 @@
 
 #include <stdarg.h>
 
-#include <algorithm>
-#include <limits>
 #include <memory>
 #include <utility>
 
@@ -18,15 +16,9 @@
 #include "core/fxcrt/fx_memcpy_wrappers.h"
 #include "core/fxge/cfx_defaultrenderdevice.h"
 #include "core/fxge/cfx_font.h"
-#include "core/fxge/cfx_fontmgr.h"
-#include "core/fxge/cfx_gemodule.h"
 #include "core/fxge/cfx_glyphbitmap.h"
 #include "core/fxge/cfx_path.h"
 #include "core/fxge/cfx_substfont.h"
-#include "core/fxge/dib/cfx_dibitmap.h"
-#include "core/fxge/freetype/fx_freetype.h"
-#include "core/fxge/scoped_font_transform.h"
-#include "third_party/base/numerics/safe_math.h"
 
 #if defined(PDF_USE_SKIA)
 #include "third_party/skia/include/core/SkStream.h"  // nogncheck
@@ -50,8 +42,6 @@
 
 constexpr uint32_t kInvalidGlyphIndex = static_cast<uint32_t>(-1);
 
-constexpr int kMaxGlyphDimension = 2048;
-
 struct UniqueKeyGen {
   void Generate(int count, ...);
 
@@ -123,117 +113,12 @@
     const CFX_Matrix& matrix,
     int dest_width,
     int anti_alias) {
-  if (!GetFaceRec())
+  if (!m_Face) {
     return nullptr;
-
-  FT_Matrix ft_matrix;
-  ft_matrix.xx = matrix.a / 64 * 65536;
-  ft_matrix.xy = matrix.c / 64 * 65536;
-  ft_matrix.yx = matrix.b / 64 * 65536;
-  ft_matrix.yy = matrix.d / 64 * 65536;
-  bool bUseCJKSubFont = false;
-  const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
-  if (pSubstFont) {
-    bUseCJKSubFont = pSubstFont->m_bSubstCJK && bFontStyle;
-    int angle;
-    if (bUseCJKSubFont)
-      angle = pSubstFont->m_bItalicCJK ? -15 : 0;
-    else
-      angle = pSubstFont->m_ItalicAngle;
-    if (angle) {
-      int skew = CFX_Font::GetSkewFromAngle(angle);
-      if (pFont->IsVertical())
-        ft_matrix.yx += ft_matrix.yy * skew / 100;
-      else
-        ft_matrix.xy -= ft_matrix.xx * skew / 100;
-    }
-    if (pSubstFont->IsBuiltInGenericFont()) {
-      pFont->AdjustMMParams(glyph_index, dest_width,
-                            pFont->GetSubstFont()->m_Weight);
-    }
   }
 
-  ScopedFontTransform scoped_transform(GetFace(), &ft_matrix);
-  int load_flags = FT_LOAD_NO_BITMAP | FT_LOAD_PEDANTIC;
-  if (!GetFace()->IsTtOt()) {
-    load_flags |= FT_LOAD_NO_HINTING;
-  }
-  int error = FT_Load_Glyph(GetFaceRec(), glyph_index, load_flags);
-  if (error) {
-    // if an error is returned, try to reload glyphs without hinting.
-    if (load_flags & FT_LOAD_NO_HINTING)
-      return nullptr;
-
-    load_flags |= FT_LOAD_NO_HINTING;
-    load_flags &= ~FT_LOAD_PEDANTIC;
-    error = FT_Load_Glyph(GetFaceRec(), glyph_index, load_flags);
-    if (error)
-      return nullptr;
-  }
-
-  int weight;
-  if (bUseCJKSubFont)
-    weight = pSubstFont->m_WeightCJK;
-  else
-    weight = pSubstFont ? pSubstFont->m_Weight : 0;
-  if (pSubstFont && !pSubstFont->IsBuiltInGenericFont() && weight > 400) {
-    uint32_t index = (weight - 400) / 10;
-    pdfium::base::CheckedNumeric<signed long> level =
-        CFX_Font::GetWeightLevel(pSubstFont->m_Charset, index);
-    if (level.ValueOrDefault(-1) < 0)
-      return nullptr;
-
-    level = level *
-            (abs(static_cast<int>(ft_matrix.xx)) +
-             abs(static_cast<int>(ft_matrix.xy))) /
-            36655;
-    FT_Outline_Embolden(FXFT_Get_Glyph_Outline(GetFaceRec()),
-                        level.ValueOrDefault(0));
-  }
-  FT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->GetFTLibrary(),
-                          FT_LCD_FILTER_DEFAULT);
-  error = FXFT_Render_Glyph(GetFaceRec(), anti_alias);
-  if (error)
-    return nullptr;
-
-  int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(GetFaceRec()));
-  int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(GetFaceRec()));
-  if (bmwidth > kMaxGlyphDimension || bmheight > kMaxGlyphDimension)
-    return nullptr;
-  int dib_width = bmwidth;
-  auto pGlyphBitmap =
-      std::make_unique<CFX_GlyphBitmap>(FXFT_Get_Glyph_BitmapLeft(GetFaceRec()),
-                                        FXFT_Get_Glyph_BitmapTop(GetFaceRec()));
-  pGlyphBitmap->GetBitmap()->Create(dib_width, bmheight,
-                                    anti_alias == FT_RENDER_MODE_MONO
-                                        ? FXDIB_Format::k1bppMask
-                                        : FXDIB_Format::k8bppMask);
-  int dest_pitch = pGlyphBitmap->GetBitmap()->GetPitch();
-  int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(GetFaceRec()));
-  uint8_t* pDestBuf = pGlyphBitmap->GetBitmap()->GetWritableBuffer().data();
-  uint8_t* pSrcBuf = static_cast<uint8_t*>(
-      FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(GetFaceRec())));
-  if (anti_alias != FT_RENDER_MODE_MONO &&
-      FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(GetFaceRec())) ==
-          FT_PIXEL_MODE_MONO) {
-    int bytes = anti_alias == FT_RENDER_MODE_LCD ? 3 : 1;
-    for (int i = 0; i < bmheight; i++) {
-      for (int n = 0; n < bmwidth; n++) {
-        uint8_t data =
-            (pSrcBuf[i * src_pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
-        for (int b = 0; b < bytes; b++)
-          pDestBuf[i * dest_pitch + n * bytes + b] = data;
-      }
-    }
-  } else {
-    FXSYS_memset(pDestBuf, 0, dest_pitch * bmheight);
-    int rowbytes = std::min(abs(src_pitch), dest_pitch);
-    for (int row = 0; row < bmheight; row++) {
-      FXSYS_memcpy(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch,
-                   rowbytes);
-    }
-  }
-  return pGlyphBitmap;
+  return m_Face->RenderGlyph(pFont, glyph_index, bFontStyle, matrix, dest_width,
+                             anti_alias);
 }
 
 const CFX_Path* CFX_GlyphCache::LoadGlyphPath(const CFX_Font* pFont,
diff --git a/core/fxge/freetype/fx_freetype.h b/core/fxge/freetype/fx_freetype.h
index afd6604..4bf4b68 100644
--- a/core/fxge/freetype/fx_freetype.h
+++ b/core/fxge/freetype/fx_freetype.h
@@ -53,9 +53,6 @@
   std::unique_ptr<FT_MM_Var, FXFTMMVarDeleter> const variation_desc_;
 };
 
-#define FXFT_Render_Glyph(face, mode) \
-  FT_Render_Glyph((face)->glyph, static_cast<enum FT_Render_Mode_>(mode))
-
 #define FXFT_Get_Glyph_HoriBearingX(face) (face)->glyph->metrics.horiBearingX
 #define FXFT_Get_Glyph_HoriBearingY(face) (face)->glyph->metrics.horiBearingY
 #define FXFT_Get_Glyph_Width(face) (face)->glyph->metrics.width
@@ -65,14 +62,6 @@
 #define FXFT_Get_Charmap_EncodingID(charmap) (charmap)->encoding_id
 #define FXFT_Get_Glyph_HoriAdvance(face) (face)->glyph->metrics.horiAdvance
 #define FXFT_Get_Glyph_Outline(face) &((face)->glyph->outline)
-#define FXFT_Get_Glyph_Bitmap(face) (face)->glyph->bitmap
-#define FXFT_Get_Bitmap_Width(bitmap) (bitmap).width
-#define FXFT_Get_Bitmap_Rows(bitmap) (bitmap).rows
-#define FXFT_Get_Bitmap_PixelMode(bitmap) (bitmap).pixel_mode
-#define FXFT_Get_Bitmap_Pitch(bitmap) (bitmap).pitch
-#define FXFT_Get_Bitmap_Buffer(bitmap) (bitmap).buffer
-#define FXFT_Get_Glyph_BitmapLeft(face) (face)->glyph->bitmap_left
-#define FXFT_Get_Glyph_BitmapTop(face) (face)->glyph->bitmap_top
 
 int FXFT_unicode_from_adobe_name(const char* glyph_name);
 void FXFT_adobe_name_from_unicode(char* name, wchar_t unicode);