• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 #include "core/fxge/cfx_face.h"
6 
7 #include <algorithm>
8 #include <array>
9 #include <limits>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13 
14 #include "core/fxcrt/check.h"
15 #include "core/fxcrt/check_op.h"
16 #include "core/fxcrt/compiler_specific.h"
17 #include "core/fxcrt/notreached.h"
18 #include "core/fxcrt/numerics/clamped_math.h"
19 #include "core/fxcrt/numerics/safe_conversions.h"
20 #include "core/fxcrt/numerics/safe_math.h"
21 #include "core/fxcrt/span.h"
22 #include "core/fxcrt/stl_util.h"
23 #include "core/fxge/cfx_font.h"
24 #include "core/fxge/cfx_fontmgr.h"
25 #include "core/fxge/cfx_gemodule.h"
26 #include "core/fxge/cfx_glyphbitmap.h"
27 #include "core/fxge/cfx_path.h"
28 #include "core/fxge/cfx_substfont.h"
29 #include "core/fxge/dib/cfx_dibitmap.h"
30 #include "core/fxge/dib/fx_dib.h"
31 #include "core/fxge/fx_font.h"
32 #include "core/fxge/fx_fontencoding.h"
33 #include "core/fxge/scoped_font_transform.h"
34 
35 #define EM_ADJUST(em, a) (em == 0 ? (a) : (a) * 1000 / em)
36 
37 namespace {
38 
39 struct OUTLINE_PARAMS {
40   UnownedPtr<CFX_Path> m_pPath;
41   FT_Pos m_CurX;
42   FT_Pos m_CurY;
43   float m_CoordUnit;
44 };
45 
46 constexpr int kThousandthMinInt = std::numeric_limits<int>::min() / 1000;
47 constexpr int kThousandthMaxInt = std::numeric_limits<int>::max() / 1000;
48 
49 constexpr int kMaxGlyphDimension = 2048;
50 
51 // Boundary value to avoid integer overflow when adding 1/64th of the value.
52 constexpr int kMaxRectTop = 2114445437;
53 
54 constexpr auto kWeightPow = fxcrt::ToArray<const uint8_t>({
55     0,   6,   12,  14,  16,  18,  22,  24,  28,  30,  32,  34,  36,  38,  40,
56     42,  44,  46,  48,  50,  52,  54,  56,  58,  60,  62,  64,  66,  68,  70,
57     70,  72,  72,  74,  74,  74,  76,  76,  76,  78,  78,  78,  80,  80,  80,
58     82,  82,  82,  84,  84,  84,  84,  86,  86,  86,  88,  88,  88,  88,  90,
59     90,  90,  90,  92,  92,  92,  92,  94,  94,  94,  94,  96,  96,  96,  96,
60     96,  98,  98,  98,  98,  100, 100, 100, 100, 100, 102, 102, 102, 102, 102,
61     104, 104, 104, 104, 104, 106, 106, 106, 106, 106,
62 });
63 
64 constexpr auto kWeightPow11 = fxcrt::ToArray<const uint8_t>({
65     0,  4,  7,  8,  9,  10, 12, 13, 15, 17, 18, 19, 20, 21, 22, 23, 24,
66     25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 39, 40, 40, 41,
67     41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46,
68     46, 43, 47, 47, 48, 48, 48, 48, 45, 50, 50, 50, 46, 51, 51, 51, 52,
69     52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55,
70     56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58,
71 });
72 
73 constexpr auto kWeightPowShiftJis = fxcrt::ToArray<const uint8_t>({
74     0,   0,   2,   4,   6,   8,   10,  14,  16,  20,  22,  26,  28,  32,  34,
75     38,  42,  44,  48,  52,  56,  60,  64,  66,  70,  74,  78,  82,  86,  90,
76     96,  96,  96,  96,  98,  98,  98,  100, 100, 100, 100, 102, 102, 102, 102,
77     104, 104, 104, 104, 104, 106, 106, 106, 106, 106, 108, 108, 108, 108, 108,
78     110, 110, 110, 110, 110, 112, 112, 112, 112, 112, 112, 114, 114, 114, 114,
79     114, 114, 114, 116, 116, 116, 116, 116, 116, 116, 118, 118, 118, 118, 118,
80     118, 118, 120, 120, 120, 120, 120, 120, 120, 120,
81 });
82 
83 constexpr size_t kWeightPowArraySize = 100;
84 static_assert(kWeightPowArraySize == std::size(kWeightPow), "Wrong size");
85 static_assert(kWeightPowArraySize == std::size(kWeightPow11), "Wrong size");
86 static_assert(kWeightPowArraySize == std::size(kWeightPowShiftJis),
87               "Wrong size");
88 
89 constexpr auto kAngleSkew = fxcrt::ToArray<const int8_t>({
90     -0,  -2,  -3,  -5,  -7,  -9,  -11, -12, -14, -16, -18, -19, -21, -23, -25,
91     -27, -29, -31, -32, -34, -36, -38, -40, -42, -45, -47, -49, -51, -53, -55,
92 });
93 
94 // Returns negative values on failure.
GetWeightLevel(FX_Charset charset,size_t index)95 int GetWeightLevel(FX_Charset charset, size_t index) {
96   if (index >= kWeightPowArraySize) {
97     return -1;
98   }
99 
100   if (charset == FX_Charset::kShiftJIS) {
101     return kWeightPowShiftJis[index];
102   }
103   return kWeightPow11[index];
104 }
105 
GetSkewFromAngle(int angle)106 int GetSkewFromAngle(int angle) {
107   // |angle| is non-positive so |-angle| is used as the index. Need to make sure
108   // |angle| != INT_MIN since -INT_MIN is undefined.
109   if (angle > 0 || angle == std::numeric_limits<int>::min() ||
110       static_cast<size_t>(-angle) >= std::size(kAngleSkew)) {
111     return -58;
112   }
113   return kAngleSkew[-angle];
114 }
115 
FTPosToCBoxInt(FT_Pos pos)116 int FTPosToCBoxInt(FT_Pos pos) {
117   // Boundary values to avoid integer overflow when multiplied by 1000.
118   constexpr FT_Pos kMinCBox = -2147483;
119   constexpr FT_Pos kMaxCBox = 2147483;
120   return static_cast<int>(std::clamp(pos, kMinCBox, kMaxCBox));
121 }
122 
Outline_CheckEmptyContour(OUTLINE_PARAMS * param)123 void Outline_CheckEmptyContour(OUTLINE_PARAMS* param) {
124   size_t size;
125   {
126     pdfium::span<const CFX_Path::Point> points = param->m_pPath->GetPoints();
127     size = points.size();
128 
129     if (size >= 2 &&
130         points[size - 2].IsTypeAndOpen(CFX_Path::Point::Type::kMove) &&
131         points[size - 2].m_Point == points[size - 1].m_Point) {
132       size -= 2;
133     }
134     if (size >= 4 &&
135         points[size - 4].IsTypeAndOpen(CFX_Path::Point::Type::kMove) &&
136         points[size - 3].IsTypeAndOpen(CFX_Path::Point::Type::kBezier) &&
137         points[size - 3].m_Point == points[size - 4].m_Point &&
138         points[size - 2].m_Point == points[size - 4].m_Point &&
139         points[size - 1].m_Point == points[size - 4].m_Point) {
140       size -= 4;
141     }
142   }
143   // Only safe after |points| has been destroyed.
144   param->m_pPath->GetPoints().resize(size);
145 }
146 
Outline_MoveTo(const FT_Vector * to,void * user)147 int Outline_MoveTo(const FT_Vector* to, void* user) {
148   OUTLINE_PARAMS* param = static_cast<OUTLINE_PARAMS*>(user);
149 
150   Outline_CheckEmptyContour(param);
151 
152   param->m_pPath->ClosePath();
153   param->m_pPath->AppendPoint(
154       CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
155       CFX_Path::Point::Type::kMove);
156 
157   param->m_CurX = to->x;
158   param->m_CurY = to->y;
159   return 0;
160 }
161 
Outline_LineTo(const FT_Vector * to,void * user)162 int Outline_LineTo(const FT_Vector* to, void* user) {
163   OUTLINE_PARAMS* param = static_cast<OUTLINE_PARAMS*>(user);
164 
165   param->m_pPath->AppendPoint(
166       CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
167       CFX_Path::Point::Type::kLine);
168 
169   param->m_CurX = to->x;
170   param->m_CurY = to->y;
171   return 0;
172 }
173 
Outline_ConicTo(const FT_Vector * control,const FT_Vector * to,void * user)174 int Outline_ConicTo(const FT_Vector* control, const FT_Vector* to, void* user) {
175   OUTLINE_PARAMS* param = static_cast<OUTLINE_PARAMS*>(user);
176 
177   param->m_pPath->AppendPoint(
178       CFX_PointF((param->m_CurX + (control->x - param->m_CurX) * 2 / 3) /
179                      param->m_CoordUnit,
180                  (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) /
181                      param->m_CoordUnit),
182       CFX_Path::Point::Type::kBezier);
183 
184   param->m_pPath->AppendPoint(
185       CFX_PointF((control->x + (to->x - control->x) / 3) / param->m_CoordUnit,
186                  (control->y + (to->y - control->y) / 3) / param->m_CoordUnit),
187       CFX_Path::Point::Type::kBezier);
188 
189   param->m_pPath->AppendPoint(
190       CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
191       CFX_Path::Point::Type::kBezier);
192 
193   param->m_CurX = to->x;
194   param->m_CurY = to->y;
195   return 0;
196 }
197 
Outline_CubicTo(const FT_Vector * control1,const FT_Vector * control2,const FT_Vector * to,void * user)198 int Outline_CubicTo(const FT_Vector* control1,
199                     const FT_Vector* control2,
200                     const FT_Vector* to,
201                     void* user) {
202   OUTLINE_PARAMS* param = static_cast<OUTLINE_PARAMS*>(user);
203 
204   param->m_pPath->AppendPoint(CFX_PointF(control1->x / param->m_CoordUnit,
205                                          control1->y / param->m_CoordUnit),
206                               CFX_Path::Point::Type::kBezier);
207 
208   param->m_pPath->AppendPoint(CFX_PointF(control2->x / param->m_CoordUnit,
209                                          control2->y / param->m_CoordUnit),
210                               CFX_Path::Point::Type::kBezier);
211 
212   param->m_pPath->AppendPoint(
213       CFX_PointF(to->x / param->m_CoordUnit, to->y / param->m_CoordUnit),
214       CFX_Path::Point::Type::kBezier);
215 
216   param->m_CurX = to->x;
217   param->m_CurY = to->y;
218   return 0;
219 }
220 
ToFTEncoding(fxge::FontEncoding encoding)221 FT_Encoding ToFTEncoding(fxge::FontEncoding encoding) {
222   switch (encoding) {
223     case fxge::FontEncoding::kAdobeCustom:
224       return FT_ENCODING_ADOBE_CUSTOM;
225     case fxge::FontEncoding::kAdobeExpert:
226       return FT_ENCODING_ADOBE_EXPERT;
227     case fxge::FontEncoding::kAdobeStandard:
228       return FT_ENCODING_ADOBE_STANDARD;
229     case fxge::FontEncoding::kAppleRoman:
230       return FT_ENCODING_APPLE_ROMAN;
231     case fxge::FontEncoding::kBig5:
232       return FT_ENCODING_BIG5;
233     case fxge::FontEncoding::kGB2312:
234       return FT_ENCODING_PRC;
235     case fxge::FontEncoding::kJohab:
236       return FT_ENCODING_JOHAB;
237     case fxge::FontEncoding::kLatin1:
238       return FT_ENCODING_ADOBE_LATIN_1;
239     case fxge::FontEncoding::kNone:
240       return FT_ENCODING_NONE;
241     case fxge::FontEncoding::kOldLatin2:
242       return FT_ENCODING_OLD_LATIN_2;
243     case fxge::FontEncoding::kSjis:
244       return FT_ENCODING_SJIS;
245     case fxge::FontEncoding::kSymbol:
246       return FT_ENCODING_MS_SYMBOL;
247     case fxge::FontEncoding::kUnicode:
248       return FT_ENCODING_UNICODE;
249     case fxge::FontEncoding::kWansung:
250       return FT_ENCODING_WANSUNG;
251   }
252 }
253 
ToFontEncoding(uint32_t ft_encoding)254 fxge::FontEncoding ToFontEncoding(uint32_t ft_encoding) {
255   switch (ft_encoding) {
256     case FT_ENCODING_ADOBE_CUSTOM:
257       return fxge::FontEncoding::kAdobeCustom;
258     case FT_ENCODING_ADOBE_EXPERT:
259       return fxge::FontEncoding::kAdobeExpert;
260     case FT_ENCODING_ADOBE_STANDARD:
261       return fxge::FontEncoding::kAdobeStandard;
262     case FT_ENCODING_APPLE_ROMAN:
263       return fxge::FontEncoding::kAppleRoman;
264     case FT_ENCODING_BIG5:
265       return fxge::FontEncoding::kBig5;
266     case FT_ENCODING_PRC:
267       return fxge::FontEncoding::kGB2312;
268     case FT_ENCODING_JOHAB:
269       return fxge::FontEncoding::kJohab;
270     case FT_ENCODING_ADOBE_LATIN_1:
271       return fxge::FontEncoding::kLatin1;
272     case FT_ENCODING_NONE:
273       return fxge::FontEncoding::kNone;
274     case FT_ENCODING_OLD_LATIN_2:
275       return fxge::FontEncoding::kOldLatin2;
276     case FT_ENCODING_SJIS:
277       return fxge::FontEncoding::kSjis;
278     case FT_ENCODING_MS_SYMBOL:
279       return fxge::FontEncoding::kSymbol;
280     case FT_ENCODING_UNICODE:
281       return fxge::FontEncoding::kUnicode;
282     case FT_ENCODING_WANSUNG:
283       return fxge::FontEncoding::kWansung;
284   }
285   NOTREACHED_NORETURN();
286 }
287 
288 }  // namespace
289 
290 // static
New(FT_Library library,RetainPtr<Retainable> pDesc,pdfium::span<const FT_Byte> data,FT_Long face_index)291 RetainPtr<CFX_Face> CFX_Face::New(FT_Library library,
292                                   RetainPtr<Retainable> pDesc,
293                                   pdfium::span<const FT_Byte> data,
294                                   FT_Long face_index) {
295   FXFT_FaceRec* pRec = nullptr;
296   if (FT_New_Memory_Face(library, data.data(),
297                          pdfium::checked_cast<FT_Long>(data.size()), face_index,
298                          &pRec) != 0) {
299     return nullptr;
300   }
301   // Private ctor.
302   return pdfium::WrapRetain(new CFX_Face(pRec, std::move(pDesc)));
303 }
304 
305 // static
Open(FT_Library library,const FT_Open_Args * args,FT_Long face_index)306 RetainPtr<CFX_Face> CFX_Face::Open(FT_Library library,
307                                    const FT_Open_Args* args,
308                                    FT_Long face_index) {
309   FXFT_FaceRec* pRec = nullptr;
310   if (FT_Open_Face(library, args, face_index, &pRec) != 0)
311     return nullptr;
312 
313   // Private ctor.
314   return pdfium::WrapRetain(new CFX_Face(pRec, nullptr));
315 }
316 
HasGlyphNames() const317 bool CFX_Face::HasGlyphNames() const {
318   return !!(GetRec()->face_flags & FT_FACE_FLAG_GLYPH_NAMES);
319 }
320 
IsTtOt() const321 bool CFX_Face::IsTtOt() const {
322   return !!(GetRec()->face_flags & FT_FACE_FLAG_SFNT);
323 }
324 
IsTricky() const325 bool CFX_Face::IsTricky() const {
326   return !!(GetRec()->face_flags & FT_FACE_FLAG_TRICKY);
327 }
328 
IsFixedWidth() const329 bool CFX_Face::IsFixedWidth() const {
330   return !!(GetRec()->face_flags & FT_FACE_FLAG_FIXED_WIDTH);
331 }
332 
333 #if defined(PDF_ENABLE_XFA)
IsScalable() const334 bool CFX_Face::IsScalable() const {
335   return !!(GetRec()->face_flags & FT_FACE_FLAG_SCALABLE);
336 }
337 
ClearExternalStream()338 void CFX_Face::ClearExternalStream() {
339   GetRec()->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
340 }
341 #endif
342 
IsItalic() const343 bool CFX_Face::IsItalic() const {
344   return !!(GetRec()->style_flags & FT_STYLE_FLAG_ITALIC);
345 }
346 
IsBold() const347 bool CFX_Face::IsBold() const {
348   return !!(GetRec()->style_flags & FT_STYLE_FLAG_BOLD);
349 }
350 
GetFamilyName() const351 ByteString CFX_Face::GetFamilyName() const {
352   return ByteString(GetRec()->family_name);
353 }
354 
GetStyleName() const355 ByteString CFX_Face::GetStyleName() const {
356   return ByteString(GetRec()->style_name);
357 }
358 
GetBBox() const359 FX_RECT CFX_Face::GetBBox() const {
360   return FX_RECT(pdfium::checked_cast<int32_t>(GetRec()->bbox.xMin),
361                  pdfium::checked_cast<int32_t>(GetRec()->bbox.yMin),
362                  pdfium::checked_cast<int32_t>(GetRec()->bbox.xMax),
363                  pdfium::checked_cast<int32_t>(GetRec()->bbox.yMax));
364 }
365 
GetUnitsPerEm() const366 uint16_t CFX_Face::GetUnitsPerEm() const {
367   return pdfium::checked_cast<uint16_t>(GetRec()->units_per_EM);
368 }
369 
GetAscender() const370 int16_t CFX_Face::GetAscender() const {
371   return pdfium::checked_cast<int16_t>(GetRec()->ascender);
372 }
373 
GetDescender() const374 int16_t CFX_Face::GetDescender() const {
375   return pdfium::checked_cast<int16_t>(GetRec()->descender);
376 }
377 
378 #if BUILDFLAG(IS_ANDROID)
GetHeight() const379 int16_t CFX_Face::GetHeight() const {
380   return pdfium::checked_cast<int16_t>(GetRec()->height);
381 }
382 #endif
383 
GetData() const384 pdfium::span<uint8_t> CFX_Face::GetData() const {
385   // TODO(tsepez): justify safety from library API.
386   return UNSAFE_BUFFERS(
387       pdfium::make_span(GetRec()->stream->base, GetRec()->stream->size));
388 }
389 
GetSfntTable(uint32_t table,pdfium::span<uint8_t> buffer)390 size_t CFX_Face::GetSfntTable(uint32_t table, pdfium::span<uint8_t> buffer) {
391   unsigned long length = pdfium::checked_cast<unsigned long>(buffer.size());
392   if (length) {
393     int error = FT_Load_Sfnt_Table(GetRec(), table, 0, buffer.data(), &length);
394     if (error || length != buffer.size()) {
395       return 0;
396     }
397     return buffer.size();
398   }
399 
400   int error = FT_Load_Sfnt_Table(GetRec(), table, 0, nullptr, &length);
401   if (error || !length) {
402     return 0;
403   }
404   return pdfium::checked_cast<size_t>(length);
405 }
406 
GetOs2UnicodeRange()407 std::optional<std::array<uint32_t, 4>> CFX_Face::GetOs2UnicodeRange() {
408   auto* os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(GetRec(), FT_SFNT_OS2));
409   if (!os2) {
410     return std::nullopt;
411   }
412   return std::array<uint32_t, 4>{static_cast<uint32_t>(os2->ulUnicodeRange1),
413                                  static_cast<uint32_t>(os2->ulUnicodeRange2),
414                                  static_cast<uint32_t>(os2->ulUnicodeRange3),
415                                  static_cast<uint32_t>(os2->ulUnicodeRange4)};
416 }
417 
GetOs2CodePageRange()418 std::optional<std::array<uint32_t, 2>> CFX_Face::GetOs2CodePageRange() {
419   auto* os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(GetRec(), FT_SFNT_OS2));
420   if (!os2) {
421     return std::nullopt;
422   }
423   return std::array<uint32_t, 2>{static_cast<uint32_t>(os2->ulCodePageRange1),
424                                  static_cast<uint32_t>(os2->ulCodePageRange2)};
425 }
426 
GetOs2Panose()427 std::optional<std::array<uint8_t, 2>> CFX_Face::GetOs2Panose() {
428   auto* os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(GetRec(), FT_SFNT_OS2));
429   if (!os2) {
430     return std::nullopt;
431   }
432   // SAFETY: required from library.
433   return UNSAFE_BUFFERS(std::array<uint8_t, 2>{os2->panose[0], os2->panose[1]});
434 }
435 
GetGlyphCount() const436 int CFX_Face::GetGlyphCount() const {
437   return pdfium::checked_cast<int>(GetRec()->num_glyphs);
438 }
439 
RenderGlyph(const CFX_Font * pFont,uint32_t glyph_index,bool bFontStyle,const CFX_Matrix & matrix,int dest_width,int anti_alias)440 std::unique_ptr<CFX_GlyphBitmap> CFX_Face::RenderGlyph(const CFX_Font* pFont,
441                                                        uint32_t glyph_index,
442                                                        bool bFontStyle,
443                                                        const CFX_Matrix& matrix,
444                                                        int dest_width,
445                                                        int anti_alias) {
446   FT_Matrix ft_matrix;
447   ft_matrix.xx = matrix.a / 64 * 65536;
448   ft_matrix.xy = matrix.c / 64 * 65536;
449   ft_matrix.yx = matrix.b / 64 * 65536;
450   ft_matrix.yy = matrix.d / 64 * 65536;
451   bool bUseCJKSubFont = false;
452   const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
453   if (pSubstFont) {
454     bUseCJKSubFont = pSubstFont->m_bSubstCJK && bFontStyle;
455     int angle;
456     if (bUseCJKSubFont) {
457       angle = pSubstFont->m_bItalicCJK ? -15 : 0;
458     } else {
459       angle = pSubstFont->m_ItalicAngle;
460     }
461     if (angle) {
462       int skew = GetSkewFromAngle(angle);
463       if (pFont->IsVertical()) {
464         ft_matrix.yx += ft_matrix.yy * skew / 100;
465       } else {
466         ft_matrix.xy -= ft_matrix.xx * skew / 100;
467       }
468     }
469     if (pSubstFont->IsBuiltInGenericFont()) {
470       pFont->GetFace()->AdjustVariationParams(glyph_index, dest_width,
471                                               pFont->GetSubstFont()->m_Weight);
472     }
473   }
474 
475   ScopedFontTransform scoped_transform(pdfium::WrapRetain(this), &ft_matrix);
476   int load_flags = FT_LOAD_NO_BITMAP | FT_LOAD_PEDANTIC;
477   if (!IsTtOt()) {
478     load_flags |= FT_LOAD_NO_HINTING;
479   }
480   FXFT_FaceRec* rec = GetRec();
481   int error = FT_Load_Glyph(rec, glyph_index, load_flags);
482   if (error) {
483     // if an error is returned, try to reload glyphs without hinting.
484     if (load_flags & FT_LOAD_NO_HINTING) {
485       return nullptr;
486     }
487 
488     load_flags |= FT_LOAD_NO_HINTING;
489     load_flags &= ~FT_LOAD_PEDANTIC;
490     error = FT_Load_Glyph(rec, glyph_index, load_flags);
491     if (error) {
492       return nullptr;
493     }
494   }
495 
496   auto* glyph = rec->glyph;
497   int weight;
498   if (bUseCJKSubFont) {
499     weight = pSubstFont->m_WeightCJK;
500   } else {
501     weight = pSubstFont ? pSubstFont->m_Weight : 0;
502   }
503   if (pSubstFont && !pSubstFont->IsBuiltInGenericFont() && weight > 400) {
504     uint32_t index = (weight - 400) / 10;
505     pdfium::CheckedNumeric<signed long> level =
506         GetWeightLevel(pSubstFont->m_Charset, index);
507     if (level.ValueOrDefault(-1) < 0) {
508       return nullptr;
509     }
510 
511     level = level *
512             (abs(static_cast<int>(ft_matrix.xx)) +
513              abs(static_cast<int>(ft_matrix.xy))) /
514             36655;
515     FT_Outline_Embolden(&glyph->outline, level.ValueOrDefault(0));
516   }
517   FT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->GetFTLibrary(),
518                           FT_LCD_FILTER_DEFAULT);
519   error = FT_Render_Glyph(glyph, static_cast<FT_Render_Mode>(anti_alias));
520   if (error) {
521     return nullptr;
522   }
523 
524   const FT_Bitmap& bitmap = glyph->bitmap;
525   if (bitmap.width > kMaxGlyphDimension || bitmap.rows > kMaxGlyphDimension) {
526     return nullptr;
527   }
528   int dib_width = bitmap.width;
529   auto pGlyphBitmap =
530       std::make_unique<CFX_GlyphBitmap>(glyph->bitmap_left, glyph->bitmap_top);
531   const FXDIB_Format format = anti_alias == FT_RENDER_MODE_MONO
532                                   ? FXDIB_Format::k1bppMask
533                                   : FXDIB_Format::k8bppMask;
534   if (!pGlyphBitmap->GetBitmap()->Create(dib_width, bitmap.rows, format)) {
535     return nullptr;
536   }
537 
538   int dest_pitch = pGlyphBitmap->GetBitmap()->GetPitch();
539   uint8_t* pDestBuf = pGlyphBitmap->GetBitmap()->GetWritableBuffer().data();
540   const uint8_t* pSrcBuf = bitmap.buffer;
541   UNSAFE_TODO({
542     if (anti_alias != FT_RENDER_MODE_MONO &&
543         bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
544       unsigned int bytes = anti_alias == FT_RENDER_MODE_LCD ? 3 : 1;
545       for (unsigned int i = 0; i < bitmap.rows; i++) {
546         for (unsigned int n = 0; n < bitmap.width; n++) {
547           uint8_t data =
548               (pSrcBuf[i * bitmap.pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
549           for (unsigned int b = 0; b < bytes; b++) {
550             pDestBuf[i * dest_pitch + n * bytes + b] = data;
551           }
552         }
553       }
554     } else {
555       FXSYS_memset(pDestBuf, 0, dest_pitch * bitmap.rows);
556       int rowbytes = std::min(abs(bitmap.pitch), dest_pitch);
557       for (unsigned int row = 0; row < bitmap.rows; row++) {
558         FXSYS_memcpy(pDestBuf + row * dest_pitch, pSrcBuf + row * bitmap.pitch,
559                      rowbytes);
560       }
561     }
562   });
563   return pGlyphBitmap;
564 }
565 
LoadGlyphPath(uint32_t glyph_index,int dest_width,bool is_vertical,const CFX_SubstFont * subst_font)566 std::unique_ptr<CFX_Path> CFX_Face::LoadGlyphPath(
567     uint32_t glyph_index,
568     int dest_width,
569     bool is_vertical,
570     const CFX_SubstFont* subst_font) {
571   FXFT_FaceRec* rec = GetRec();
572   FT_Set_Pixel_Sizes(rec, 0, 64);
573   FT_Matrix ft_matrix = {65536, 0, 0, 65536};
574   if (subst_font) {
575     if (subst_font->m_ItalicAngle) {
576       int skew = GetSkewFromAngle(subst_font->m_ItalicAngle);
577       if (is_vertical) {
578         ft_matrix.yx += ft_matrix.yy * skew / 100;
579       } else {
580         ft_matrix.xy -= ft_matrix.xx * skew / 100;
581       }
582     }
583     if (subst_font->IsBuiltInGenericFont()) {
584       AdjustVariationParams(glyph_index, dest_width, subst_font->m_Weight);
585     }
586   }
587   ScopedFontTransform scoped_transform(pdfium::WrapRetain(this), &ft_matrix);
588   int load_flags = FT_LOAD_NO_BITMAP;
589   if (!IsTtOt() || !IsTricky()) {
590     load_flags |= FT_LOAD_NO_HINTING;
591   }
592   if (FT_Load_Glyph(rec, glyph_index, load_flags)) {
593     return nullptr;
594   }
595   if (subst_font && !subst_font->IsBuiltInGenericFont() &&
596       subst_font->m_Weight > 400) {
597     uint32_t index = std::min<uint32_t>((subst_font->m_Weight - 400) / 10,
598                                         kWeightPowArraySize - 1);
599     int level;
600     if (subst_font->m_Charset == FX_Charset::kShiftJIS) {
601       level = kWeightPowShiftJis[index] * 65536 / 36655;
602     } else {
603       level = kWeightPow[index];
604     }
605     FT_Outline_Embolden(&rec->glyph->outline, level);
606   }
607 
608   FT_Outline_Funcs funcs;
609   funcs.move_to = Outline_MoveTo;
610   funcs.line_to = Outline_LineTo;
611   funcs.conic_to = Outline_ConicTo;
612   funcs.cubic_to = Outline_CubicTo;
613   funcs.shift = 0;
614   funcs.delta = 0;
615 
616   auto pPath = std::make_unique<CFX_Path>();
617   OUTLINE_PARAMS params;
618   params.m_pPath = pPath.get();
619   params.m_CurX = params.m_CurY = 0;
620   params.m_CoordUnit = 64 * 64.0;
621 
622   FT_Outline_Decompose(&rec->glyph->outline, &funcs, &params);
623   if (pPath->GetPoints().empty()) {
624     return nullptr;
625   }
626 
627   Outline_CheckEmptyContour(&params);
628   pPath->ClosePath();
629   return pPath;
630 }
631 
GetGlyphWidth(uint32_t glyph_index,int dest_width,int weight,const CFX_SubstFont * subst_font)632 int CFX_Face::GetGlyphWidth(uint32_t glyph_index,
633                             int dest_width,
634                             int weight,
635                             const CFX_SubstFont* subst_font) {
636   if (subst_font && subst_font->IsBuiltInGenericFont()) {
637     AdjustVariationParams(glyph_index, dest_width, weight);
638   }
639 
640   FXFT_FaceRec* rec = GetRec();
641   int err = FT_Load_Glyph(
642       rec, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
643   if (err) {
644     return 0;
645   }
646 
647   FT_Pos horizontal_advance = rec->glyph->metrics.horiAdvance;
648   if (horizontal_advance < kThousandthMinInt ||
649       horizontal_advance > kThousandthMaxInt) {
650     return 0;
651   }
652 
653   return static_cast<int>(EM_ADJUST(GetUnitsPerEm(), horizontal_advance));
654 }
655 
GetGlyphName(uint32_t glyph_index)656 ByteString CFX_Face::GetGlyphName(uint32_t glyph_index) {
657   char name[256] = {};
658   FT_Get_Glyph_Name(GetRec(), glyph_index, name, sizeof(name));
659   name[255] = 0;
660   return ByteString(name);
661 }
662 
GetCharIndex(uint32_t code)663 int CFX_Face::GetCharIndex(uint32_t code) {
664   return FT_Get_Char_Index(GetRec(), code);
665 }
666 
GetNameIndex(const char * name)667 int CFX_Face::GetNameIndex(const char* name) {
668   return FT_Get_Name_Index(GetRec(), name);
669 }
670 
GetCharBBox(uint32_t code,int glyph_index)671 FX_RECT CFX_Face::GetCharBBox(uint32_t code, int glyph_index) {
672   FX_RECT rect;
673   FXFT_FaceRec* rec = GetRec();
674   if (IsTricky()) {
675     int err =
676         FT_Load_Glyph(rec, glyph_index, FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
677     if (!err) {
678       FT_Glyph glyph;
679       err = FT_Get_Glyph(rec->glyph, &glyph);
680       if (!err) {
681         FT_BBox cbox;
682         FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_PIXELS, &cbox);
683         const int xMin = FTPosToCBoxInt(cbox.xMin);
684         const int xMax = FTPosToCBoxInt(cbox.xMax);
685         const int yMin = FTPosToCBoxInt(cbox.yMin);
686         const int yMax = FTPosToCBoxInt(cbox.yMax);
687         const int pixel_size_x = rec->size->metrics.x_ppem;
688         const int pixel_size_y = rec->size->metrics.y_ppem;
689         if (pixel_size_x == 0 || pixel_size_y == 0) {
690           rect = FX_RECT(xMin, yMax, xMax, yMin);
691         } else {
692           rect =
693               FX_RECT(xMin * 1000 / pixel_size_x, yMax * 1000 / pixel_size_y,
694                       xMax * 1000 / pixel_size_x, yMin * 1000 / pixel_size_y);
695         }
696         rect.top = std::min(rect.top, static_cast<int>(GetAscender()));
697         rect.bottom = std::max(rect.bottom, static_cast<int>(GetDescender()));
698         FT_Done_Glyph(glyph);
699       }
700     }
701   } else {
702     int err = FT_Load_Glyph(rec, glyph_index, FT_LOAD_NO_SCALE);
703     if (err == 0) {
704       rect = GetGlyphBBox();
705       if (rect.top <= kMaxRectTop) {
706         rect.top += rect.top / 64;
707       } else {
708         rect.top = std::numeric_limits<int>::max();
709       }
710     }
711   }
712   return rect;
713 }
714 
GetGlyphBBox() const715 FX_RECT CFX_Face::GetGlyphBBox() const {
716   const auto* glyph = GetRec()->glyph;
717   pdfium::ClampedNumeric<FT_Pos> left = glyph->metrics.horiBearingX;
718   pdfium::ClampedNumeric<FT_Pos> top = glyph->metrics.horiBearingY;
719   const uint16_t upem = GetUnitsPerEm();
720   return FX_RECT(NormalizeFontMetric(left, upem),
721                  NormalizeFontMetric(top, upem),
722                  NormalizeFontMetric(left + glyph->metrics.width, upem),
723                  NormalizeFontMetric(top - glyph->metrics.height, upem));
724 }
725 
GetCharCodesAndIndices(char32_t max_char)726 std::vector<CFX_Face::CharCodeAndIndex> CFX_Face::GetCharCodesAndIndices(
727     char32_t max_char) {
728   CharCodeAndIndex char_code_and_index;
729   char_code_and_index.char_code = static_cast<uint32_t>(
730       FT_Get_First_Char(GetRec(), &char_code_and_index.glyph_index));
731   if (char_code_and_index.char_code > max_char) {
732     return {};
733   }
734   std::vector<CharCodeAndIndex> results = {char_code_and_index};
735   while (true) {
736     char_code_and_index.char_code = static_cast<uint32_t>(FT_Get_Next_Char(
737         GetRec(), results.back().char_code, &char_code_and_index.glyph_index));
738     if (char_code_and_index.char_code > max_char ||
739         char_code_and_index.glyph_index == 0) {
740       return results;
741     }
742     results.push_back(char_code_and_index);
743   }
744 }
745 
GetCurrentCharMap() const746 CFX_Face::CharMap CFX_Face::GetCurrentCharMap() const {
747   return GetRec()->charmap;
748 }
749 
GetCurrentCharMapEncoding() const750 std::optional<fxge::FontEncoding> CFX_Face::GetCurrentCharMapEncoding() const {
751   if (!GetRec()->charmap) {
752     return std::nullopt;
753   }
754   return ToFontEncoding(GetRec()->charmap->encoding);
755 }
756 
GetCharMapPlatformIdByIndex(size_t index) const757 int CFX_Face::GetCharMapPlatformIdByIndex(size_t index) const {
758   CHECK_LT(index, GetCharMapCount());
759   // SAFETY: required from library as enforced by check above.
760   return UNSAFE_BUFFERS(GetRec()->charmaps[index]->platform_id);
761 }
762 
GetCharMapEncodingIdByIndex(size_t index) const763 int CFX_Face::GetCharMapEncodingIdByIndex(size_t index) const {
764   CHECK_LT(index, GetCharMapCount());
765   // SAFETY: required from library as enforced by check above.
766   return UNSAFE_BUFFERS(GetRec()->charmaps[index]->encoding_id);
767 }
768 
GetCharMapEncodingByIndex(size_t index) const769 fxge::FontEncoding CFX_Face::GetCharMapEncodingByIndex(size_t index) const {
770   CHECK_LT(index, GetCharMapCount());
771   // SAFETY: required from library as enforced by check above.
772   return ToFontEncoding(UNSAFE_BUFFERS(GetRec()->charmaps[index]->encoding));
773 }
774 
GetCharMapCount() const775 size_t CFX_Face::GetCharMapCount() const {
776   return GetRec()->charmaps
777              ? pdfium::checked_cast<size_t>(GetRec()->num_charmaps)
778              : 0;
779 }
780 
SetCharMap(CharMap map)781 void CFX_Face::SetCharMap(CharMap map) {
782   FT_Set_Charmap(GetRec(), static_cast<FT_CharMap>(map));
783 }
784 
SetCharMapByIndex(size_t index)785 void CFX_Face::SetCharMapByIndex(size_t index) {
786   CHECK_LT(index, GetCharMapCount());
787   // SAFETY: required from library as enforced by check above.
788   SetCharMap(UNSAFE_BUFFERS(GetRec()->charmaps[index]));
789 }
790 
SelectCharMap(fxge::FontEncoding encoding)791 bool CFX_Face::SelectCharMap(fxge::FontEncoding encoding) {
792   FT_Error error = FT_Select_Charmap(GetRec(), ToFTEncoding(encoding));
793   return !error;
794 }
795 
SetPixelSize(uint32_t width,uint32_t height)796 bool CFX_Face::SetPixelSize(uint32_t width, uint32_t height) {
797   FT_Error error = FT_Set_Pixel_Sizes(GetRec(), width, height);
798   return !error;
799 }
800 
801 #if BUILDFLAG(IS_WIN)
CanEmbed()802 bool CFX_Face::CanEmbed() {
803   FT_UShort fstype = FT_Get_FSType_Flags(GetRec());
804   return (fstype & (FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING |
805                     FT_FSTYPE_BITMAP_EMBEDDING_ONLY)) == 0;
806 }
807 #endif
808 
CFX_Face(FXFT_FaceRec * rec,RetainPtr<Retainable> pDesc)809 CFX_Face::CFX_Face(FXFT_FaceRec* rec, RetainPtr<Retainable> pDesc)
810     : m_pRec(rec), m_pDesc(std::move(pDesc)) {
811   DCHECK(m_pRec);
812 }
813 
814 CFX_Face::~CFX_Face() = default;
815 
AdjustVariationParams(int glyph_index,int dest_width,int weight)816 void CFX_Face::AdjustVariationParams(int glyph_index,
817                                      int dest_width,
818                                      int weight) {
819   DCHECK(dest_width >= 0);
820 
821   FXFT_FaceRec* rec = GetRec();
822   ScopedFXFTMMVar variation_desc(rec);
823   if (!variation_desc) {
824     return;
825   }
826 
827   FT_Pos coords[2];
828   if (weight == 0) {
829     coords[0] = variation_desc.GetAxisDefault(0) / 65536;
830   } else {
831     coords[0] = weight;
832   }
833 
834   if (dest_width == 0) {
835     coords[1] = variation_desc.GetAxisDefault(1) / 65536;
836   } else {
837     FT_Long min_param = variation_desc.GetAxisMin(1) / 65536;
838     FT_Long max_param = variation_desc.GetAxisMax(1) / 65536;
839     coords[1] = min_param;
840     FT_Set_MM_Design_Coordinates(rec, 2, coords);
841     FT_Load_Glyph(rec, glyph_index,
842                   FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
843     FT_Pos min_width = rec->glyph->metrics.horiAdvance * 1000 / GetUnitsPerEm();
844     coords[1] = max_param;
845     FT_Set_MM_Design_Coordinates(rec, 2, coords);
846     FT_Load_Glyph(rec, glyph_index,
847                   FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
848     FT_Pos max_width = rec->glyph->metrics.horiAdvance * 1000 / GetUnitsPerEm();
849     if (max_width == min_width) {
850       return;
851     }
852     FT_Pos param = min_param + (max_param - min_param) *
853                                    (dest_width - min_width) /
854                                    (max_width - min_width);
855     coords[1] = param;
856   }
857   FT_Set_MM_Design_Coordinates(rec, 2, coords);
858 }
859