xref: /aosp_15_r20/external/pdfium/core/fxge/cfx_font.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2014 The PDFium Authors
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 <stdint.h>
10 
11 #include <algorithm>
12 #include <limits>
13 #include <memory>
14 #include <utility>
15 
16 #include "build/build_config.h"
17 #include "core/fxcrt/data_vector.h"
18 #include "core/fxcrt/fx_codepage.h"
19 #include "core/fxcrt/fx_stream.h"
20 #include "core/fxcrt/unowned_ptr.h"
21 #include "core/fxge/cfx_fontcache.h"
22 #include "core/fxge/cfx_fontmapper.h"
23 #include "core/fxge/cfx_fontmgr.h"
24 #include "core/fxge/cfx_gemodule.h"
25 #include "core/fxge/cfx_glyphcache.h"
26 #include "core/fxge/cfx_path.h"
27 #include "core/fxge/cfx_substfont.h"
28 #include "core/fxge/fx_font.h"
29 #include "core/fxge/scoped_font_transform.h"
30 #include "third_party/base/check.h"
31 #include "third_party/base/containers/span.h"
32 #include "third_party/base/numerics/safe_conversions.h"
33 
34 #define EM_ADJUST(em, a) (em == 0 ? (a) : (a)*1000 / em)
35 
36 namespace {
37 
38 constexpr int kThousandthMinInt = std::numeric_limits<int>::min() / 1000;
39 constexpr int kThousandthMaxInt = std::numeric_limits<int>::max() / 1000;
40 
41 struct OUTLINE_PARAMS {
42   UnownedPtr<CFX_Path> m_pPath;
43   FT_Pos m_CurX;
44   FT_Pos m_CurY;
45   float m_CoordUnit;
46 };
47 
FXRectFromFTPos(FT_Pos left,FT_Pos top,FT_Pos right,FT_Pos bottom)48 FX_RECT FXRectFromFTPos(FT_Pos left, FT_Pos top, FT_Pos right, FT_Pos bottom) {
49   return FX_RECT(pdfium::base::checked_cast<int32_t>(left),
50                  pdfium::base::checked_cast<int32_t>(top),
51                  pdfium::base::checked_cast<int32_t>(right),
52                  pdfium::base::checked_cast<int32_t>(bottom));
53 }
54 
ScaledFXRectFromFTPos(FT_Pos left,FT_Pos top,FT_Pos right,FT_Pos bottom,int x_scale,int y_scale)55 FX_RECT ScaledFXRectFromFTPos(FT_Pos left,
56                               FT_Pos top,
57                               FT_Pos right,
58                               FT_Pos bottom,
59                               int x_scale,
60                               int y_scale) {
61   if (x_scale == 0 || y_scale == 0)
62     return FXRectFromFTPos(left, top, right, bottom);
63 
64   return FXRectFromFTPos(left * 1000 / x_scale, top * 1000 / y_scale,
65                          right * 1000 / x_scale, bottom * 1000 / y_scale);
66 }
67 
68 #ifdef PDF_ENABLE_XFA
FTStreamRead(FXFT_StreamRec * stream,unsigned long offset,unsigned char * buffer,unsigned long count)69 unsigned long FTStreamRead(FXFT_StreamRec* stream,
70                            unsigned long offset,
71                            unsigned char* buffer,
72                            unsigned long count) {
73   if (count == 0)
74     return 0;
75 
76   IFX_SeekableReadStream* pFile =
77       static_cast<IFX_SeekableReadStream*>(stream->descriptor.pointer);
78   return pFile && pFile->ReadBlockAtOffset({buffer, count}, offset) ? count : 0;
79 }
80 
FTStreamClose(FXFT_StreamRec * stream)81 void FTStreamClose(FXFT_StreamRec* stream) {}
82 #endif  // PDF_ENABLE_XFA
83 
Outline_CheckEmptyContour(OUTLINE_PARAMS * param)84 void Outline_CheckEmptyContour(OUTLINE_PARAMS* param) {
85   size_t size;
86   {
87     pdfium::span<const CFX_Path::Point> points = param->m_pPath->GetPoints();
88     size = points.size();
89 
90     if (size >= 2 &&
91         points[size - 2].IsTypeAndOpen(CFX_Path::Point::Type::kMove) &&
92         points[size - 2].m_Point == points[size - 1].m_Point) {
93       size -= 2;
94     }
95     if (size >= 4 &&
96         points[size - 4].IsTypeAndOpen(CFX_Path::Point::Type::kMove) &&
97         points[size - 3].IsTypeAndOpen(CFX_Path::Point::Type::kBezier) &&
98         points[size - 3].m_Point == points[size - 4].m_Point &&
99         points[size - 2].m_Point == points[size - 4].m_Point &&
100         points[size - 1].m_Point == points[size - 4].m_Point) {
101       size -= 4;
102     }
103   }
104   // Only safe after |points| has been destroyed.
105   param->m_pPath->GetPoints().resize(size);
106 }
107 
Outline_MoveTo(const FT_Vector * to,void * user)108 int Outline_MoveTo(const FT_Vector* to, void* user) {
109   OUTLINE_PARAMS* param = static_cast<OUTLINE_PARAMS*>(user);
110 
111   Outline_CheckEmptyContour(param);
112 
113   param->m_pPath->ClosePath();
114   param->m_pPath->AppendPoint(
115       CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
116       CFX_Path::Point::Type::kMove);
117 
118   param->m_CurX = to->x;
119   param->m_CurY = to->y;
120   return 0;
121 }
122 
Outline_LineTo(const FT_Vector * to,void * user)123 int Outline_LineTo(const FT_Vector* to, void* user) {
124   OUTLINE_PARAMS* param = static_cast<OUTLINE_PARAMS*>(user);
125 
126   param->m_pPath->AppendPoint(
127       CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
128       CFX_Path::Point::Type::kLine);
129 
130   param->m_CurX = to->x;
131   param->m_CurY = to->y;
132   return 0;
133 }
134 
Outline_ConicTo(const FT_Vector * control,const FT_Vector * to,void * user)135 int Outline_ConicTo(const FT_Vector* control, const FT_Vector* to, void* user) {
136   OUTLINE_PARAMS* param = static_cast<OUTLINE_PARAMS*>(user);
137 
138   param->m_pPath->AppendPoint(
139       CFX_PointF((param->m_CurX + (control->x - param->m_CurX) * 2 / 3) /
140                      param->m_CoordUnit,
141                  (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) /
142                      param->m_CoordUnit),
143       CFX_Path::Point::Type::kBezier);
144 
145   param->m_pPath->AppendPoint(
146       CFX_PointF((control->x + (to->x - control->x) / 3) / param->m_CoordUnit,
147                  (control->y + (to->y - control->y) / 3) / param->m_CoordUnit),
148       CFX_Path::Point::Type::kBezier);
149 
150   param->m_pPath->AppendPoint(
151       CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
152       CFX_Path::Point::Type::kBezier);
153 
154   param->m_CurX = to->x;
155   param->m_CurY = to->y;
156   return 0;
157 }
158 
Outline_CubicTo(const FT_Vector * control1,const FT_Vector * control2,const FT_Vector * to,void * user)159 int Outline_CubicTo(const FT_Vector* control1,
160                     const FT_Vector* control2,
161                     const FT_Vector* to,
162                     void* user) {
163   OUTLINE_PARAMS* param = static_cast<OUTLINE_PARAMS*>(user);
164 
165   param->m_pPath->AppendPoint(CFX_PointF(control1->x / param->m_CoordUnit,
166                                          control1->y / param->m_CoordUnit),
167                               CFX_Path::Point::Type::kBezier);
168 
169   param->m_pPath->AppendPoint(CFX_PointF(control2->x / param->m_CoordUnit,
170                                          control2->y / param->m_CoordUnit),
171                               CFX_Path::Point::Type::kBezier);
172 
173   param->m_pPath->AppendPoint(
174       CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
175       CFX_Path::Point::Type::kBezier);
176 
177   param->m_CurX = to->x;
178   param->m_CurY = to->y;
179   return 0;
180 }
181 
ShouldAppendStyle(const ByteString & style)182 bool ShouldAppendStyle(const ByteString& style) {
183   return !style.IsEmpty() && style != "Regular";
184 }
185 
186 constexpr int8_t kAngleSkew[] = {
187     -0,  -2,  -3,  -5,  -7,  -9,  -11, -12, -14, -16, -18, -19, -21, -23, -25,
188     -27, -29, -31, -32, -34, -36, -38, -40, -42, -45, -47, -49, -51, -53, -55,
189 };
190 
191 constexpr uint8_t kWeightPow[] = {
192     0,   6,   12,  14,  16,  18,  22,  24,  28,  30,  32,  34,  36,  38,  40,
193     42,  44,  46,  48,  50,  52,  54,  56,  58,  60,  62,  64,  66,  68,  70,
194     70,  72,  72,  74,  74,  74,  76,  76,  76,  78,  78,  78,  80,  80,  80,
195     82,  82,  82,  84,  84,  84,  84,  86,  86,  86,  88,  88,  88,  88,  90,
196     90,  90,  90,  92,  92,  92,  92,  94,  94,  94,  94,  96,  96,  96,  96,
197     96,  98,  98,  98,  98,  100, 100, 100, 100, 100, 102, 102, 102, 102, 102,
198     104, 104, 104, 104, 104, 106, 106, 106, 106, 106,
199 };
200 
201 constexpr uint8_t kWeightPow11[] = {
202     0,  4,  7,  8,  9,  10, 12, 13, 15, 17, 18, 19, 20, 21, 22, 23, 24,
203     25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 39, 40, 40, 41,
204     41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46,
205     46, 43, 47, 47, 48, 48, 48, 48, 45, 50, 50, 50, 46, 51, 51, 51, 52,
206     52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55,
207     56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58,
208 };
209 
210 constexpr uint8_t kWeightPowShiftJis[] = {
211     0,   0,   2,   4,   6,   8,   10,  14,  16,  20,  22,  26,  28,  32,  34,
212     38,  42,  44,  48,  52,  56,  60,  64,  66,  70,  74,  78,  82,  86,  90,
213     96,  96,  96,  96,  98,  98,  98,  100, 100, 100, 100, 102, 102, 102, 102,
214     104, 104, 104, 104, 104, 106, 106, 106, 106, 106, 108, 108, 108, 108, 108,
215     110, 110, 110, 110, 110, 112, 112, 112, 112, 112, 112, 114, 114, 114, 114,
216     114, 114, 114, 116, 116, 116, 116, 116, 116, 116, 118, 118, 118, 118, 118,
217     118, 118, 120, 120, 120, 120, 120, 120, 120, 120,
218 };
219 
220 constexpr size_t kWeightPowArraySize = 100;
221 static_assert(kWeightPowArraySize == std::size(kWeightPow), "Wrong size");
222 static_assert(kWeightPowArraySize == std::size(kWeightPow11), "Wrong size");
223 static_assert(kWeightPowArraySize == std::size(kWeightPowShiftJis),
224               "Wrong size");
225 
226 }  // namespace
227 
228 const CFX_Font::CharsetFontMap CFX_Font::kDefaultTTFMap[] = {
229     {static_cast<int>(FX_Charset::kANSI), kDefaultAnsiFontName},
230     {static_cast<int>(FX_Charset::kChineseSimplified), "SimSun"},
231     {static_cast<int>(FX_Charset::kChineseTraditional), "MingLiU"},
232     {static_cast<int>(FX_Charset::kShiftJIS), "MS Gothic"},
233     {static_cast<int>(FX_Charset::kHangul), "Batang"},
234     {static_cast<int>(FX_Charset::kMSWin_Cyrillic), "Arial"},
235 #if BUILDFLAG(IS_WIN)
236     {static_cast<int>(FX_Charset::kMSWin_EasternEuropean), "Tahoma"},
237 #else
238     {static_cast<int>(FX_Charset::kMSWin_EasternEuropean), "Arial"},
239 #endif
240     {static_cast<int>(FX_Charset::kMSWin_Arabic), "Arial"},
241     {-1, nullptr}};
242 
243 // static
244 const char CFX_Font::kUntitledFontName[] = "Untitled";
245 
246 // static
247 const char CFX_Font::kDefaultAnsiFontName[] = "Helvetica";
248 
249 // static
250 const char CFX_Font::kUniversalDefaultFontName[] = "Arial Unicode MS";
251 
252 // static
GetDefaultFontNameByCharset(FX_Charset nCharset)253 ByteString CFX_Font::GetDefaultFontNameByCharset(FX_Charset nCharset) {
254   for (size_t i = 0; i < std::size(kDefaultTTFMap) - 1; ++i) {
255     if (static_cast<int>(nCharset) == kDefaultTTFMap[i].charset)
256       return kDefaultTTFMap[i].fontname;
257   }
258   return kUniversalDefaultFontName;
259 }
260 
261 // static
GetCharSetFromUnicode(uint16_t word)262 FX_Charset CFX_Font::GetCharSetFromUnicode(uint16_t word) {
263   // to avoid CJK Font to show ASCII
264   if (word < 0x7F)
265     return FX_Charset::kANSI;
266 
267   // find new charset
268   if ((word >= 0x4E00 && word <= 0x9FA5) ||
269       (word >= 0xE7C7 && word <= 0xE7F3) ||
270       (word >= 0x3000 && word <= 0x303F) ||
271       (word >= 0x2000 && word <= 0x206F)) {
272     return FX_Charset::kChineseSimplified;
273   }
274 
275   if (((word >= 0x3040) && (word <= 0x309F)) ||
276       ((word >= 0x30A0) && (word <= 0x30FF)) ||
277       ((word >= 0x31F0) && (word <= 0x31FF)) ||
278       ((word >= 0xFF00) && (word <= 0xFFEF))) {
279     return FX_Charset::kShiftJIS;
280   }
281 
282   if (((word >= 0xAC00) && (word <= 0xD7AF)) ||
283       ((word >= 0x1100) && (word <= 0x11FF)) ||
284       ((word >= 0x3130) && (word <= 0x318F))) {
285     return FX_Charset::kHangul;
286   }
287 
288   if (word >= 0x0E00 && word <= 0x0E7F)
289     return FX_Charset::kThai;
290 
291   if ((word >= 0x0370 && word <= 0x03FF) || (word >= 0x1F00 && word <= 0x1FFF))
292     return FX_Charset::kMSWin_Greek;
293 
294   if ((word >= 0x0600 && word <= 0x06FF) || (word >= 0xFB50 && word <= 0xFEFC))
295     return FX_Charset::kMSWin_Arabic;
296 
297   if (word >= 0x0590 && word <= 0x05FF)
298     return FX_Charset::kMSWin_Hebrew;
299 
300   if (word >= 0x0400 && word <= 0x04FF)
301     return FX_Charset::kMSWin_Cyrillic;
302 
303   if (word >= 0x0100 && word <= 0x024F)
304     return FX_Charset::kMSWin_EasternEuropean;
305 
306   if (word >= 0x1E00 && word <= 0x1EFF)
307     return FX_Charset::kMSWin_Vietnamese;
308 
309   return FX_Charset::kANSI;
310 }
311 
312 CFX_Font::CFX_Font() = default;
313 
GetSubstFontItalicAngle() const314 int CFX_Font::GetSubstFontItalicAngle() const {
315   CFX_SubstFont* subst_font = GetSubstFont();
316   return subst_font ? subst_font->m_ItalicAngle : 0;
317 }
318 
319 #ifdef PDF_ENABLE_XFA
LoadFile(RetainPtr<IFX_SeekableReadStream> pFile,int nFaceIndex)320 bool CFX_Font::LoadFile(RetainPtr<IFX_SeekableReadStream> pFile,
321                         int nFaceIndex) {
322   m_bEmbedded = false;
323   m_ObjectTag = 0;
324 
325   auto pStreamRec = std::make_unique<FXFT_StreamRec>();
326   pStreamRec->base = nullptr;
327   pStreamRec->size = static_cast<unsigned long>(pFile->GetSize());
328   pStreamRec->pos = 0;
329   pStreamRec->descriptor.pointer = static_cast<void*>(pFile.Get());
330   pStreamRec->close = FTStreamClose;
331   pStreamRec->read = FTStreamRead;
332 
333   FT_Open_Args args;
334   args.flags = FT_OPEN_STREAM;
335   args.stream = pStreamRec.get();
336 
337   m_Face = CFX_Face::Open(CFX_GEModule::Get()->GetFontMgr()->GetFTLibrary(),
338                           &args, nFaceIndex);
339   if (!m_Face)
340     return false;
341 
342   m_pOwnedFile = std::move(pFile);
343   m_pOwnedStreamRec = std::move(pStreamRec);
344   FT_Set_Pixel_Sizes(m_Face->GetRec(), 0, 64);
345   return true;
346 }
347 
348 #if !BUILDFLAG(IS_WIN)
SetFace(RetainPtr<CFX_Face> face)349 void CFX_Font::SetFace(RetainPtr<CFX_Face> face) {
350   ClearGlyphCache();
351   m_ObjectTag = 0;
352   m_Face = face;
353 }
354 
SetSubstFont(std::unique_ptr<CFX_SubstFont> subst)355 void CFX_Font::SetSubstFont(std::unique_ptr<CFX_SubstFont> subst) {
356   m_pSubstFont = std::move(subst);
357 }
358 #endif  // !BUILDFLAG(IS_WIN)
359 #endif  // PDF_ENABLE_XFA
360 
~CFX_Font()361 CFX_Font::~CFX_Font() {
362   m_FontData = {};  // m_FontData can't outive m_Face.
363   m_Face.Reset();
364 
365 #if BUILDFLAG(IS_APPLE)
366   ReleasePlatformResource();
367 #endif
368 }
369 
LoadSubst(const ByteString & face_name,bool bTrueType,uint32_t flags,int weight,int italic_angle,FX_CodePage code_page,bool bVertical)370 void CFX_Font::LoadSubst(const ByteString& face_name,
371                          bool bTrueType,
372                          uint32_t flags,
373                          int weight,
374                          int italic_angle,
375                          FX_CodePage code_page,
376                          bool bVertical) {
377   m_bEmbedded = false;
378   m_bVertical = bVertical;
379   m_ObjectTag = 0;
380   m_pSubstFont = std::make_unique<CFX_SubstFont>();
381   m_Face = CFX_GEModule::Get()->GetFontMgr()->GetBuiltinMapper()->FindSubstFont(
382       face_name, bTrueType, flags, weight, italic_angle, code_page,
383       m_pSubstFont.get());
384   if (m_Face) {
385     m_FontData = {FXFT_Get_Face_Stream_Base(m_Face->GetRec()),
386                   FXFT_Get_Face_Stream_Size(m_Face->GetRec())};
387   }
388 }
389 
GetGlyphWidth(uint32_t glyph_index) const390 int CFX_Font::GetGlyphWidth(uint32_t glyph_index) const {
391   return GetGlyphWidth(glyph_index, 0, 0);
392 }
393 
GetGlyphWidth(uint32_t glyph_index,int dest_width,int weight) const394 int CFX_Font::GetGlyphWidth(uint32_t glyph_index,
395                             int dest_width,
396                             int weight) const {
397   return GetOrCreateGlyphCache()->GetGlyphWidth(this, glyph_index, dest_width,
398                                                 weight);
399 }
400 
GetGlyphWidthImpl(uint32_t glyph_index,int dest_width,int weight) const401 int CFX_Font::GetGlyphWidthImpl(uint32_t glyph_index,
402                                 int dest_width,
403                                 int weight) const {
404   if (!m_Face)
405     return 0;
406   if (m_pSubstFont && m_pSubstFont->IsBuiltInGenericFont())
407     AdjustMMParams(glyph_index, dest_width, weight);
408   int err =
409       FT_Load_Glyph(m_Face->GetRec(), glyph_index,
410                     FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
411   if (err)
412     return 0;
413 
414   FT_Pos horiAdvance = FXFT_Get_Glyph_HoriAdvance(m_Face->GetRec());
415   if (horiAdvance < kThousandthMinInt || horiAdvance > kThousandthMaxInt)
416     return 0;
417 
418   return static_cast<int>(
419       EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face->GetRec()), horiAdvance));
420 }
421 
LoadEmbedded(pdfium::span<const uint8_t> src_span,bool force_vertical,uint64_t object_tag)422 bool CFX_Font::LoadEmbedded(pdfium::span<const uint8_t> src_span,
423                             bool force_vertical,
424                             uint64_t object_tag) {
425   m_bVertical = force_vertical;
426   m_ObjectTag = object_tag;
427   m_FontDataAllocation = DataVector<uint8_t>(src_span.begin(), src_span.end());
428   m_Face = CFX_GEModule::Get()->GetFontMgr()->NewFixedFace(
429       nullptr, m_FontDataAllocation, 0);
430   m_bEmbedded = true;
431   m_FontData = m_FontDataAllocation;
432   return !!m_Face;
433 }
434 
IsTTFont() const435 bool CFX_Font::IsTTFont() const {
436   return m_Face && FXFT_Is_Face_TT_OT(m_Face->GetRec()) == FT_FACE_FLAG_SFNT;
437 }
438 
GetAscent() const439 int CFX_Font::GetAscent() const {
440   if (!m_Face)
441     return 0;
442 
443   int ascender = FXFT_Get_Face_Ascender(m_Face->GetRec());
444   if (ascender < kThousandthMinInt || ascender > kThousandthMaxInt)
445     return 0;
446 
447   return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face->GetRec()), ascender);
448 }
449 
GetDescent() const450 int CFX_Font::GetDescent() const {
451   if (!m_Face)
452     return 0;
453 
454   int descender = FXFT_Get_Face_Descender(m_Face->GetRec());
455   if (descender < kThousandthMinInt || descender > kThousandthMaxInt)
456     return 0;
457 
458   return EM_ADJUST(FXFT_Get_Face_UnitsPerEM(m_Face->GetRec()), descender);
459 }
460 
GetGlyphBBox(uint32_t glyph_index)461 absl::optional<FX_RECT> CFX_Font::GetGlyphBBox(uint32_t glyph_index) {
462   if (!m_Face)
463     return absl::nullopt;
464 
465   if (FXFT_Is_Face_Tricky(m_Face->GetRec())) {
466     int error = FT_Set_Char_Size(m_Face->GetRec(), 0, 1000 * 64, 72, 72);
467     if (error)
468       return absl::nullopt;
469 
470     error = FT_Load_Glyph(m_Face->GetRec(), glyph_index,
471                           FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
472     if (error)
473       return absl::nullopt;
474 
475     FT_Glyph glyph;
476     error = FT_Get_Glyph(m_Face->GetRec()->glyph, &glyph);
477     if (error)
478       return absl::nullopt;
479 
480     FT_BBox cbox;
481     FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &cbox);
482     int pixel_size_x = m_Face->GetRec()->size->metrics.x_ppem;
483     int pixel_size_y = m_Face->GetRec()->size->metrics.y_ppem;
484     FX_RECT result = ScaledFXRectFromFTPos(
485         cbox.xMin, cbox.yMax, cbox.xMax, cbox.yMin, pixel_size_x, pixel_size_y);
486     result.top =
487         std::min(result.top, pdfium::base::checked_cast<int32_t>(
488                                  FXFT_Get_Face_Ascender(m_Face->GetRec())));
489     result.bottom =
490         std::max(result.bottom, pdfium::base::checked_cast<int32_t>(
491                                     FXFT_Get_Face_Descender(m_Face->GetRec())));
492     FT_Done_Glyph(glyph);
493     if (FT_Set_Pixel_Sizes(m_Face->GetRec(), 0, 64) != 0)
494       return absl::nullopt;
495     return result;
496   }
497   constexpr int kFlag = FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
498   if (FT_Load_Glyph(m_Face->GetRec(), glyph_index, kFlag) != 0)
499     return absl::nullopt;
500   int em = FXFT_Get_Face_UnitsPerEM(m_Face->GetRec());
501   return ScaledFXRectFromFTPos(FXFT_Get_Glyph_HoriBearingX(m_Face->GetRec()),
502                                FXFT_Get_Glyph_HoriBearingY(m_Face->GetRec()) -
503                                    FXFT_Get_Glyph_Height(m_Face->GetRec()),
504                                FXFT_Get_Glyph_HoriBearingX(m_Face->GetRec()) +
505                                    FXFT_Get_Glyph_Width(m_Face->GetRec()),
506                                FXFT_Get_Glyph_HoriBearingY(m_Face->GetRec()),
507                                em, em);
508 }
509 
IsItalic() const510 bool CFX_Font::IsItalic() const {
511   if (!m_Face)
512     return false;
513   if (FXFT_Is_Face_Italic(m_Face->GetRec()) == FT_STYLE_FLAG_ITALIC)
514     return true;
515 
516   ByteString str(FXFT_Get_Face_Style_Name(m_Face->GetRec()));
517   str.MakeLower();
518   return str.Contains("italic");
519 }
520 
IsBold() const521 bool CFX_Font::IsBold() const {
522   return m_Face && FXFT_Is_Face_Bold(m_Face->GetRec()) == FT_STYLE_FLAG_BOLD;
523 }
524 
IsFixedWidth() const525 bool CFX_Font::IsFixedWidth() const {
526   return m_Face && FXFT_Is_Face_fixedwidth(m_Face->GetRec()) != 0;
527 }
528 
529 #if defined(_SKIA_SUPPORT_)
IsSubstFontBold() const530 bool CFX_Font::IsSubstFontBold() const {
531   CFX_SubstFont* subst_font = GetSubstFont();
532   return subst_font && subst_font->GetOriginalWeight() >= FXFONT_FW_BOLD;
533 }
534 #endif
535 
GetPsName() const536 ByteString CFX_Font::GetPsName() const {
537   if (!m_Face)
538     return ByteString();
539 
540   ByteString psName = FT_Get_Postscript_Name(m_Face->GetRec());
541   if (psName.IsEmpty())
542     psName = kUntitledFontName;
543   return psName;
544 }
545 
GetFamilyName() const546 ByteString CFX_Font::GetFamilyName() const {
547   if (!m_Face && !m_pSubstFont)
548     return ByteString();
549   if (m_Face)
550     return ByteString(FXFT_Get_Face_Family_Name(m_Face->GetRec()));
551   return m_pSubstFont->m_Family;
552 }
553 
GetFamilyNameOrUntitled() const554 ByteString CFX_Font::GetFamilyNameOrUntitled() const {
555   ByteString facename = GetFamilyName();
556   return facename.IsEmpty() ? kUntitledFontName : facename;
557 }
558 
GetFaceName() const559 ByteString CFX_Font::GetFaceName() const {
560   if (!m_Face && !m_pSubstFont)
561     return ByteString();
562   if (m_Face) {
563     ByteString style = ByteString(FXFT_Get_Face_Style_Name(m_Face->GetRec()));
564     ByteString facename = GetFamilyNameOrUntitled();
565     if (ShouldAppendStyle(style))
566       facename += " " + style;
567     return facename;
568   }
569   return m_pSubstFont->m_Family;
570 }
571 
GetBaseFontName() const572 ByteString CFX_Font::GetBaseFontName() const {
573   ByteString psname = GetPsName();
574   if (!psname.IsEmpty() && psname != kUntitledFontName)
575     return psname;
576   if (m_Face) {
577     ByteString style = ByteString(FXFT_Get_Face_Style_Name(m_Face->GetRec()));
578     ByteString facename = GetFamilyNameOrUntitled();
579     if (IsTTFont())
580       facename.Remove(' ');
581     if (ShouldAppendStyle(style))
582       facename += (IsTTFont() ? "," : " ") + style;
583     return facename;
584   }
585   if (m_pSubstFont)
586     return m_pSubstFont->m_Family;
587   return ByteString();
588 }
589 
GetRawBBox() const590 absl::optional<FX_RECT> CFX_Font::GetRawBBox() const {
591   if (!m_Face)
592     return absl::nullopt;
593 
594   return FXRectFromFTPos(FXFT_Get_Face_xMin(m_Face->GetRec()),
595                          FXFT_Get_Face_yMin(m_Face->GetRec()),
596                          FXFT_Get_Face_xMax(m_Face->GetRec()),
597                          FXFT_Get_Face_yMax(m_Face->GetRec()));
598 }
599 
GetBBox() const600 absl::optional<FX_RECT> CFX_Font::GetBBox() const {
601   absl::optional<FX_RECT> result = GetRawBBox();
602   if (!result.has_value())
603     return result;
604 
605   int em = FXFT_Get_Face_UnitsPerEM(m_Face->GetRec());
606   if (em != 0) {
607     FX_RECT& bbox = result.value();
608     bbox.left = (bbox.left * 1000) / em;
609     bbox.top = (bbox.top * 1000) / em;
610     bbox.right = (bbox.right * 1000) / em;
611     bbox.bottom = (bbox.bottom * 1000) / em;
612   }
613   return result;
614 }
615 
GetOrCreateGlyphCache() const616 RetainPtr<CFX_GlyphCache> CFX_Font::GetOrCreateGlyphCache() const {
617   if (!m_GlyphCache)
618     m_GlyphCache = CFX_GEModule::Get()->GetFontCache()->GetGlyphCache(this);
619   return m_GlyphCache;
620 }
621 
ClearGlyphCache()622 void CFX_Font::ClearGlyphCache() {
623   m_GlyphCache = nullptr;
624 }
625 
AdjustMMParams(int glyph_index,int dest_width,int weight) const626 void CFX_Font::AdjustMMParams(int glyph_index,
627                               int dest_width,
628                               int weight) const {
629   DCHECK(dest_width >= 0);
630   ScopedFXFTMMVar variation_desc(m_Face->GetRec());
631   if (!variation_desc) {
632     return;
633   }
634 
635   FT_Pos coords[2];
636   if (weight == 0) {
637     coords[0] = variation_desc.GetAxisDefault(0) / 65536;
638   } else {
639     coords[0] = weight;
640   }
641 
642   if (dest_width == 0) {
643     coords[1] = variation_desc.GetAxisDefault(1) / 65536;
644   } else {
645     FT_Long min_param = variation_desc.GetAxisMin(1) / 65536;
646     FT_Long max_param = variation_desc.GetAxisMax(1) / 65536;
647     coords[1] = min_param;
648     FT_Set_MM_Design_Coordinates(m_Face->GetRec(), 2, coords);
649     FT_Load_Glyph(m_Face->GetRec(), glyph_index,
650                   FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
651     FT_Pos min_width = FXFT_Get_Glyph_HoriAdvance(m_Face->GetRec()) * 1000 /
652                        FXFT_Get_Face_UnitsPerEM(m_Face->GetRec());
653     coords[1] = max_param;
654     FT_Set_MM_Design_Coordinates(m_Face->GetRec(), 2, coords);
655     FT_Load_Glyph(m_Face->GetRec(), glyph_index,
656                   FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
657     FT_Pos max_width = FXFT_Get_Glyph_HoriAdvance(m_Face->GetRec()) * 1000 /
658                        FXFT_Get_Face_UnitsPerEM(m_Face->GetRec());
659     if (max_width == min_width) {
660       return;
661     }
662     FT_Pos param = min_param + (max_param - min_param) *
663                                    (dest_width - min_width) /
664                                    (max_width - min_width);
665     coords[1] = param;
666   }
667   FT_Set_MM_Design_Coordinates(m_Face->GetRec(), 2, coords);
668 }
669 
LoadGlyphPathImpl(uint32_t glyph_index,int dest_width) const670 std::unique_ptr<CFX_Path> CFX_Font::LoadGlyphPathImpl(uint32_t glyph_index,
671                                                       int dest_width) const {
672   if (!m_Face)
673     return nullptr;
674 
675   FT_Set_Pixel_Sizes(m_Face->GetRec(), 0, 64);
676   FT_Matrix ft_matrix = {65536, 0, 0, 65536};
677   if (m_pSubstFont) {
678     if (m_pSubstFont->m_ItalicAngle) {
679       int skew = GetSkewFromAngle(m_pSubstFont->m_ItalicAngle);
680       if (m_bVertical)
681         ft_matrix.yx += ft_matrix.yy * skew / 100;
682       else
683         ft_matrix.xy -= ft_matrix.xx * skew / 100;
684     }
685     if (m_pSubstFont->IsBuiltInGenericFont())
686       AdjustMMParams(glyph_index, dest_width, m_pSubstFont->m_Weight);
687   }
688   ScopedFontTransform scoped_transform(m_Face, &ft_matrix);
689   int load_flags = FT_LOAD_NO_BITMAP;
690   if (!(m_Face->GetRec()->face_flags & FT_FACE_FLAG_SFNT) ||
691       !FT_IS_TRICKY(m_Face->GetRec()))
692     load_flags |= FT_LOAD_NO_HINTING;
693   if (FT_Load_Glyph(m_Face->GetRec(), glyph_index, load_flags))
694     return nullptr;
695   if (m_pSubstFont && !m_pSubstFont->IsBuiltInGenericFont() &&
696       m_pSubstFont->m_Weight > 400) {
697     uint32_t index = std::min<uint32_t>((m_pSubstFont->m_Weight - 400) / 10,
698                                         kWeightPowArraySize - 1);
699     int level;
700     if (m_pSubstFont->m_Charset == FX_Charset::kShiftJIS)
701       level = kWeightPowShiftJis[index] * 65536 / 36655;
702     else
703       level = kWeightPow[index];
704     FT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face->GetRec()), level);
705   }
706 
707   FT_Outline_Funcs funcs;
708   funcs.move_to = Outline_MoveTo;
709   funcs.line_to = Outline_LineTo;
710   funcs.conic_to = Outline_ConicTo;
711   funcs.cubic_to = Outline_CubicTo;
712   funcs.shift = 0;
713   funcs.delta = 0;
714 
715   auto pPath = std::make_unique<CFX_Path>();
716   OUTLINE_PARAMS params;
717   params.m_pPath = pPath.get();
718   params.m_CurX = params.m_CurY = 0;
719   params.m_CoordUnit = 64 * 64.0;
720 
721   FT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face->GetRec()), &funcs,
722                        &params);
723   if (pPath->GetPoints().empty())
724     return nullptr;
725 
726   Outline_CheckEmptyContour(&params);
727   pPath->ClosePath();
728   return pPath;
729 }
730 
LoadGlyphBitmap(uint32_t glyph_index,bool bFontStyle,const CFX_Matrix & matrix,int dest_width,int anti_alias,CFX_TextRenderOptions * text_options) const731 const CFX_GlyphBitmap* CFX_Font::LoadGlyphBitmap(
732     uint32_t glyph_index,
733     bool bFontStyle,
734     const CFX_Matrix& matrix,
735     int dest_width,
736     int anti_alias,
737     CFX_TextRenderOptions* text_options) const {
738   return GetOrCreateGlyphCache()->LoadGlyphBitmap(this, glyph_index, bFontStyle,
739                                                   matrix, dest_width,
740                                                   anti_alias, text_options);
741 }
742 
LoadGlyphPath(uint32_t glyph_index,int dest_width) const743 const CFX_Path* CFX_Font::LoadGlyphPath(uint32_t glyph_index,
744                                         int dest_width) const {
745   return GetOrCreateGlyphCache()->LoadGlyphPath(this, glyph_index, dest_width);
746 }
747 
748 // static
GetWeightLevel(FX_Charset charset,size_t index)749 int CFX_Font::GetWeightLevel(FX_Charset charset, size_t index) {
750   if (index >= kWeightPowArraySize)
751     return -1;
752 
753   if (charset == FX_Charset::kShiftJIS)
754     return kWeightPowShiftJis[index];
755   return kWeightPow11[index];
756 }
757 
758 // static
GetSkewFromAngle(int angle)759 int CFX_Font::GetSkewFromAngle(int angle) {
760   // |angle| is non-positive so |-angle| is used as the index. Need to make sure
761   // |angle| != INT_MIN since -INT_MIN is undefined.
762   if (angle > 0 || angle == std::numeric_limits<int>::min() ||
763       static_cast<size_t>(-angle) >= std::size(kAngleSkew)) {
764     return -58;
765   }
766   return kAngleSkew[-angle];
767 }
768 
769 #if defined(_SKIA_SUPPORT_)
GetDeviceCache() const770 CFX_TypeFace* CFX_Font::GetDeviceCache() const {
771   return GetOrCreateGlyphCache()->GetDeviceCache(this);
772 }
773 #endif
774