Move CFX_FaceCache to its own file

Moved ScopedFontTransform from fx_ge_text namespace to fx_font
Moved some arrays used by both CFX_Font and CFX_FaceCache from fx_ge_text to
inside CFX_Font class

Review-Url: https://codereview.chromium.org/2263623002
diff --git a/BUILD.gn b/BUILD.gn
index ec2d55a..0a4df45 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -753,6 +753,7 @@
     "core/fxge/ge/cfx_autofontcache.cpp",
     "core/fxge/ge/cfx_cliprgn.cpp",
     "core/fxge/ge/cfx_cliprgn.h",
+    "core/fxge/ge/cfx_facecache.cpp",
     "core/fxge/ge/cfx_folderfontinfo.cpp",
     "core/fxge/ge/cfx_folderfontinfo.h",
     "core/fxge/ge/cfx_fontcache.cpp",
@@ -773,6 +774,7 @@
     "core/fxge/ge/include/ifx_systemfontinfo.h",
     "core/fxge/ifx_renderdevicedriver.cpp",
     "core/fxge/include/cfx_autofontcache.h",
+    "core/fxge/include/cfx_facecache.h",
     "core/fxge/include/cfx_fontcache.h",
     "core/fxge/include/cfx_fxgedevice.h",
     "core/fxge/include/cfx_gemodule.h",
diff --git a/core/fpdfapi/fpdf_render/fpdf_render_text.cpp b/core/fpdfapi/fpdf_render/fpdf_render_text.cpp
index 549e592..080a757 100644
--- a/core/fpdfapi/fpdf_render/fpdf_render_text.cpp
+++ b/core/fpdfapi/fpdf_render/fpdf_render_text.cpp
@@ -23,6 +23,7 @@
 #include "core/fpdfapi/fpdf_render/include/cpdf_renderoptions.h"
 #include "core/fpdfapi/fpdf_render/include/cpdf_textrenderer.h"
 #include "core/fxge/include/cfx_autofontcache.h"
+#include "core/fxge/include/cfx_facecache.h"
 #include "core/fxge/include/cfx_fontcache.h"
 #include "core/fxge/include/cfx_fxgedevice.h"
 #include "core/fxge/include/cfx_gemodule.h"
diff --git a/core/fxge/apple/fx_apple_platform.cpp b/core/fxge/apple/fx_apple_platform.cpp
index fed24cf..be429e9 100644
--- a/core/fxge/apple/fx_apple_platform.cpp
+++ b/core/fxge/apple/fx_apple_platform.cpp
@@ -17,6 +17,7 @@
 #include "core/fxge/dib/dib_int.h"
 #include "core/fxge/ge/cfx_cliprgn.h"
 #include "core/fxge/ge/fx_text_int.h"
+#include "core/fxge/include/cfx_facecache.h"
 #include "core/fxge/include/cfx_fontcache.h"
 #include "core/fxge/include/cfx_gemodule.h"
 #include "core/fxge/include/cfx_renderdevice.h"
diff --git a/core/fxge/ge/cfx_facecache.cpp b/core/fxge/ge/cfx_facecache.cpp
new file mode 100644
index 0000000..7c85b06
--- /dev/null
+++ b/core/fxge/ge/cfx_facecache.cpp
@@ -0,0 +1,383 @@
+// Copyright 2016 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "core/fxge/include/cfx_facecache.h"
+
+#include <algorithm>
+
+#include "core/fxge/ge/fx_text_int.h"
+#include "core/fxge/include/cfx_fontmgr.h"
+#include "core/fxge/include/cfx_gemodule.h"
+#include "core/fxge/include/cfx_pathdata.h"
+#include "core/fxge/include/fx_freetype.h"
+
+#ifdef _SKIA_SUPPORT_
+#include "third_party/skia/include/core/SkStream.h"
+#include "third_party/skia/include/core/SkTypeface.h"
+#endif
+
+namespace {
+
+void GammaAdjust(uint8_t* pData,
+                 int nHeight,
+                 int src_pitch,
+                 const uint8_t* gammaTable) {
+  int count = nHeight * src_pitch;
+  for (int i = 0; i < count; i++)
+    pData[i] = gammaTable[pData[i]];
+}
+
+void ContrastAdjust(uint8_t* pDataIn,
+                    uint8_t* pDataOut,
+                    int nWidth,
+                    int nHeight,
+                    int nSrcRowBytes,
+                    int nDstRowBytes) {
+  int col, row, temp;
+  int max = 0, min = 255;
+  FX_FLOAT rate;
+  for (row = 0; row < nHeight; row++) {
+    uint8_t* pRow = pDataIn + row * nSrcRowBytes;
+    for (col = 0; col < nWidth; col++) {
+      temp = *pRow++;
+      max = std::max(temp, max);
+      min = std::min(temp, min);
+    }
+  }
+  temp = max - min;
+  if (temp == 0 || temp == 255) {
+    int rowbytes = std::min(FXSYS_abs(nSrcRowBytes), nDstRowBytes);
+    for (row = 0; row < nHeight; row++) {
+      FXSYS_memcpy(pDataOut + row * nDstRowBytes, pDataIn + row * nSrcRowBytes,
+                   rowbytes);
+    }
+    return;
+  }
+  rate = 255.f / temp;
+  for (row = 0; row < nHeight; row++) {
+    uint8_t* pSrcRow = pDataIn + row * nSrcRowBytes;
+    uint8_t* pDstRow = pDataOut + row * nDstRowBytes;
+    for (col = 0; col < nWidth; col++) {
+      temp = static_cast<int>((*(pSrcRow++) - min) * rate + 0.5);
+      temp = std::min(temp, 255);
+      temp = std::max(temp, 0);
+      *pDstRow++ = (uint8_t)temp;
+    }
+  }
+}
+}  // namespace
+
+CFX_FaceCache::CFX_FaceCache(FXFT_Face face)
+    : m_Face(face)
+#ifdef _SKIA_SUPPORT_
+      ,
+      m_pTypeface(nullptr)
+#endif
+{
+}
+
+CFX_FaceCache::~CFX_FaceCache() {
+#ifdef _SKIA_SUPPORT_
+  SkSafeUnref(m_pTypeface);
+#endif
+}
+
+CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph(CFX_Font* pFont,
+                                            uint32_t glyph_index,
+                                            FX_BOOL bFontStyle,
+                                            const CFX_Matrix* pMatrix,
+                                            int dest_width,
+                                            int anti_alias) {
+  if (!m_Face)
+    return nullptr;
+
+  FXFT_Matrix ft_matrix;
+  ft_matrix.xx = (signed long)(pMatrix->GetA() / 64 * 65536);
+  ft_matrix.xy = (signed long)(pMatrix->GetC() / 64 * 65536);
+  ft_matrix.yx = (signed long)(pMatrix->GetB() / 64 * 65536);
+  ft_matrix.yy = (signed long)(pMatrix->GetD() / 64 * 65536);
+  bool bUseCJKSubFont = false;
+  const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
+  if (pSubstFont) {
+    bUseCJKSubFont = pSubstFont->m_bSubstCJK && bFontStyle;
+    int skew = 0;
+    if (bUseCJKSubFont)
+      skew = pSubstFont->m_bItalicCJK ? -15 : 0;
+    else
+      skew = pSubstFont->m_ItalicAngle;
+    if (skew) {
+      // |skew| is nonpositive so |-skew| is used as the index. We need to make
+      // sure |skew| != INT_MIN since -INT_MIN is undefined.
+      if (skew <= 0 && skew != std::numeric_limits<int>::min() &&
+          static_cast<size_t>(-skew) < CFX_Font::kAngleSkewArraySize) {
+        skew = -CFX_Font::s_AngleSkew[-skew];
+      } else {
+        skew = -58;
+      }
+      if (pFont->IsVertical())
+        ft_matrix.yx += ft_matrix.yy * skew / 100;
+      else
+        ft_matrix.xy -= ft_matrix.xx * skew / 100;
+    }
+    if (pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
+      pFont->AdjustMMParams(glyph_index, dest_width,
+                            pFont->GetSubstFont()->m_Weight);
+    }
+  }
+  ScopedFontTransform scoped_transform(m_Face, &ft_matrix);
+  int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT)
+                       ? FXFT_LOAD_NO_BITMAP
+                       : (FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
+  int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
+  if (error) {
+    // if an error is returned, try to reload glyphs without hinting.
+    if (load_flags & FT_LOAD_NO_HINTING || load_flags & FT_LOAD_NO_SCALE)
+      return nullptr;
+
+    load_flags |= FT_LOAD_NO_HINTING;
+    error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
+
+    if (error)
+      return nullptr;
+  }
+  int weight = 0;
+  if (bUseCJKSubFont)
+    weight = pSubstFont->m_WeightCJK;
+  else
+    weight = pSubstFont ? pSubstFont->m_Weight : 0;
+  if (pSubstFont && !(pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) &&
+      weight > 400) {
+    uint32_t index = (weight - 400) / 10;
+    if (index >= CFX_Font::kWeightPowArraySize)
+      return nullptr;
+    int level = 0;
+    if (pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
+      level =
+          CFX_Font::s_WeightPow_SHIFTJIS[index] * 2 *
+          (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) /
+          36655;
+    } else {
+      level =
+          CFX_Font::s_WeightPow_11[index] *
+          (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) /
+          36655;
+    }
+    FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
+  }
+  FXFT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->GetFTLibrary(),
+                            FT_LCD_FILTER_DEFAULT);
+  error = FXFT_Render_Glyph(m_Face, anti_alias);
+  if (error)
+    return nullptr;
+  int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(m_Face));
+  int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(m_Face));
+  if (bmwidth > 2048 || bmheight > 2048)
+    return nullptr;
+  int dib_width = bmwidth;
+  CFX_GlyphBitmap* pGlyphBitmap = new CFX_GlyphBitmap;
+  pGlyphBitmap->m_Bitmap.Create(
+      dib_width, bmheight,
+      anti_alias == FXFT_RENDER_MODE_MONO ? FXDIB_1bppMask : FXDIB_8bppMask);
+  pGlyphBitmap->m_Left = FXFT_Get_Glyph_BitmapLeft(m_Face);
+  pGlyphBitmap->m_Top = FXFT_Get_Glyph_BitmapTop(m_Face);
+  int dest_pitch = pGlyphBitmap->m_Bitmap.GetPitch();
+  int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(m_Face));
+  uint8_t* pDestBuf = pGlyphBitmap->m_Bitmap.GetBuffer();
+  uint8_t* pSrcBuf =
+      (uint8_t*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(m_Face));
+  if (anti_alias != FXFT_RENDER_MODE_MONO &&
+      FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) ==
+          FXFT_PIXEL_MODE_MONO) {
+    int bytes = anti_alias == FXFT_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);
+    if (anti_alias == FXFT_RENDER_MODE_MONO &&
+        FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) ==
+            FXFT_PIXEL_MODE_MONO) {
+      int rowbytes =
+          FXSYS_abs(src_pitch) > dest_pitch ? dest_pitch : FXSYS_abs(src_pitch);
+      for (int row = 0; row < bmheight; row++) {
+        FXSYS_memcpy(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch,
+                     rowbytes);
+      }
+    } else {
+      ContrastAdjust(pSrcBuf, pDestBuf, bmwidth, bmheight, src_pitch,
+                     dest_pitch);
+      GammaAdjust(pDestBuf, bmheight, dest_pitch,
+                  CFX_GEModule::Get()->GetTextGammaTable());
+    }
+  }
+  return pGlyphBitmap;
+}
+
+const CFX_PathData* CFX_FaceCache::LoadGlyphPath(CFX_Font* pFont,
+                                                 uint32_t glyph_index,
+                                                 int dest_width) {
+  if (!m_Face || glyph_index == (uint32_t)-1)
+    return nullptr;
+
+  uint32_t key = glyph_index;
+  if (pFont->GetSubstFont()) {
+    key += (((pFont->GetSubstFont()->m_Weight / 16) << 15) +
+            ((pFont->GetSubstFont()->m_ItalicAngle / 2) << 21) +
+            ((dest_width / 16) << 25) + (pFont->IsVertical() << 31));
+  }
+  auto it = m_PathMap.find(key);
+  if (it != m_PathMap.end())
+    return it->second.get();
+
+  CFX_PathData* pGlyphPath = pFont->LoadGlyphPath(glyph_index, dest_width);
+  m_PathMap[key] = std::unique_ptr<CFX_PathData>(pGlyphPath);
+  return pGlyphPath;
+}
+
+const CFX_GlyphBitmap* CFX_FaceCache::LoadGlyphBitmap(CFX_Font* pFont,
+                                                      uint32_t glyph_index,
+                                                      FX_BOOL bFontStyle,
+                                                      const CFX_Matrix* pMatrix,
+                                                      int dest_width,
+                                                      int anti_alias,
+                                                      int& text_flags) {
+  if (glyph_index == (uint32_t)-1)
+    return nullptr;
+  _CFX_UniqueKeyGen keygen;
+  int nMatrixA = static_cast<int>(pMatrix->a * 10000);
+  int nMatrixB = static_cast<int>(pMatrix->b * 10000);
+  int nMatrixC = static_cast<int>(pMatrix->c * 10000);
+  int nMatrixD = static_cast<int>(pMatrix->d * 10000);
+#if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
+  if (pFont->GetSubstFont()) {
+    keygen.Generate(9, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
+                    anti_alias, pFont->GetSubstFont()->m_Weight,
+                    pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
+  } else {
+    keygen.Generate(6, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
+                    anti_alias);
+  }
+#else
+  if (text_flags & FXTEXT_NO_NATIVETEXT) {
+    if (pFont->GetSubstFont()) {
+      keygen.Generate(9, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
+                      anti_alias, pFont->GetSubstFont()->m_Weight,
+                      pFont->GetSubstFont()->m_ItalicAngle,
+                      pFont->IsVertical());
+    } else {
+      keygen.Generate(6, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
+                      anti_alias);
+    }
+  } else {
+    if (pFont->GetSubstFont()) {
+      keygen.Generate(10, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
+                      anti_alias, pFont->GetSubstFont()->m_Weight,
+                      pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(),
+                      3);
+    } else {
+      keygen.Generate(7, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
+                      anti_alias, 3);
+    }
+  }
+#endif
+  CFX_ByteString FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
+#if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_ || defined _SKIA_SUPPORT_
+  return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index,
+                           bFontStyle, dest_width, anti_alias);
+#else
+  if (text_flags & FXTEXT_NO_NATIVETEXT) {
+    return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index,
+                             bFontStyle, dest_width, anti_alias);
+  }
+  CFX_GlyphBitmap* pGlyphBitmap;
+  auto it = m_SizeMap.find(FaceGlyphsKey);
+  if (it != m_SizeMap.end()) {
+    CFX_SizeGlyphCache* pSizeCache = it->second.get();
+    auto it2 = pSizeCache->m_GlyphMap.find(glyph_index);
+    if (it2 != pSizeCache->m_GlyphMap.end())
+      return it2->second;
+
+    pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix,
+                                          dest_width, anti_alias);
+    if (pGlyphBitmap) {
+      pSizeCache->m_GlyphMap[glyph_index] = pGlyphBitmap;
+      return pGlyphBitmap;
+    }
+  } else {
+    pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix,
+                                          dest_width, anti_alias);
+    if (pGlyphBitmap) {
+      CFX_SizeGlyphCache* pSizeCache = new CFX_SizeGlyphCache;
+      m_SizeMap[FaceGlyphsKey] =
+          std::unique_ptr<CFX_SizeGlyphCache>(pSizeCache);
+      pSizeCache->m_GlyphMap[glyph_index] = pGlyphBitmap;
+      return pGlyphBitmap;
+    }
+  }
+  if (pFont->GetSubstFont()) {
+    keygen.Generate(9, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
+                    anti_alias, pFont->GetSubstFont()->m_Weight,
+                    pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
+  } else {
+    keygen.Generate(6, nMatrixA, nMatrixB, nMatrixC, nMatrixD, dest_width,
+                    anti_alias);
+  }
+  CFX_ByteString FaceGlyphsKey2(keygen.m_Key, keygen.m_KeyLen);
+  text_flags |= FXTEXT_NO_NATIVETEXT;
+  return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey2, glyph_index,
+                           bFontStyle, dest_width, anti_alias);
+#endif
+}
+
+#ifdef _SKIA_SUPPORT_
+CFX_TypeFace* CFX_FaceCache::GetDeviceCache(CFX_Font* pFont) {
+  if (!m_pTypeface) {
+    m_pTypeface =
+        SkTypeface::MakeFromStream(
+            new SkMemoryStream(pFont->GetFontData(), pFont->GetSize()))
+            .release();
+  }
+  return m_pTypeface;
+}
+#endif
+
+#if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
+void CFX_FaceCache::InitPlatform() {}
+#endif
+
+CFX_GlyphBitmap* CFX_FaceCache::LookUpGlyphBitmap(
+    CFX_Font* pFont,
+    const CFX_Matrix* pMatrix,
+    const CFX_ByteString& FaceGlyphsKey,
+    uint32_t glyph_index,
+    FX_BOOL bFontStyle,
+    int dest_width,
+    int anti_alias) {
+  CFX_SizeGlyphCache* pSizeCache;
+  auto it = m_SizeMap.find(FaceGlyphsKey);
+  if (it == m_SizeMap.end()) {
+    pSizeCache = new CFX_SizeGlyphCache;
+    m_SizeMap[FaceGlyphsKey] = std::unique_ptr<CFX_SizeGlyphCache>(pSizeCache);
+  } else {
+    pSizeCache = it->second.get();
+  }
+  auto it2 = pSizeCache->m_GlyphMap.find(glyph_index);
+  if (it2 != pSizeCache->m_GlyphMap.end())
+    return it2->second;
+
+  CFX_GlyphBitmap* pGlyphBitmap = RenderGlyph(pFont, glyph_index, bFontStyle,
+                                              pMatrix, dest_width, anti_alias);
+  if (!pGlyphBitmap)
+    return nullptr;
+
+  pSizeCache->m_GlyphMap[glyph_index] = pGlyphBitmap;
+  return pGlyphBitmap;
+}
diff --git a/core/fxge/ge/cfx_fontcache.cpp b/core/fxge/ge/cfx_fontcache.cpp
index a183711..3ecd83c 100644
--- a/core/fxge/ge/cfx_fontcache.cpp
+++ b/core/fxge/ge/cfx_fontcache.cpp
@@ -6,6 +6,7 @@
 
 #include "core/fxge/include/cfx_fontcache.h"
 
+#include "core/fxge/include/cfx_facecache.h"
 #include "core/fxge/include/fx_font.h"
 #include "core/fxge/include/fx_freetype.h"
 
diff --git a/core/fxge/ge/cfx_renderdevice.cpp b/core/fxge/ge/cfx_renderdevice.cpp
index 1890b52..7396308 100644
--- a/core/fxge/ge/cfx_renderdevice.cpp
+++ b/core/fxge/ge/cfx_renderdevice.cpp
@@ -8,6 +8,7 @@
 
 #include "core/fxcrt/include/fx_safe_types.h"
 #include "core/fxge/include/cfx_autofontcache.h"
+#include "core/fxge/include/cfx_facecache.h"
 #include "core/fxge/include/cfx_fontcache.h"
 #include "core/fxge/include/cfx_fxgedevice.h"
 #include "core/fxge/include/cfx_graphstatedata.h"
diff --git a/core/fxge/ge/fx_ge_text.cpp b/core/fxge/ge/fx_ge_text.cpp
index 8e16c17..b81c1ba 100644
--- a/core/fxge/ge/fx_ge_text.cpp
+++ b/core/fxge/ge/fx_ge_text.cpp
@@ -4,23 +4,17 @@
 
 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
 
+#include <algorithm>
 #include <limits>
 #include <vector>
 
 #include "core/fxcodec/include/fx_codec.h"
 #include "core/fxcrt/include/fx_safe_types.h"
 #include "core/fxge/ge/fx_text_int.h"
-#include "core/fxge/include/cfx_fontmgr.h"
-#include "core/fxge/include/cfx_gemodule.h"
 #include "core/fxge/include/cfx_pathdata.h"
 #include "core/fxge/include/fx_freetype.h"
 #include "core/fxge/include/ifx_renderdevicedriver.h"
 
-#ifdef _SKIA_SUPPORT_
-#include "third_party/skia/include/core/SkStream.h"
-#include "third_party/skia/include/core/SkTypeface.h"
-#endif
-
 namespace {
 
 void ResetTransform(FT_Face face) {
@@ -32,22 +26,17 @@
   FXFT_Set_Transform(face, &matrix, 0);
 }
 
-// Sets the given transform on the font, and resets it to the identity when it
-// goes out of scope.
-class ScopedFontTransform {
- public:
-  ScopedFontTransform(FT_Face face, FXFT_Matrix* matrix) : m_Face(face) {
-    FXFT_Set_Transform(m_Face, matrix, 0);
-  }
-
-  ~ScopedFontTransform() { ResetTransform(m_Face); }
-
- private:
-  FT_Face m_Face;
-};
-
 }  // namespace
 
+ScopedFontTransform::ScopedFontTransform(FT_Face face, FXFT_Matrix* matrix)
+    : m_Face(face) {
+  FXFT_Set_Transform(m_Face, matrix, 0);
+}
+
+ScopedFontTransform::~ScopedFontTransform() {
+  ResetTransform(m_Face);
+}
+
 FX_RECT FXGE_GetGlyphsBBox(const std::vector<FXTEXT_GLYPHPOS>& glyphs,
                            int anti_alias,
                            FX_FLOAT retinaScaleX,
@@ -106,167 +95,6 @@
   return rect;
 }
 
-#ifdef _SKIA_SUPPORT_
-CFX_TypeFace* CFX_FaceCache::GetDeviceCache(CFX_Font* pFont) {
-  if (!m_pTypeface) {
-    m_pTypeface =
-        SkTypeface::MakeFromStream(
-            new SkMemoryStream(pFont->GetFontData(), pFont->GetSize()))
-            .release();
-  }
-  return m_pTypeface;
-}
-#endif
-
-CFX_FaceCache::CFX_FaceCache(FXFT_Face face)
-    : m_Face(face)
-#ifdef _SKIA_SUPPORT_
-      ,
-      m_pTypeface(nullptr)
-#endif
-{
-}
-
-CFX_FaceCache::~CFX_FaceCache() {
-  for (const auto& pair : m_SizeMap) {
-    delete pair.second;
-  }
-  m_SizeMap.clear();
-  for (const auto& pair : m_PathMap) {
-    delete pair.second;
-  }
-  m_PathMap.clear();
-#ifdef _SKIA_SUPPORT_
-  SkSafeUnref(m_pTypeface);
-#endif
-}
-
-#if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
-void CFX_FaceCache::InitPlatform() {}
-#endif
-CFX_GlyphBitmap* CFX_FaceCache::LookUpGlyphBitmap(
-    CFX_Font* pFont,
-    const CFX_Matrix* pMatrix,
-    const CFX_ByteString& FaceGlyphsKey,
-    uint32_t glyph_index,
-    FX_BOOL bFontStyle,
-    int dest_width,
-    int anti_alias) {
-  CFX_SizeGlyphCache* pSizeCache;
-  auto it = m_SizeMap.find(FaceGlyphsKey);
-  if (it == m_SizeMap.end()) {
-    pSizeCache = new CFX_SizeGlyphCache;
-    m_SizeMap[FaceGlyphsKey] = pSizeCache;
-  } else {
-    pSizeCache = it->second;
-  }
-  auto it2 = pSizeCache->m_GlyphMap.find(glyph_index);
-  if (it2 != pSizeCache->m_GlyphMap.end())
-    return it2->second;
-
-  CFX_GlyphBitmap* pGlyphBitmap = RenderGlyph(pFont, glyph_index, bFontStyle,
-                                              pMatrix, dest_width, anti_alias);
-  if (!pGlyphBitmap)
-    return nullptr;
-
-  pSizeCache->m_GlyphMap[glyph_index] = pGlyphBitmap;
-  return pGlyphBitmap;
-}
-const CFX_GlyphBitmap* CFX_FaceCache::LoadGlyphBitmap(CFX_Font* pFont,
-                                                      uint32_t glyph_index,
-                                                      FX_BOOL bFontStyle,
-                                                      const CFX_Matrix* pMatrix,
-                                                      int dest_width,
-                                                      int anti_alias,
-                                                      int& text_flags) {
-  if (glyph_index == (uint32_t)-1) {
-    return nullptr;
-  }
-  _CFX_UniqueKeyGen keygen;
-#if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
-  if (pFont->GetSubstFont())
-    keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
-                    (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000),
-                    dest_width, anti_alias, pFont->GetSubstFont()->m_Weight,
-                    pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
-  else
-    keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
-                    (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000),
-                    dest_width, anti_alias);
-#else
-  if (text_flags & FXTEXT_NO_NATIVETEXT) {
-    if (pFont->GetSubstFont())
-      keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
-                      (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000),
-                      dest_width, anti_alias, pFont->GetSubstFont()->m_Weight,
-                      pFont->GetSubstFont()->m_ItalicAngle,
-                      pFont->IsVertical());
-    else
-      keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
-                      (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000),
-                      dest_width, anti_alias);
-  } else {
-    if (pFont->GetSubstFont())
-      keygen.Generate(10, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
-                      (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000),
-                      dest_width, anti_alias, pFont->GetSubstFont()->m_Weight,
-                      pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(),
-                      3);
-    else
-      keygen.Generate(7, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
-                      (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000),
-                      dest_width, anti_alias, 3);
-  }
-#endif
-  CFX_ByteString FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
-#if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_ || defined _SKIA_SUPPORT_
-  return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index,
-                           bFontStyle, dest_width, anti_alias);
-#else
-  if (text_flags & FXTEXT_NO_NATIVETEXT) {
-    return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index,
-                             bFontStyle, dest_width, anti_alias);
-  }
-  CFX_GlyphBitmap* pGlyphBitmap;
-  auto it = m_SizeMap.find(FaceGlyphsKey);
-  if (it != m_SizeMap.end()) {
-    CFX_SizeGlyphCache* pSizeCache = it->second;
-    auto it2 = pSizeCache->m_GlyphMap.find(glyph_index);
-    if (it2 != pSizeCache->m_GlyphMap.end())
-      return it2->second;
-
-    pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix,
-                                          dest_width, anti_alias);
-    if (pGlyphBitmap) {
-      pSizeCache->m_GlyphMap[glyph_index] = pGlyphBitmap;
-      return pGlyphBitmap;
-    }
-  } else {
-    pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix,
-                                          dest_width, anti_alias);
-    if (pGlyphBitmap) {
-      CFX_SizeGlyphCache* pSizeCache = new CFX_SizeGlyphCache;
-      m_SizeMap[FaceGlyphsKey] = pSizeCache;
-      pSizeCache->m_GlyphMap[glyph_index] = pGlyphBitmap;
-      return pGlyphBitmap;
-    }
-  }
-  if (pFont->GetSubstFont())
-    keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
-                    (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000),
-                    dest_width, anti_alias, pFont->GetSubstFont()->m_Weight,
-                    pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
-  else
-    keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
-                    (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000),
-                    dest_width, anti_alias);
-  CFX_ByteString FaceGlyphsKey2(keygen.m_Key, keygen.m_KeyLen);
-  text_flags |= FXTEXT_NO_NATIVETEXT;
-  return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey2, glyph_index,
-                           bFontStyle, dest_width, anti_alias);
-#endif
-}
-
 CFX_SizeGlyphCache::CFX_SizeGlyphCache() {}
 
 CFX_SizeGlyphCache::~CFX_SizeGlyphCache() {
@@ -320,13 +148,11 @@
   FXFT_Free(m_Face, pMasters);
   FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
 }
-static const size_t ANGLESKEW_ARRAY_SIZE = 30;
-static const char g_AngleSkew[ANGLESKEW_ARRAY_SIZE] = {
+const char CFX_Font::s_AngleSkew[] = {
     0,  2,  3,  5,  7,  9,  11, 12, 14, 16, 18, 19, 21, 23, 25,
     27, 29, 31, 32, 34, 36, 38, 40, 42, 45, 47, 49, 51, 53, 55,
 };
-static const size_t WEIGHTPOW_ARRAY_SIZE = 100;
-static const uint8_t g_WeightPow[WEIGHTPOW_ARRAY_SIZE] = {
+const uint8_t CFX_Font::s_WeightPow[] = {
     0,  3,  6,  7,  8,  9,  11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22,
     23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 36, 37,
     37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42,
@@ -334,7 +160,7 @@
     47, 47, 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 50,
     51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53,
 };
-static const uint8_t g_WeightPow_11[WEIGHTPOW_ARRAY_SIZE] = {
+const uint8_t CFX_Font::s_WeightPow_11[] = {
     0,  4,  7,  8,  9,  10, 12, 13, 15, 17, 18, 19, 20, 21, 22, 23, 24,
     25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 39, 40, 40, 41,
     41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46,
@@ -342,7 +168,7 @@
     52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55,
     56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58,
 };
-static const uint8_t g_WeightPow_SHIFTJIS[WEIGHTPOW_ARRAY_SIZE] = {
+const uint8_t CFX_Font::s_WeightPow_SHIFTJIS[] = {
     0,  0,  1,  2,  3,  4,  5,  7,  8,  10, 11, 13, 14, 16, 17, 19, 21,
     22, 24, 26, 28, 30, 32, 33, 35, 37, 39, 41, 43, 45, 48, 48, 48, 48,
     49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 52, 53,
@@ -350,223 +176,6 @@
     56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 58,
     59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60,
 };
-static void _GammaAdjust(uint8_t* pData,
-                         int nWid,
-                         int nHei,
-                         int src_pitch,
-                         const uint8_t* gammaTable) {
-  int count = nHei * src_pitch;
-  for (int i = 0; i < count; i++) {
-    pData[i] = gammaTable[pData[i]];
-  }
-}
-static void _ContrastAdjust(uint8_t* pDataIn,
-                            uint8_t* pDataOut,
-                            int nWid,
-                            int nHei,
-                            int nSrcRowBytes,
-                            int nDstRowBytes) {
-  int col, row, temp;
-  int max = 0, min = 255;
-  FX_FLOAT rate;
-  for (row = 0; row < nHei; row++) {
-    uint8_t* pRow = pDataIn + row * nSrcRowBytes;
-    for (col = 0; col < nWid; col++) {
-      temp = *pRow++;
-      if (temp > max) {
-        max = temp;
-      }
-      if (temp < min) {
-        min = temp;
-      }
-    }
-  }
-  temp = max - min;
-  if (0 == temp || 255 == temp) {
-    int rowbytes = FXSYS_abs(nSrcRowBytes) > nDstRowBytes
-                       ? nDstRowBytes
-                       : FXSYS_abs(nSrcRowBytes);
-    for (row = 0; row < nHei; row++) {
-      FXSYS_memcpy(pDataOut + row * nDstRowBytes, pDataIn + row * nSrcRowBytes,
-                   rowbytes);
-    }
-    return;
-  }
-  rate = 255.f / temp;
-  for (row = 0; row < nHei; row++) {
-    uint8_t* pSrcRow = pDataIn + row * nSrcRowBytes;
-    uint8_t* pDstRow = pDataOut + row * nDstRowBytes;
-    for (col = 0; col < nWid; col++) {
-      temp = (int)((*(pSrcRow++) - min) * rate + 0.5);
-      if (temp > 255) {
-        temp = 255;
-      } else if (temp < 0) {
-        temp = 0;
-      }
-      *pDstRow++ = (uint8_t)temp;
-    }
-  }
-}
-CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph(CFX_Font* pFont,
-                                            uint32_t glyph_index,
-                                            FX_BOOL bFontStyle,
-                                            const CFX_Matrix* pMatrix,
-                                            int dest_width,
-                                            int anti_alias) {
-  if (!m_Face) {
-    return nullptr;
-  }
-  FXFT_Matrix ft_matrix;
-  ft_matrix.xx = (signed long)(pMatrix->GetA() / 64 * 65536);
-  ft_matrix.xy = (signed long)(pMatrix->GetC() / 64 * 65536);
-  ft_matrix.yx = (signed long)(pMatrix->GetB() / 64 * 65536);
-  ft_matrix.yy = (signed long)(pMatrix->GetD() / 64 * 65536);
-  FX_BOOL bUseCJKSubFont = FALSE;
-  const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
-  if (pSubstFont) {
-    bUseCJKSubFont = pSubstFont->m_bSubstCJK && bFontStyle;
-    int skew = 0;
-    if (bUseCJKSubFont) {
-      skew = pSubstFont->m_bItalicCJK ? -15 : 0;
-    } else {
-      skew = pSubstFont->m_ItalicAngle;
-    }
-    if (skew) {
-      // |skew| is nonpositive so |-skew| is used as the index. We need to make
-      // sure |skew| != INT_MIN since -INT_MIN is undefined.
-      if (skew <= 0 && skew != std::numeric_limits<int>::min() &&
-          static_cast<size_t>(-skew) < ANGLESKEW_ARRAY_SIZE) {
-        skew = -g_AngleSkew[-skew];
-      } else {
-        skew = -58;
-      }
-      if (pFont->IsVertical())
-        ft_matrix.yx += ft_matrix.yy * skew / 100;
-      else
-        ft_matrix.xy -= ft_matrix.xx * skew / 100;
-    }
-    if (pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
-      pFont->AdjustMMParams(glyph_index, dest_width,
-                            pFont->GetSubstFont()->m_Weight);
-    }
-  }
-  ScopedFontTransform scoped_transform(m_Face, &ft_matrix);
-  int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT)
-                       ? FXFT_LOAD_NO_BITMAP
-                       : (FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
-  int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
-  if (error) {
-    // if an error is returned, try to reload glyphs without hinting.
-    if (load_flags & FT_LOAD_NO_HINTING || load_flags & FT_LOAD_NO_SCALE) {
-      return nullptr;
-    }
-
-    load_flags |= FT_LOAD_NO_HINTING;
-    error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
-
-    if (error) {
-      return nullptr;
-    }
-  }
-  int weight = 0;
-  if (bUseCJKSubFont) {
-    weight = pSubstFont->m_WeightCJK;
-  } else {
-    weight = pSubstFont ? pSubstFont->m_Weight : 0;
-  }
-  if (pSubstFont && !(pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) &&
-      weight > 400) {
-    uint32_t index = (weight - 400) / 10;
-    if (index >= WEIGHTPOW_ARRAY_SIZE)
-      return nullptr;
-    int level = 0;
-    if (pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
-      level =
-          g_WeightPow_SHIFTJIS[index] * 2 *
-          (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) /
-          36655;
-    } else {
-      level = g_WeightPow_11[index] * (FXSYS_abs((int)(ft_matrix.xx)) +
-                                       FXSYS_abs((int)(ft_matrix.xy))) /
-              36655;
-    }
-    FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
-  }
-  FXFT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->GetFTLibrary(),
-                            FT_LCD_FILTER_DEFAULT);
-  error = FXFT_Render_Glyph(m_Face, anti_alias);
-  if (error) {
-    return nullptr;
-  }
-  int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(m_Face));
-  int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(m_Face));
-  if (bmwidth > 2048 || bmheight > 2048) {
-    return nullptr;
-  }
-  int dib_width = bmwidth;
-  CFX_GlyphBitmap* pGlyphBitmap = new CFX_GlyphBitmap;
-  pGlyphBitmap->m_Bitmap.Create(
-      dib_width, bmheight,
-      anti_alias == FXFT_RENDER_MODE_MONO ? FXDIB_1bppMask : FXDIB_8bppMask);
-  pGlyphBitmap->m_Left = FXFT_Get_Glyph_BitmapLeft(m_Face);
-  pGlyphBitmap->m_Top = FXFT_Get_Glyph_BitmapTop(m_Face);
-  int dest_pitch = pGlyphBitmap->m_Bitmap.GetPitch();
-  int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(m_Face));
-  uint8_t* pDestBuf = pGlyphBitmap->m_Bitmap.GetBuffer();
-  uint8_t* pSrcBuf =
-      (uint8_t*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(m_Face));
-  if (anti_alias != FXFT_RENDER_MODE_MONO &&
-      FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) ==
-          FXFT_PIXEL_MODE_MONO) {
-    int bytes = anti_alias == FXFT_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);
-    if (anti_alias == FXFT_RENDER_MODE_MONO &&
-        FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) ==
-            FXFT_PIXEL_MODE_MONO) {
-      int rowbytes =
-          FXSYS_abs(src_pitch) > dest_pitch ? dest_pitch : FXSYS_abs(src_pitch);
-      for (int row = 0; row < bmheight; row++) {
-        FXSYS_memcpy(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch,
-                     rowbytes);
-      }
-    } else {
-      _ContrastAdjust(pSrcBuf, pDestBuf, bmwidth, bmheight, src_pitch,
-                      dest_pitch);
-      _GammaAdjust(pDestBuf, bmwidth, bmheight, dest_pitch,
-                   CFX_GEModule::Get()->GetTextGammaTable());
-    }
-  }
-  return pGlyphBitmap;
-}
-const CFX_PathData* CFX_FaceCache::LoadGlyphPath(CFX_Font* pFont,
-                                                 uint32_t glyph_index,
-                                                 int dest_width) {
-  if (!m_Face || glyph_index == (uint32_t)-1)
-    return nullptr;
-
-  uint32_t key = glyph_index;
-  if (pFont->GetSubstFont()) {
-    key += (((pFont->GetSubstFont()->m_Weight / 16) << 15) +
-            ((pFont->GetSubstFont()->m_ItalicAngle / 2) << 21) +
-            ((dest_width / 16) << 25) + (pFont->IsVertical() << 31));
-  }
-  auto it = m_PathMap.find(key);
-  if (it != m_PathMap.end())
-    return it->second;
-
-  CFX_PathData* pGlyphPath = pFont->LoadGlyphPath(glyph_index, dest_width);
-  m_PathMap[key] = pGlyphPath;
-  return pGlyphPath;
-}
 typedef struct {
   FX_BOOL m_bCount;
   int m_PointCount;
@@ -705,8 +314,8 @@
       // |skew| is nonpositive so |-skew| is used as the index. We need to make
       // sure |skew| != INT_MIN since -INT_MIN is undefined.
       if (skew <= 0 && skew != std::numeric_limits<int>::min() &&
-          static_cast<size_t>(-skew) < ANGLESKEW_ARRAY_SIZE) {
-        skew = -g_AngleSkew[-skew];
+          static_cast<size_t>(-skew) < kAngleSkewArraySize) {
+        skew = -s_AngleSkew[-skew];
       } else {
         skew = -58;
       }
@@ -729,13 +338,12 @@
   if (m_pSubstFont && !(m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) &&
       m_pSubstFont->m_Weight > 400) {
     uint32_t index = (m_pSubstFont->m_Weight - 400) / 10;
-    if (index >= WEIGHTPOW_ARRAY_SIZE)
-      index = WEIGHTPOW_ARRAY_SIZE - 1;
+    index = std::min(index, static_cast<uint32_t>(kWeightPowArraySize - 1));
     int level = 0;
     if (m_pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET)
-      level = g_WeightPow_SHIFTJIS[index] * 2 * 65536 / 36655;
+      level = s_WeightPow_SHIFTJIS[index] * 2 * 65536 / 36655;
     else
-      level = g_WeightPow[index] * 2;
+      level = s_WeightPow[index] * 2;
     FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
   }
   FXFT_Outline_Funcs funcs;
diff --git a/core/fxge/include/cfx_facecache.h b/core/fxge/include/cfx_facecache.h
new file mode 100644
index 0000000..6e437b4
--- /dev/null
+++ b/core/fxge/include/cfx_facecache.h
@@ -0,0 +1,64 @@
+// Copyright 2016 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef CORE_FXGE_INCLUDE_CFX_FACECACHE_H_
+#define CORE_FXGE_INCLUDE_CFX_FACECACHE_H_
+
+#include <map>
+
+#include "core/fxge/include/fx_font.h"
+#include "core/fxge/include/fx_freetype.h"
+
+class CFX_FaceCache {
+ public:
+  explicit CFX_FaceCache(FXFT_Face face);
+  ~CFX_FaceCache();
+  const CFX_GlyphBitmap* LoadGlyphBitmap(CFX_Font* pFont,
+                                         uint32_t glyph_index,
+                                         FX_BOOL bFontStyle,
+                                         const CFX_Matrix* pMatrix,
+                                         int dest_width,
+                                         int anti_alias,
+                                         int& text_flags);
+  const CFX_PathData* LoadGlyphPath(CFX_Font* pFont,
+                                    uint32_t glyph_index,
+                                    int dest_width);
+
+#ifdef _SKIA_SUPPORT_
+  CFX_TypeFace* GetDeviceCache(CFX_Font* pFont);
+#endif
+
+ private:
+  CFX_GlyphBitmap* RenderGlyph(CFX_Font* pFont,
+                               uint32_t glyph_index,
+                               FX_BOOL bFontStyle,
+                               const CFX_Matrix* pMatrix,
+                               int dest_width,
+                               int anti_alias);
+  CFX_GlyphBitmap* RenderGlyph_Nativetext(CFX_Font* pFont,
+                                          uint32_t glyph_index,
+                                          const CFX_Matrix* pMatrix,
+                                          int dest_width,
+                                          int anti_alias);
+  CFX_GlyphBitmap* LookUpGlyphBitmap(CFX_Font* pFont,
+                                     const CFX_Matrix* pMatrix,
+                                     const CFX_ByteString& FaceGlyphsKey,
+                                     uint32_t glyph_index,
+                                     FX_BOOL bFontStyle,
+                                     int dest_width,
+                                     int anti_alias);
+  void InitPlatform();
+  void DestroyPlatform();
+
+  FXFT_Face const m_Face;
+  std::map<CFX_ByteString, std::unique_ptr<CFX_SizeGlyphCache>> m_SizeMap;
+  std::map<uint32_t, std::unique_ptr<CFX_PathData>> m_PathMap;
+#ifdef _SKIA_SUPPORT_
+  CFX_TypeFace* m_pTypeface;
+#endif
+};
+
+#endif  //  CORE_FXGE_INCLUDE_CFX_FACECACHE_H_
diff --git a/core/fxge/include/cfx_fontcache.h b/core/fxge/include/cfx_fontcache.h
index 3aee207..d4a4ddd 100644
--- a/core/fxge/include/cfx_fontcache.h
+++ b/core/fxge/include/cfx_fontcache.h
@@ -13,6 +13,8 @@
 #include "core/fxge/include/fx_font.h"
 #include "core/fxge/include/fx_freetype.h"
 
+class CFX_FaceCache;
+
 class CFX_FontCache {
  public:
   CFX_FontCache();
diff --git a/core/fxge/include/fx_font.h b/core/fxge/include/fx_font.h
index e6ffc6b..28c51b1 100644
--- a/core/fxge/include/fx_font.h
+++ b/core/fxge/include/fx_font.h
@@ -74,6 +74,17 @@
 #define GET_TT_LONG(w) \
   (uint32_t)(((w)[0] << 24) | ((w)[1] << 16) | ((w)[2] << 8) | (w)[3])
 
+// Sets the given transform on the font, and resets it to the identity when it
+// goes out of scope.
+class ScopedFontTransform {
+ public:
+  ScopedFontTransform(FT_Face face, FXFT_Matrix* matrix);
+  ~ScopedFontTransform();
+
+ private:
+  FT_Face m_Face;
+};
+
 class CFX_Font {
  public:
   CFX_Font();
@@ -132,6 +143,13 @@
   uint32_t GetSize() const { return m_dwSize; }
   void AdjustMMParams(int glyph_index, int width, int weight);
 
+  static const size_t kAngleSkewArraySize = 30;
+  static const char s_AngleSkew[kAngleSkewArraySize];
+  static const size_t kWeightPowArraySize = 100;
+  static const uint8_t s_WeightPow[kWeightPowArraySize];
+  static const uint8_t s_WeightPow_11[kWeightPowArraySize];
+  static const uint8_t s_WeightPow_SHIFTJIS[kWeightPowArraySize];
+
 #ifdef PDF_ENABLE_XFA
  protected:
   CFX_BinaryBuf m_OtfFontData;
@@ -243,56 +261,6 @@
   CFX_DIBitmap m_Bitmap;
 };
 
-class CFX_FaceCache {
- public:
-  explicit CFX_FaceCache(FXFT_Face face);
-  ~CFX_FaceCache();
-  const CFX_GlyphBitmap* LoadGlyphBitmap(CFX_Font* pFont,
-                                         uint32_t glyph_index,
-                                         FX_BOOL bFontStyle,
-                                         const CFX_Matrix* pMatrix,
-                                         int dest_width,
-                                         int anti_alias,
-                                         int& text_flags);
-  const CFX_PathData* LoadGlyphPath(CFX_Font* pFont,
-                                    uint32_t glyph_index,
-                                    int dest_width);
-
-#ifdef _SKIA_SUPPORT_
-  CFX_TypeFace* GetDeviceCache(CFX_Font* pFont);
-#endif
-
- private:
-  CFX_GlyphBitmap* RenderGlyph(CFX_Font* pFont,
-                               uint32_t glyph_index,
-                               FX_BOOL bFontStyle,
-                               const CFX_Matrix* pMatrix,
-                               int dest_width,
-                               int anti_alias);
-  CFX_GlyphBitmap* RenderGlyph_Nativetext(CFX_Font* pFont,
-                                          uint32_t glyph_index,
-                                          const CFX_Matrix* pMatrix,
-                                          int dest_width,
-                                          int anti_alias);
-  CFX_GlyphBitmap* LookUpGlyphBitmap(CFX_Font* pFont,
-                                     const CFX_Matrix* pMatrix,
-                                     const CFX_ByteString& FaceGlyphsKey,
-                                     uint32_t glyph_index,
-                                     FX_BOOL bFontStyle,
-                                     int dest_width,
-                                     int anti_alias);
-  void InitPlatform();
-  void DestroyPlatform();
-
-  FXFT_Face const m_Face;
-  std::map<CFX_ByteString, CFX_SizeGlyphCache*> m_SizeMap;
-  std::map<uint32_t, CFX_PathData*> m_PathMap;
-  CFX_DIBitmap* m_pBitmap;
-#ifdef _SKIA_SUPPORT_
-  CFX_TypeFace* m_pTypeface;
-#endif
-};
-
 struct FXTEXT_GLYPHPOS {
   const CFX_GlyphBitmap* m_pGlyph;
   int m_OriginX;
diff --git a/pdfium.gyp b/pdfium.gyp
index f2e0106..1fc54ea 100644
--- a/pdfium.gyp
+++ b/pdfium.gyp
@@ -737,6 +737,7 @@
         'core/fxge/ge/cfx_autofontcache.cpp',
         'core/fxge/ge/cfx_cliprgn.cpp',
         'core/fxge/ge/cfx_cliprgn.h',
+        'core/fxge/ge/cfx_facecache.cpp',
         'core/fxge/ge/cfx_folderfontinfo.cpp',
         'core/fxge/ge/cfx_folderfontinfo.h',
         'core/fxge/ge/cfx_fontcache.cpp',
@@ -757,6 +758,7 @@
         'core/fxge/ge/fx_text_int.h',
         'core/fxge/ifx_renderdevicedriver.cpp',
         'core/fxge/include/cfx_autofontcache.h',
+        'core/fxge/include/cfx_facecache.h',
         'core/fxge/include/cfx_fontcache.h',
         'core/fxge/include/cfx_fxgedevice.h',
         'core/fxge/include/cfx_gemodule.h',