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