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