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/freetype/fx_freetype.h"
8
9 #include <stdint.h>
10
11 #include "core/fxcrt/compiler_specific.h"
12 #include "core/fxge/cfx_fontmgr.h"
13 #include "core/fxge/cfx_gemodule.h"
14
15 #define DEFINE_PS_TABLES
16 #include "third_party/freetype/include/pstables.h"
17
18 namespace {
19
20 constexpr uint32_t kVariantBit = 0x80000000;
21
SearchNode(pdfium::span<const uint8_t> glyph_span,pdfium::span<char> name_buf,int name_offset,int table_offset,wchar_t unicode)22 bool SearchNode(pdfium::span<const uint8_t> glyph_span,
23 pdfium::span<char> name_buf,
24 int name_offset,
25 int table_offset,
26 wchar_t unicode) {
27 // copy letters
28 while (true) {
29 name_buf[name_offset] = glyph_span[table_offset] & 0x7f;
30 name_offset++;
31 table_offset++;
32 if (!(glyph_span[table_offset - 1] & 0x80)) {
33 break;
34 }
35 }
36 name_buf[name_offset] = 0;
37
38 // get child count
39 int count = glyph_span[table_offset] & 0x7f;
40
41 // check if we have value for this node
42 if (glyph_span[table_offset] & 0x80) {
43 unsigned short thiscode =
44 glyph_span[table_offset + 1] * 256 + glyph_span[table_offset + 2];
45 if (thiscode == (unsigned short)unicode) { // found it!
46 return true;
47 }
48 table_offset += 3;
49 } else {
50 table_offset++;
51 }
52
53 // now search in sub-nodes
54 for (int i = 0; i < count; i++) {
55 int child_offset = glyph_span[table_offset + i * 2] * 256 +
56 glyph_span[table_offset + i * 2 + 1];
57 if (SearchNode(glyph_span, name_buf, name_offset, child_offset, unicode)) {
58 // found in child
59 return true;
60 }
61 }
62
63 return false;
64 }
65
GetVariationDescriptor(FXFT_FaceRec * face)66 FT_MM_Var* GetVariationDescriptor(FXFT_FaceRec* face) {
67 FT_MM_Var* variation_desc = nullptr;
68 FT_Get_MM_Var(face, &variation_desc);
69 return variation_desc;
70 }
71
GetVariationAxis(const FT_MM_Var * variation_desc)72 pdfium::span<const FT_Var_Axis> GetVariationAxis(
73 const FT_MM_Var* variation_desc) {
74 if (!variation_desc) {
75 return {};
76 }
77
78 // SAFETY: Required from library.
79 return UNSAFE_BUFFERS(
80 pdfium::make_span(variation_desc->axis, variation_desc->num_axis));
81 }
82
83 } // namespace
84
operator ()(FT_MM_Var * variation_desc)85 void FXFTMMVarDeleter::operator()(FT_MM_Var* variation_desc) {
86 FT_Done_MM_Var(CFX_GEModule::Get()->GetFontMgr()->GetFTLibrary(),
87 variation_desc);
88 }
89
ScopedFXFTMMVar(FXFT_FaceRec * face)90 ScopedFXFTMMVar::ScopedFXFTMMVar(FXFT_FaceRec* face)
91 : variation_desc_(GetVariationDescriptor(face)),
92 axis_(GetVariationAxis(variation_desc_.get())) {}
93
94 ScopedFXFTMMVar::~ScopedFXFTMMVar() = default;
95
GetAxisDefault(size_t index) const96 FT_Pos ScopedFXFTMMVar::GetAxisDefault(size_t index) const {
97 return axis_[index].def;
98 }
99
GetAxisMin(size_t index) const100 FT_Long ScopedFXFTMMVar::GetAxisMin(size_t index) const {
101 return axis_[index].minimum;
102 }
103
GetAxisMax(size_t index) const104 FT_Long ScopedFXFTMMVar::GetAxisMax(size_t index) const {
105 return axis_[index].maximum;
106 }
107
FXFT_unicode_from_adobe_name(const char * glyph_name)108 int FXFT_unicode_from_adobe_name(const char* glyph_name) {
109 /* If the name begins with `uni', then the glyph name may be a */
110 /* hard-coded unicode character code. */
111 UNSAFE_TODO({
112 if (glyph_name[0] == 'u' && glyph_name[1] == 'n' && glyph_name[2] == 'i') {
113 /* determine whether the next four characters following are */
114 /* hexadecimal. */
115
116 /* XXX: Add code to deal with ligatures, i.e. glyph names like */
117 /* `uniXXXXYYYYZZZZ'... */
118
119 FT_Int count;
120 FT_UInt32 value = 0;
121 const char* p = glyph_name + 3;
122
123 for (count = 4; count > 0; count--, p++) {
124 char c = *p;
125 unsigned int d = (unsigned char)c - '0';
126 if (d >= 10) {
127 d = (unsigned char)c - 'A';
128 if (d >= 6) {
129 d = 16;
130 } else {
131 d += 10;
132 }
133 }
134
135 /* Exit if a non-uppercase hexadecimal character was found */
136 /* -- this also catches character codes below `0' since such */
137 /* negative numbers cast to `unsigned int' are far too big. */
138 if (d >= 16) {
139 break;
140 }
141
142 value = (value << 4) + d;
143 }
144
145 /* there must be exactly four hex digits */
146 if (count == 0) {
147 if (*p == '\0') {
148 return value;
149 }
150 if (*p == '.') {
151 return (FT_UInt32)(value | kVariantBit);
152 }
153 }
154 }
155
156 /* If the name begins with `u', followed by four to six uppercase */
157 /* hexadecimal digits, it is a hard-coded unicode character code. */
158 if (glyph_name[0] == 'u') {
159 FT_Int count;
160 FT_UInt32 value = 0;
161 const char* p = glyph_name + 1;
162
163 for (count = 6; count > 0; count--, p++) {
164 char c = *p;
165 unsigned int d = (unsigned char)c - '0';
166 if (d >= 10) {
167 d = (unsigned char)c - 'A';
168 if (d >= 6) {
169 d = 16;
170 } else {
171 d += 10;
172 }
173 }
174
175 if (d >= 16) {
176 break;
177 }
178
179 value = (value << 4) + d;
180 }
181
182 if (count <= 2) {
183 if (*p == '\0') {
184 return value;
185 }
186 if (*p == '.') {
187 return (FT_UInt32)(value | kVariantBit);
188 }
189 }
190 }
191
192 /* Look for a non-initial dot in the glyph name in order to */
193 /* find variants like `A.swash', `e.final', etc. */
194 {
195 const char* p = glyph_name;
196 const char* dot = nullptr;
197
198 for (; *p; p++) {
199 if (*p == '.' && p > glyph_name) {
200 dot = p;
201 break;
202 }
203 }
204
205 /* now look up the glyph in the Adobe Glyph List */
206 if (!dot) {
207 return (FT_UInt32)ft_get_adobe_glyph_index(glyph_name, p);
208 }
209
210 return (FT_UInt32)(ft_get_adobe_glyph_index(glyph_name, dot) |
211 kVariantBit);
212 }
213 });
214 }
215
FXFT_adobe_name_from_unicode(pdfium::span<char> name_buf,wchar_t unicode)216 void FXFT_adobe_name_from_unicode(pdfium::span<char> name_buf,
217 wchar_t unicode) {
218 pdfium::span<const uint8_t> glyph_span(ft_adobe_glyph_list);
219
220 // start from top level node
221 int count = glyph_span[1];
222 for (int i = 0; i < count; i++) {
223 int child_offset = glyph_span[i * 2 + 2] * 256 + glyph_span[i * 2 + 3];
224 if (SearchNode(glyph_span, name_buf, 0, child_offset, unicode)) {
225 return;
226 }
227 }
228
229 // failed, clear the buffer
230 name_buf[0] = 0;
231 }
232