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