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