1 // Copyright 2018 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/fx_font.h"
6
7 #include <stdint.h>
8
9 #include <algorithm>
10
11 #include "core/fxcrt/byteorder.h"
12 #include "core/fxcrt/fx_safe_types.h"
13 #include "core/fxcrt/numerics/safe_conversions.h"
14 #include "core/fxcrt/widestring.h"
15 #include "core/fxge/cfx_glyphbitmap.h"
16 #include "core/fxge/dib/cfx_dibitmap.h"
17 #include "core/fxge/freetype/fx_freetype.h"
18 #include "core/fxge/text_glyph_pos.h"
19
20 namespace {
21
22 // These numbers come from the OpenType name table specification.
23 constexpr uint16_t kNameMacEncodingRoman = 0;
24 constexpr uint16_t kNameWindowsEncodingUnicode = 1;
25
GetStringFromTable(pdfium::span<const uint8_t> string_span,uint16_t offset,uint16_t length)26 ByteString GetStringFromTable(pdfium::span<const uint8_t> string_span,
27 uint16_t offset,
28 uint16_t length) {
29 if (string_span.size() < static_cast<uint32_t>(offset + length))
30 return ByteString();
31
32 return ByteString(ByteStringView(string_span.subspan(offset, length)));
33 }
34
35 } // namespace
36
GetGlyphsBBox(const std::vector<TextGlyphPos> & glyphs,int anti_alias)37 FX_RECT GetGlyphsBBox(const std::vector<TextGlyphPos>& glyphs, int anti_alias) {
38 FX_RECT rect;
39 bool bStarted = false;
40 for (const TextGlyphPos& glyph : glyphs) {
41 if (!glyph.m_pGlyph)
42 continue;
43
44 std::optional<CFX_Point> point = glyph.GetOrigin({0, 0});
45 if (!point.has_value())
46 continue;
47
48 int char_width = glyph.m_pGlyph->GetBitmap()->GetWidth();
49 if (anti_alias == FT_RENDER_MODE_LCD)
50 char_width /= 3;
51
52 FX_SAFE_INT32 char_right = point.value().x;
53 char_right += char_width;
54 if (!char_right.IsValid())
55 continue;
56
57 FX_SAFE_INT32 char_bottom = point.value().y;
58 char_bottom += glyph.m_pGlyph->GetBitmap()->GetHeight();
59 if (!char_bottom.IsValid())
60 continue;
61
62 if (bStarted) {
63 rect.left = std::min(rect.left, point.value().x);
64 rect.top = std::min(rect.top, point.value().y);
65 rect.right = pdfium::ValueOrDieForType<int32_t>(
66 pdfium::CheckMax(rect.right, char_right));
67 rect.bottom = pdfium::ValueOrDieForType<int32_t>(
68 pdfium::CheckMax(rect.bottom, char_bottom));
69 continue;
70 }
71
72 rect.left = point.value().x;
73 rect.top = point.value().y;
74 rect.right = char_right.ValueOrDie();
75 rect.bottom = char_bottom.ValueOrDie();
76 bStarted = true;
77 }
78 return rect;
79 }
80
GetNameFromTT(pdfium::span<const uint8_t> name_table,uint32_t name_id)81 ByteString GetNameFromTT(pdfium::span<const uint8_t> name_table,
82 uint32_t name_id) {
83 if (name_table.size() < 6)
84 return ByteString();
85
86 uint32_t name_count = fxcrt::GetUInt16MSBFirst(name_table.subspan(2));
87 uint32_t string_offset = fxcrt::GetUInt16MSBFirst(name_table.subspan(4));
88 // We will ignore the possibility of overlap of structures and
89 // string table as if it's all corrupt there's not a lot we can do.
90 if (name_table.size() < string_offset)
91 return ByteString();
92
93 pdfium::span<const uint8_t> string_span = name_table.subspan(string_offset);
94 name_table = name_table.subspan(6);
95 if (name_table.size() < name_count * 12)
96 return ByteString();
97
98 for (uint32_t i = 0; i < name_count;
99 i++, name_table = name_table.subspan(12)) {
100 if (fxcrt::GetUInt16MSBFirst(name_table.subspan(6)) == name_id) {
101 const uint16_t platform_identifier = fxcrt::GetUInt16MSBFirst(name_table);
102 const uint16_t platform_encoding =
103 fxcrt::GetUInt16MSBFirst(name_table.subspan(2));
104
105 if (platform_identifier == kNamePlatformMac &&
106 platform_encoding == kNameMacEncodingRoman) {
107 return GetStringFromTable(
108 string_span, fxcrt::GetUInt16MSBFirst(name_table.subspan(10)),
109 fxcrt::GetUInt16MSBFirst(name_table.subspan(8)));
110 }
111 if (platform_identifier == kNamePlatformWindows &&
112 platform_encoding == kNameWindowsEncodingUnicode) {
113 // This name is always UTF16-BE and we have to convert it to UTF8.
114 ByteString utf16_be = GetStringFromTable(
115 string_span, fxcrt::GetUInt16MSBFirst(name_table.subspan(10)),
116 fxcrt::GetUInt16MSBFirst(name_table.subspan(8)));
117 if (utf16_be.IsEmpty() || utf16_be.GetLength() % 2 != 0) {
118 return ByteString();
119 }
120
121 return WideString::FromUTF16BE(utf16_be.unsigned_span()).ToUTF8();
122 }
123 }
124 }
125 return ByteString();
126 }
127
GetTTCIndex(pdfium::span<const uint8_t> pFontData,size_t font_offset)128 size_t GetTTCIndex(pdfium::span<const uint8_t> pFontData, size_t font_offset) {
129 pdfium::span<const uint8_t> p = pFontData.subspan(8);
130 size_t nfont = fxcrt::GetUInt32MSBFirst(p);
131 for (size_t index = 0; index < nfont; index++) {
132 p = pFontData.subspan(12 + index * 4);
133 if (fxcrt::GetUInt32MSBFirst(p) == font_offset) {
134 return index;
135 }
136 }
137 return 0;
138 }
139
UnicodeFromAdobeName(const char * name)140 wchar_t UnicodeFromAdobeName(const char* name) {
141 return (wchar_t)(FXFT_unicode_from_adobe_name(name) & 0x7FFFFFFF);
142 }
143
AdobeNameFromUnicode(wchar_t unicode)144 ByteString AdobeNameFromUnicode(wchar_t unicode) {
145 char glyph_name[64];
146 FXFT_adobe_name_from_unicode(glyph_name, unicode);
147 return ByteString(glyph_name);
148 }
149
NormalizeFontMetric(int64_t value,uint16_t upem)150 int NormalizeFontMetric(int64_t value, uint16_t upem) {
151 if (upem == 0) {
152 return pdfium::saturated_cast<int>(value);
153 }
154
155 const double scaled_value = (value * 1000.0 + upem / 2) / upem;
156 return pdfium::saturated_cast<int>(scaled_value);
157 }
158