Home | History | Annotate | Download | only in fxge
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "core/fxge/cfx_font.h"
      8 
      9 #include <algorithm>
     10 #include <limits>
     11 #include <memory>
     12 #include <utility>
     13 #include <vector>
     14 
     15 #include "core/fpdfapi/font/cpdf_font.h"
     16 #include "core/fxcrt/fx_codepage.h"
     17 #include "core/fxcrt/fx_stream.h"
     18 #include "core/fxge/cfx_facecache.h"
     19 #include "core/fxge/cfx_fontcache.h"
     20 #include "core/fxge/cfx_fontmgr.h"
     21 #include "core/fxge/cfx_gemodule.h"
     22 #include "core/fxge/cfx_pathdata.h"
     23 #include "core/fxge/cfx_substfont.h"
     24 #include "core/fxge/fx_freetype.h"
     25 #include "third_party/base/ptr_util.h"
     26 
     27 #define EM_ADJUST(em, a) (em == 0 ? (a) : (a)*1000 / em)
     28 
     29 namespace {
     30 
     31 constexpr int kThousandthMinInt = std::numeric_limits<int>::min() / 1000;
     32 constexpr int kThousandthMaxInt = std::numeric_limits<int>::max() / 1000;
     33 
     34 struct OUTLINE_PARAMS {
     35   CFX_PathData* m_pPath;
     36   int m_CurX;
     37   int m_CurY;
     38   float m_CoordUnit;
     39 };
     40 
     41 #ifdef PDF_ENABLE_XFA
     42 
     43 unsigned long FTStreamRead(FXFT_Stream stream,
     44                            unsigned long offset,
     45                            unsigned char* buffer,
     46                            unsigned long count) {
     47   if (count == 0)
     48     return 0;
     49 
     50   IFX_SeekableReadStream* pFile =
     51       static_cast<IFX_SeekableReadStream*>(stream->descriptor.pointer);
     52   return pFile && pFile->ReadBlock(buffer, offset, count) ? count : 0;
     53 }
     54 
     55 void FTStreamClose(FXFT_Stream stream) {}
     56 
     57 bool LoadFileImp(FXFT_Library library,
     58                  FXFT_Face* Face,
     59                  const RetainPtr<IFX_SeekableReadStream>& pFile,
     60                  int32_t faceIndex,
     61                  std::unique_ptr<FXFT_StreamRec>* stream) {
     62   auto stream1 = pdfium::MakeUnique<FXFT_StreamRec>();
     63   stream1->base = nullptr;
     64   stream1->size = static_cast<unsigned long>(pFile->GetSize());
     65   stream1->pos = 0;
     66   stream1->descriptor.pointer = static_cast<void*>(pFile.Get());
     67   stream1->close = FTStreamClose;
     68   stream1->read = FTStreamRead;
     69   FXFT_Open_Args args;
     70   args.flags = FT_OPEN_STREAM;
     71   args.stream = stream1.get();
     72   if (FXFT_Open_Face(library, &args, faceIndex, Face))
     73     return false;
     74   if (stream)
     75     *stream = std::move(stream1);
     76   return true;
     77 }
     78 #endif  // PDF_ENABLE_XFA
     79 
     80 FXFT_Face FT_LoadFont(const uint8_t* pData, int size) {
     81   return CFX_GEModule::Get()->GetFontMgr()->GetFixedFace(pData, size, 0);
     82 }
     83 
     84 void Outline_CheckEmptyContour(OUTLINE_PARAMS* param) {
     85   std::vector<FX_PATHPOINT>& points = param->m_pPath->GetPoints();
     86   size_t size = points.size();
     87 
     88   if (size >= 2 && points[size - 2].IsTypeAndOpen(FXPT_TYPE::MoveTo) &&
     89       points[size - 2].m_Point == points[size - 1].m_Point) {
     90     size -= 2;
     91   }
     92   if (size >= 4 && points[size - 4].IsTypeAndOpen(FXPT_TYPE::MoveTo) &&
     93       points[size - 3].IsTypeAndOpen(FXPT_TYPE::BezierTo) &&
     94       points[size - 3].m_Point == points[size - 4].m_Point &&
     95       points[size - 2].m_Point == points[size - 4].m_Point &&
     96       points[size - 1].m_Point == points[size - 4].m_Point) {
     97     size -= 4;
     98   }
     99   points.resize(size);
    100 }
    101 
    102 int Outline_MoveTo(const FXFT_Vector* to, void* user) {
    103   OUTLINE_PARAMS* param = static_cast<OUTLINE_PARAMS*>(user);
    104 
    105   Outline_CheckEmptyContour(param);
    106 
    107   param->m_pPath->ClosePath();
    108   param->m_pPath->AppendPoint(
    109       CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
    110       FXPT_TYPE::MoveTo, false);
    111 
    112   param->m_CurX = to->x;
    113   param->m_CurY = to->y;
    114   return 0;
    115 }
    116 
    117 int Outline_LineTo(const FXFT_Vector* to, void* user) {
    118   OUTLINE_PARAMS* param = static_cast<OUTLINE_PARAMS*>(user);
    119 
    120   param->m_pPath->AppendPoint(
    121       CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
    122       FXPT_TYPE::LineTo, false);
    123 
    124   param->m_CurX = to->x;
    125   param->m_CurY = to->y;
    126   return 0;
    127 }
    128 
    129 int Outline_ConicTo(const FXFT_Vector* control,
    130                     const FXFT_Vector* to,
    131                     void* user) {
    132   OUTLINE_PARAMS* param = static_cast<OUTLINE_PARAMS*>(user);
    133 
    134   param->m_pPath->AppendPoint(
    135       CFX_PointF((param->m_CurX + (control->x - param->m_CurX) * 2 / 3) /
    136                      param->m_CoordUnit,
    137                  (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) /
    138                      param->m_CoordUnit),
    139       FXPT_TYPE::BezierTo, false);
    140 
    141   param->m_pPath->AppendPoint(
    142       CFX_PointF((control->x + (to->x - control->x) / 3) / param->m_CoordUnit,
    143                  (control->y + (to->y - control->y) / 3) / param->m_CoordUnit),
    144       FXPT_TYPE::BezierTo, false);
    145 
    146   param->m_pPath->AppendPoint(
    147       CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
    148       FXPT_TYPE::BezierTo, false);
    149 
    150   param->m_CurX = to->x;
    151   param->m_CurY = to->y;
    152   return 0;
    153 }
    154 
    155 int Outline_CubicTo(const FXFT_Vector* control1,
    156                     const FXFT_Vector* control2,
    157                     const FXFT_Vector* to,
    158                     void* user) {
    159   OUTLINE_PARAMS* param = static_cast<OUTLINE_PARAMS*>(user);
    160 
    161   param->m_pPath->AppendPoint(CFX_PointF(control1->x / param->m_CoordUnit,
    162                                          control1->y / param->m_CoordUnit),
    163                               FXPT_TYPE::BezierTo, false);
    164 
    165   param->m_pPath->AppendPoint(CFX_PointF(control2->x / param->m_CoordUnit,
    166                                          control2->y / param->m_CoordUnit),
    167                               FXPT_TYPE::BezierTo, false);
    168 
    169   param->m_pPath->AppendPoint(
    170       CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
    171       FXPT_TYPE::BezierTo, false);
    172 
    173   param->m_CurX = to->x;
    174   param->m_CurY = to->y;
    175   return 0;
    176 }
    177 
    178 }  // namespace
    179 
    180 const char CFX_Font::s_AngleSkew[] = {
    181     0,  2,  3,  5,  7,  9,  11, 12, 14, 16, 18, 19, 21, 23, 25,
    182     27, 29, 31, 32, 34, 36, 38, 40, 42, 45, 47, 49, 51, 53, 55,
    183 };
    184 
    185 const uint8_t CFX_Font::s_WeightPow[] = {
    186     0,  3,  6,  7,  8,  9,  11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22,
    187     23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 36, 37,
    188     37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42,
    189     42, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47,
    190     47, 47, 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 50,
    191     51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53,
    192 };
    193 
    194 const uint8_t CFX_Font::s_WeightPow_11[] = {
    195     0,  4,  7,  8,  9,  10, 12, 13, 15, 17, 18, 19, 20, 21, 22, 23, 24,
    196     25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 39, 40, 40, 41,
    197     41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46,
    198     46, 43, 47, 47, 48, 48, 48, 48, 45, 50, 50, 50, 46, 51, 51, 51, 52,
    199     52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55,
    200     56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58,
    201 };
    202 
    203 const uint8_t CFX_Font::s_WeightPow_SHIFTJIS[] = {
    204     0,  0,  1,  2,  3,  4,  5,  7,  8,  10, 11, 13, 14, 16, 17, 19, 21,
    205     22, 24, 26, 28, 30, 32, 33, 35, 37, 39, 41, 43, 45, 48, 48, 48, 48,
    206     49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 52, 53,
    207     53, 53, 53, 53, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 56, 56, 56,
    208     56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 58,
    209     59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60,
    210 };
    211 
    212 CFX_Font::CFX_Font()
    213     :
    214       m_Face(nullptr),
    215       m_FaceCache(nullptr),
    216       m_pFontData(nullptr),
    217       m_pGsubData(nullptr),
    218       m_dwSize(0),
    219 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
    220       m_pPlatformFont(nullptr),
    221 #endif
    222       m_bEmbedded(false),
    223       m_bVertical(false) {
    224 }
    225 
    226 #ifdef PDF_ENABLE_XFA
    227 void CFX_Font::SetFace(FXFT_Face face) {
    228   ClearFaceCache();
    229   m_Face = face;
    230 }
    231 
    232 void CFX_Font::SetSubstFont(std::unique_ptr<CFX_SubstFont> subst) {
    233   m_pSubstFont = std::move(subst);
    234 }
    235 #endif  // PDF_ENABLE_XFA
    236 
    237 CFX_Font::~CFX_Font() {
    238   if (m_Face) {
    239 #ifndef PDF_ENABLE_XFA
    240     if (FXFT_Get_Face_External_Stream(m_Face)) {
    241       FXFT_Clear_Face_External_Stream(m_Face);
    242     }
    243 #endif  // PDF_ENABLE_XFA
    244     DeleteFace();
    245   }
    246 #if _FX_PLATFORM_ == _FX_PLATFORM_APPLE_
    247   ReleasePlatformResource();
    248 #endif
    249 }
    250 
    251 void CFX_Font::DeleteFace() {
    252   ClearFaceCache();
    253   if (m_bEmbedded)
    254     FXFT_Done_Face(m_Face);
    255   else
    256     CFX_GEModule::Get()->GetFontMgr()->ReleaseFace(m_Face);
    257   m_Face = nullptr;
    258 }
    259 
    260 void CFX_Font::LoadSubst(const ByteString& face_name,
    261                          bool bTrueType,
    262                          uint32_t flags,
    263                          int weight,
    264                          int italic_angle,
    265                          int CharsetCP,
    266                          bool bVertical) {
    267   m_bEmbedded = false;
    268   m_bVertical = bVertical;
    269   m_pSubstFont = pdfium::MakeUnique<CFX_SubstFont>();
    270   m_Face = CFX_GEModule::Get()->GetFontMgr()->FindSubstFont(
    271       face_name, bTrueType, flags, weight, italic_angle, CharsetCP,
    272       m_pSubstFont.get());
    273   if (m_Face) {
    274     m_pFontData = FXFT_Get_Face_Stream_Base(m_Face);
    275     m_dwSize = FXFT_Get_Face_Stream_Size(m_Face);
    276   }
    277 }
    278 
    279 #ifdef PDF_ENABLE_XFA
    280 bool CFX_Font::LoadFile(const RetainPtr<IFX_SeekableReadStream>& pFile,
    281                         int nFaceIndex) {
    282   m_bEmbedded = false;
    283 
    284   CFX_FontMgr* pFontMgr = CFX_GEModule::Get()->GetFontMgr();
    285   pFontMgr->InitFTLibrary();
    286 
    287   FXFT_Library library = pFontMgr->GetFTLibrary();
    288   std::unique_ptr<FXFT_StreamRec> stream;
    289   if (!LoadFileImp(library, &m_Face, pFile, nFaceIndex, &stream))
    290     return false;
    291 
    292   m_pOwnedStream = std::move(stream);
    293   FXFT_Set_Pixel_Sizes(m_Face, 0, 64);
    294   return true;
    295 }
    296 #endif  // PDF_ENABLE_XFA
    297 
    298 int CFX_Font::GetGlyphWidth(uint32_t glyph_index) {
    299   if (!m_Face)
    300     return 0;
    301   if (m_pSubstFont && m_pSubstFont->m_bFlagMM)
    302     AdjustMMParams(glyph_index, 0, 0);
    303   int err = FXFT_Load_Glyph(
    304       m_Face, glyph_index,
    305       FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
    306   if (err)
    307     return 0;
    308 
    309   int horiAdvance = FXFT_Get_Glyph_HoriAdvance(m_Face);
    310   if (horiAdvance < kThousandthMinInt || horiAdvance > kThousandthMaxInt)
    311     return 0;
    312 
    313   return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face), horiAdvance);
    314 }
    315 
    316 bool CFX_Font::LoadEmbedded(const uint8_t* data, uint32_t size) {
    317   std::vector<uint8_t> temp(data, data + size);
    318   m_pFontDataAllocation.swap(temp);
    319   m_Face = FT_LoadFont(m_pFontDataAllocation.data(), size);
    320   m_pFontData = m_pFontDataAllocation.data();
    321   m_bEmbedded = true;
    322   m_dwSize = size;
    323   return !!m_Face;
    324 }
    325 
    326 bool CFX_Font::IsTTFont() const {
    327   return m_Face && FXFT_Is_Face_TT_OT(m_Face) == FXFT_FACE_FLAG_SFNT;
    328 }
    329 
    330 int CFX_Font::GetAscent() const {
    331   if (!m_Face)
    332     return 0;
    333 
    334   int ascender = FXFT_Get_Face_Ascender(m_Face);
    335   if (ascender < kThousandthMinInt || ascender > kThousandthMaxInt)
    336     return 0;
    337 
    338   return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face), ascender);
    339 }
    340 
    341 int CFX_Font::GetDescent() const {
    342   if (!m_Face)
    343     return 0;
    344 
    345   int descender = FXFT_Get_Face_Descender(m_Face);
    346   if (descender < kThousandthMinInt || descender > kThousandthMaxInt)
    347     return 0;
    348 
    349   return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face), descender);
    350 }
    351 
    352 bool CFX_Font::GetGlyphBBox(uint32_t glyph_index, FX_RECT& bbox) {
    353   if (!m_Face)
    354     return false;
    355 
    356   if (FXFT_Is_Face_Tricky(m_Face)) {
    357     int error = FXFT_Set_Char_Size(m_Face, 0, 1000 * 64, 72, 72);
    358     if (error)
    359       return false;
    360 
    361     error = FXFT_Load_Glyph(m_Face, glyph_index,
    362                             FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
    363     if (error)
    364       return false;
    365 
    366     FXFT_BBox cbox;
    367     FT_Glyph glyph;
    368     error = FXFT_Get_Glyph(m_Face->glyph, &glyph);
    369     if (error)
    370       return false;
    371 
    372     FXFT_Glyph_Get_CBox(glyph, FXFT_GLYPH_BBOX_PIXELS, &cbox);
    373     int pixel_size_x = m_Face->size->metrics.x_ppem,
    374         pixel_size_y = m_Face->size->metrics.y_ppem;
    375     if (pixel_size_x == 0 || pixel_size_y == 0) {
    376       bbox.left = cbox.xMin;
    377       bbox.right = cbox.xMax;
    378       bbox.top = cbox.yMax;
    379       bbox.bottom = cbox.yMin;
    380     } else {
    381       bbox.left = cbox.xMin * 1000 / pixel_size_x;
    382       bbox.right = cbox.xMax * 1000 / pixel_size_x;
    383       bbox.top = cbox.yMax * 1000 / pixel_size_y;
    384       bbox.bottom = cbox.yMin * 1000 / pixel_size_y;
    385     }
    386     bbox.top = std::min(bbox.top,
    387                         static_cast<int32_t>(FXFT_Get_Face_Ascender(m_Face)));
    388     bbox.bottom = std::max(
    389         bbox.bottom, static_cast<int32_t>(FXFT_Get_Face_Descender(m_Face)));
    390     FT_Done_Glyph(glyph);
    391     return FXFT_Set_Pixel_Sizes(m_Face, 0, 64) == 0;
    392   }
    393   if (FXFT_Load_Glyph(
    394           m_Face, glyph_index,
    395           FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH)) {
    396     return false;
    397   }
    398   int em = FXFT_Get_Face_UnitsPerEM(m_Face);
    399   if (em == 0) {
    400     bbox.left = FXFT_Get_Glyph_HoriBearingX(m_Face);
    401     bbox.bottom = FXFT_Get_Glyph_HoriBearingY(m_Face);
    402     bbox.top = bbox.bottom - FXFT_Get_Glyph_Height(m_Face);
    403     bbox.right = bbox.left + FXFT_Get_Glyph_Width(m_Face);
    404   } else {
    405     bbox.left = FXFT_Get_Glyph_HoriBearingX(m_Face) * 1000 / em;
    406     bbox.top =
    407         (FXFT_Get_Glyph_HoriBearingY(m_Face) - FXFT_Get_Glyph_Height(m_Face)) *
    408         1000 / em;
    409     bbox.right =
    410         (FXFT_Get_Glyph_HoriBearingX(m_Face) + FXFT_Get_Glyph_Width(m_Face)) *
    411         1000 / em;
    412     bbox.bottom = (FXFT_Get_Glyph_HoriBearingY(m_Face)) * 1000 / em;
    413   }
    414   return true;
    415 }
    416 
    417 bool CFX_Font::IsItalic() const {
    418   if (!m_Face)
    419     return false;
    420   if (FXFT_Is_Face_Italic(m_Face) == FXFT_STYLE_FLAG_ITALIC)
    421     return true;
    422 
    423   ByteString str(FXFT_Get_Face_Style_Name(m_Face));
    424   str.MakeLower();
    425   return str.Contains("italic");
    426 }
    427 
    428 bool CFX_Font::IsBold() const {
    429   return m_Face && FXFT_Is_Face_Bold(m_Face) == FXFT_STYLE_FLAG_BOLD;
    430 }
    431 
    432 bool CFX_Font::IsFixedWidth() const {
    433   return m_Face && FXFT_Is_Face_fixedwidth(m_Face) != 0;
    434 }
    435 
    436 ByteString CFX_Font::GetPsName() const {
    437   if (!m_Face)
    438     return ByteString();
    439 
    440   ByteString psName = FXFT_Get_Postscript_Name(m_Face);
    441   if (psName.IsEmpty())
    442     psName = "Untitled";
    443   return psName;
    444 }
    445 
    446 ByteString CFX_Font::GetFamilyName() const {
    447   if (!m_Face && !m_pSubstFont)
    448     return ByteString();
    449   if (m_Face)
    450     return ByteString(FXFT_Get_Face_Family_Name(m_Face));
    451 
    452   return m_pSubstFont->m_Family;
    453 }
    454 
    455 ByteString CFX_Font::GetFaceName() const {
    456   if (!m_Face && !m_pSubstFont)
    457     return ByteString();
    458   if (m_Face) {
    459     ByteString style = ByteString(FXFT_Get_Face_Style_Name(m_Face));
    460     ByteString facename = GetFamilyName();
    461     if (facename.IsEmpty())
    462       facename = "Untitled";
    463     if (!style.IsEmpty() && style != "Regular")
    464       facename += " " + style;
    465     return facename;
    466   }
    467   return m_pSubstFont->m_Family;
    468 }
    469 
    470 bool CFX_Font::GetBBox(FX_RECT& bbox) {
    471   if (!m_Face)
    472     return false;
    473 
    474   int em = FXFT_Get_Face_UnitsPerEM(m_Face);
    475   if (em == 0) {
    476     bbox.left = FXFT_Get_Face_xMin(m_Face);
    477     bbox.bottom = FXFT_Get_Face_yMax(m_Face);
    478     bbox.top = FXFT_Get_Face_yMin(m_Face);
    479     bbox.right = FXFT_Get_Face_xMax(m_Face);
    480   } else {
    481     bbox.left = FXFT_Get_Face_xMin(m_Face) * 1000 / em;
    482     bbox.top = FXFT_Get_Face_yMin(m_Face) * 1000 / em;
    483     bbox.right = FXFT_Get_Face_xMax(m_Face) * 1000 / em;
    484     bbox.bottom = FXFT_Get_Face_yMax(m_Face) * 1000 / em;
    485   }
    486   return true;
    487 }
    488 
    489 CFX_FaceCache* CFX_Font::GetFaceCache() const {
    490   if (!m_FaceCache)
    491     m_FaceCache = CFX_GEModule::Get()->GetFontCache()->GetCachedFace(this);
    492   return m_FaceCache.Get();
    493 }
    494 
    495 void CFX_Font::ClearFaceCache() {
    496   if (!m_FaceCache)
    497     return;
    498 
    499   m_FaceCache = nullptr;
    500   CFX_GEModule::Get()->GetFontCache()->ReleaseCachedFace(this);
    501 }
    502 
    503 void CFX_Font::AdjustMMParams(int glyph_index,
    504                               int dest_width,
    505                               int weight) const {
    506   FXFT_MM_Var pMasters = nullptr;
    507   FXFT_Get_MM_Var(m_Face, &pMasters);
    508   if (!pMasters)
    509     return;
    510 
    511   long coords[2];
    512   if (weight == 0)
    513     coords[0] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 0)) / 65536;
    514   else
    515     coords[0] = weight;
    516 
    517   if (dest_width == 0) {
    518     coords[1] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
    519   } else {
    520     int min_param = FXFT_Get_MM_Axis_Min(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
    521     int max_param = FXFT_Get_MM_Axis_Max(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
    522     coords[1] = min_param;
    523     FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
    524     FXFT_Load_Glyph(m_Face, glyph_index,
    525                     FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
    526     int min_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 /
    527                     FXFT_Get_Face_UnitsPerEM(m_Face);
    528     coords[1] = max_param;
    529     FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
    530     FXFT_Load_Glyph(m_Face, glyph_index,
    531                     FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
    532     int max_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 /
    533                     FXFT_Get_Face_UnitsPerEM(m_Face);
    534     if (max_width == min_width) {
    535       FXFT_Free(m_Face, pMasters);
    536       return;
    537     }
    538     int param = min_param + (max_param - min_param) * (dest_width - min_width) /
    539                                 (max_width - min_width);
    540     coords[1] = param;
    541   }
    542   FXFT_Free(m_Face, pMasters);
    543   FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
    544 }
    545 
    546 CFX_PathData* CFX_Font::LoadGlyphPathImpl(uint32_t glyph_index,
    547                                           int dest_width) const {
    548   if (!m_Face)
    549     return nullptr;
    550   FXFT_Set_Pixel_Sizes(m_Face, 0, 64);
    551   FXFT_Matrix ft_matrix = {65536, 0, 0, 65536};
    552   if (m_pSubstFont) {
    553     if (m_pSubstFont->m_ItalicAngle) {
    554       int skew = m_pSubstFont->m_ItalicAngle;
    555       // |skew| is nonpositive so |-skew| is used as the index. We need to make
    556       // sure |skew| != INT_MIN since -INT_MIN is undefined.
    557       if (skew <= 0 && skew != std::numeric_limits<int>::min() &&
    558           static_cast<size_t>(-skew) < kAngleSkewArraySize) {
    559         skew = -s_AngleSkew[-skew];
    560       } else {
    561         skew = -58;
    562       }
    563       if (m_bVertical)
    564         ft_matrix.yx += ft_matrix.yy * skew / 100;
    565       else
    566         ft_matrix.xy -= ft_matrix.xx * skew / 100;
    567     }
    568     if (m_pSubstFont->m_bFlagMM)
    569       AdjustMMParams(glyph_index, dest_width, m_pSubstFont->m_Weight);
    570   }
    571   ScopedFontTransform scoped_transform(m_Face, &ft_matrix);
    572   int load_flags = FXFT_LOAD_NO_BITMAP;
    573   if (!(m_Face->face_flags & FT_FACE_FLAG_SFNT) || !FT_IS_TRICKY(m_Face))
    574     load_flags |= FT_LOAD_NO_HINTING;
    575   if (FXFT_Load_Glyph(m_Face, glyph_index, load_flags))
    576     return nullptr;
    577   if (m_pSubstFont && !m_pSubstFont->m_bFlagMM &&
    578       m_pSubstFont->m_Weight > 400) {
    579     uint32_t index = (m_pSubstFont->m_Weight - 400) / 10;
    580     index = std::min(index, static_cast<uint32_t>(kWeightPowArraySize - 1));
    581     int level = 0;
    582     if (m_pSubstFont->m_Charset == FX_CHARSET_ShiftJIS)
    583       level = s_WeightPow_SHIFTJIS[index] * 2 * 65536 / 36655;
    584     else
    585       level = s_WeightPow[index] * 2;
    586     FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
    587   }
    588 
    589   FXFT_Outline_Funcs funcs;
    590   funcs.move_to = Outline_MoveTo;
    591   funcs.line_to = Outline_LineTo;
    592   funcs.conic_to = Outline_ConicTo;
    593   funcs.cubic_to = Outline_CubicTo;
    594   funcs.shift = 0;
    595   funcs.delta = 0;
    596 
    597   OUTLINE_PARAMS params;
    598   auto pPath = pdfium::MakeUnique<CFX_PathData>();
    599   params.m_pPath = pPath.get();
    600   params.m_CurX = params.m_CurY = 0;
    601   params.m_CoordUnit = 64 * 64.0;
    602 
    603   FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, &params);
    604   if (pPath->GetPoints().empty())
    605     return nullptr;
    606 
    607   Outline_CheckEmptyContour(&params);
    608   pPath->ClosePath();
    609 
    610   return pPath.release();
    611 }
    612 
    613 const CFX_GlyphBitmap* CFX_Font::LoadGlyphBitmap(uint32_t glyph_index,
    614                                                  bool bFontStyle,
    615                                                  const CFX_Matrix* pMatrix,
    616                                                  int dest_width,
    617                                                  int anti_alias,
    618                                                  int& text_flags) const {
    619   return GetFaceCache()->LoadGlyphBitmap(this, glyph_index, bFontStyle, pMatrix,
    620                                          dest_width, anti_alias, text_flags);
    621 }
    622 
    623 const CFX_PathData* CFX_Font::LoadGlyphPath(uint32_t glyph_index,
    624                                             int dest_width) const {
    625   return GetFaceCache()->LoadGlyphPath(this, glyph_index, dest_width);
    626 }
    627 
    628 #if defined _SKIA_SUPPORT_ || _SKIA_SUPPORT_PATHS_
    629 CFX_TypeFace* CFX_Font::GetDeviceCache() const {
    630   return GetFaceCache()->GetDeviceCache(this);
    631 }
    632 #endif
    633