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, ¶ms);
623 if (pPath->GetPoints().empty()) {
624 return nullptr;
625 }
626
627 Outline_CheckEmptyContour(¶ms);
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