/src/mupdf/source/fitz/font.c
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (C) 2004-2022 Artifex Software, Inc. |
2 | | // |
3 | | // This file is part of MuPDF. |
4 | | // |
5 | | // MuPDF is free software: you can redistribute it and/or modify it under the |
6 | | // terms of the GNU Affero General Public License as published by the Free |
7 | | // Software Foundation, either version 3 of the License, or (at your option) |
8 | | // any later version. |
9 | | // |
10 | | // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | | // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
13 | | // details. |
14 | | // |
15 | | // You should have received a copy of the GNU Affero General Public License |
16 | | // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> |
17 | | // |
18 | | // Alternative licensing terms are available from the licensor. |
19 | | // For commercial licensing, see <https://www.artifex.com/> or contact |
20 | | // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
21 | | // CA 94129, USA, for further information. |
22 | | |
23 | | #include "mupdf/fitz.h" |
24 | | #include "mupdf/ucdn.h" |
25 | | |
26 | | #include "draw-imp.h" |
27 | | #include "color-imp.h" |
28 | | #include "glyph-imp.h" |
29 | | #include "pixmap-imp.h" |
30 | | |
31 | | #include <ft2build.h> |
32 | | |
33 | | #include <assert.h> |
34 | | |
35 | | #include FT_FREETYPE_H |
36 | | #include FT_ADVANCES_H |
37 | | #include FT_MODULE_H |
38 | | #include FT_STROKER_H |
39 | | #include FT_SYSTEM_H |
40 | | #include FT_TRUETYPE_TABLES_H |
41 | | #include FT_TRUETYPE_TAGS_H |
42 | | |
43 | | #ifndef FT_SFNT_OS2 |
44 | 12.6k | #define FT_SFNT_OS2 ft_sfnt_os2 |
45 | | #endif |
46 | | |
47 | | /* 20 degrees */ |
48 | 0 | #define SHEAR 0.36397f |
49 | | |
50 | | int ft_char_index(void *face, int cid) |
51 | 35.9M | { |
52 | 35.9M | int gid = FT_Get_Char_Index(face, cid); |
53 | 35.9M | if (gid == 0) |
54 | 34.4M | gid = FT_Get_Char_Index(face, 0xf000 + cid); |
55 | | |
56 | | /* some chinese fonts only ship the similarly looking 0x2026 */ |
57 | 35.9M | if (gid == 0 && cid == 0x22ef) |
58 | 0 | gid = FT_Get_Char_Index(face, 0x2026); |
59 | | |
60 | 35.9M | return gid; |
61 | 35.9M | } |
62 | | |
63 | | int ft_name_index(void *face, const char *name) |
64 | 1.21M | { |
65 | 1.21M | int code = FT_Get_Name_Index(face, (char*)name); |
66 | 1.21M | if (code == 0) |
67 | 296k | { |
68 | 296k | int unicode = fz_unicode_from_glyph_name(name); |
69 | 296k | if (unicode) |
70 | 296k | { |
71 | 296k | const char **dupnames = fz_duplicate_glyph_names_from_unicode(unicode); |
72 | 331k | while (*dupnames) |
73 | 35.2k | { |
74 | 35.2k | code = FT_Get_Name_Index(face, (char*)*dupnames); |
75 | 35.2k | if (code) |
76 | 119 | break; |
77 | 35.1k | dupnames++; |
78 | 35.1k | } |
79 | 296k | if (code == 0) |
80 | 296k | { |
81 | 296k | char buf[12]; |
82 | 296k | sprintf(buf, "uni%04X", unicode); |
83 | 296k | code = FT_Get_Name_Index(face, buf); |
84 | 296k | } |
85 | 296k | } |
86 | 296k | } |
87 | 1.21M | return code; |
88 | 1.21M | } |
89 | | |
90 | | static void fz_drop_freetype(fz_context *ctx); |
91 | | |
92 | | static fz_font * |
93 | | fz_new_font(fz_context *ctx, const char *name, int use_glyph_bbox, int glyph_count) |
94 | 27.5k | { |
95 | 27.5k | fz_font *font; |
96 | | |
97 | 27.5k | font = fz_malloc_struct(ctx, fz_font); |
98 | 27.5k | font->refs = 1; |
99 | | |
100 | 27.5k | if (name) |
101 | 27.5k | fz_strlcpy(font->name, name, sizeof font->name); |
102 | 0 | else |
103 | 0 | fz_strlcpy(font->name, "(null)", sizeof font->name); |
104 | | |
105 | 27.5k | font->ft_face = NULL; |
106 | 27.5k | font->flags.ft_substitute = 0; |
107 | 27.5k | font->flags.fake_bold = 0; |
108 | 27.5k | font->flags.fake_italic = 0; |
109 | 27.5k | font->flags.has_opentype = 0; |
110 | 27.5k | font->flags.embed = 0; |
111 | 27.5k | font->flags.never_embed = 0; |
112 | | |
113 | 27.5k | font->t3matrix = fz_identity; |
114 | 27.5k | font->t3resources = NULL; |
115 | 27.5k | font->t3procs = NULL; |
116 | 27.5k | font->t3lists = NULL; |
117 | 27.5k | font->t3widths = NULL; |
118 | 27.5k | font->t3flags = NULL; |
119 | 27.5k | font->t3doc = NULL; |
120 | 27.5k | font->t3run = NULL; |
121 | | |
122 | 27.5k | font->bbox.x0 = 0; |
123 | 27.5k | font->bbox.y0 = 0; |
124 | 27.5k | font->bbox.x1 = 1; |
125 | 27.5k | font->bbox.y1 = 1; |
126 | | |
127 | 27.5k | font->glyph_count = glyph_count; |
128 | | |
129 | 27.5k | font->bbox_table = NULL; |
130 | 27.5k | font->use_glyph_bbox = use_glyph_bbox; |
131 | | |
132 | 27.5k | font->width_count = 0; |
133 | 27.5k | font->width_table = NULL; |
134 | | |
135 | 27.5k | font->subfont = 0; |
136 | | |
137 | 27.5k | return font; |
138 | 27.5k | } |
139 | | |
140 | | fz_font * |
141 | | fz_keep_font(fz_context *ctx, fz_font *font) |
142 | 980k | { |
143 | 980k | return fz_keep_imp(ctx, font, &font->refs); |
144 | 980k | } |
145 | | |
146 | | static void |
147 | | free_resources(fz_context *ctx, fz_font *font) |
148 | 28.0k | { |
149 | 28.0k | int i; |
150 | | |
151 | 28.0k | if (font->t3resources) |
152 | 539 | { |
153 | 539 | font->t3freeres(ctx, font->t3doc, font->t3resources); |
154 | 539 | font->t3resources = NULL; |
155 | 539 | } |
156 | | |
157 | 28.0k | if (font->t3procs) |
158 | 547 | { |
159 | 140k | for (i = 0; i < 256; i++) |
160 | 140k | fz_drop_buffer(ctx, font->t3procs[i]); |
161 | 547 | } |
162 | 28.0k | fz_free(ctx, font->t3procs); |
163 | 28.0k | font->t3procs = NULL; |
164 | 28.0k | } |
165 | | |
166 | | /* |
167 | | Internal function to remove the |
168 | | references to a document held by a Type3 font. This is |
169 | | called during document destruction to ensure that Type3 |
170 | | fonts clean up properly. |
171 | | |
172 | | Without this call being made, Type3 fonts can be left |
173 | | holding pdf_obj references for the sake of interpretation |
174 | | operations that will never come. These references |
175 | | cannot be freed after the document, hence this function |
176 | | forces them to be freed earlier in the process. |
177 | | |
178 | | font: The font to decouple. |
179 | | |
180 | | t3doc: The document to which the font may refer. |
181 | | */ |
182 | | void fz_decouple_type3_font(fz_context *ctx, fz_font *font, void *t3doc) |
183 | 481 | { |
184 | 481 | if (!font || !t3doc || font->t3doc == NULL) |
185 | 0 | return; |
186 | | |
187 | 481 | if (font->t3doc != t3doc) |
188 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "can't decouple type3 font from a different doc"); |
189 | | |
190 | 481 | font->t3doc = NULL; |
191 | 481 | free_resources(ctx, font); |
192 | 481 | } |
193 | | |
194 | | void |
195 | | fz_drop_font(fz_context *ctx, fz_font *font) |
196 | 8.23M | { |
197 | 8.23M | int fterr; |
198 | 8.23M | int i; |
199 | | |
200 | 8.23M | if (!fz_drop_imp(ctx, font, &font->refs)) |
201 | 8.20M | return; |
202 | | |
203 | 27.5k | free_resources(ctx, font); |
204 | 27.5k | if (font->t3lists) |
205 | 140k | for (i = 0; i < 256; i++) |
206 | 140k | fz_drop_display_list(ctx, font->t3lists[i]); |
207 | 27.5k | fz_free(ctx, font->t3procs); |
208 | 27.5k | fz_free(ctx, font->t3lists); |
209 | 27.5k | fz_free(ctx, font->t3widths); |
210 | 27.5k | fz_free(ctx, font->t3flags); |
211 | | |
212 | 27.5k | if (font->ft_face) |
213 | 27.0k | { |
214 | 27.0k | fz_ft_lock(ctx); |
215 | 27.0k | fterr = FT_Done_Face((FT_Face)font->ft_face); |
216 | 27.0k | fz_ft_unlock(ctx); |
217 | 27.0k | if (fterr) |
218 | 0 | fz_warn(ctx, "FT_Done_Face(%s): %s", font->name, ft_error_string(fterr)); |
219 | 27.0k | fz_drop_freetype(ctx); |
220 | 27.0k | } |
221 | | |
222 | 7.09M | for (i = 0; i < 256; ++i) |
223 | 7.06M | fz_free(ctx, font->encoding_cache[i]); |
224 | | |
225 | 27.5k | fz_drop_buffer(ctx, font->buffer); |
226 | 27.5k | if (font->bbox_table) |
227 | 14.4k | { |
228 | 14.4k | int n = (font->glyph_count+255)/256; |
229 | 140k | for (i = 0; i < n; i++) |
230 | 126k | fz_free(ctx, font->bbox_table[i]); |
231 | 14.4k | fz_free(ctx, font->bbox_table); |
232 | 14.4k | } |
233 | 27.5k | fz_free(ctx, font->width_table); |
234 | 27.5k | if (font->advance_cache) |
235 | 6.24k | { |
236 | 6.24k | int n = (font->glyph_count+255)/256; |
237 | 330k | for (i = 0; i < n; i++) |
238 | 324k | fz_free(ctx, font->advance_cache[i]); |
239 | 6.24k | fz_free(ctx, font->advance_cache); |
240 | 6.24k | } |
241 | 27.5k | if (font->shaper_data.destroy && font->shaper_data.shaper_handle) |
242 | 6.12k | { |
243 | 6.12k | font->shaper_data.destroy(ctx, font->shaper_data.shaper_handle); |
244 | 6.12k | } |
245 | 27.5k | fz_free(ctx, font); |
246 | 27.5k | } |
247 | | |
248 | | void |
249 | | fz_set_font_bbox(fz_context *ctx, fz_font *font, float xmin, float ymin, float xmax, float ymax) |
250 | 27.5k | { |
251 | 27.5k | if (xmin >= xmax || ymin >= ymax) |
252 | 804 | { |
253 | | /* Invalid bbox supplied. */ |
254 | 804 | if (font->t3procs) |
255 | 147 | { |
256 | | /* For type3 fonts we use the union of all the glyphs' bboxes. */ |
257 | 147 | font->bbox = fz_empty_rect; |
258 | 147 | } |
259 | 657 | else |
260 | 657 | { |
261 | | /* For other fonts it would be prohibitively slow to measure the true one, so make one up. */ |
262 | 657 | font->bbox = fz_unit_rect; |
263 | 657 | } |
264 | 804 | font->flags.invalid_bbox = 1; |
265 | 804 | } |
266 | 26.7k | else |
267 | 26.7k | { |
268 | 26.7k | font->bbox.x0 = xmin; |
269 | 26.7k | font->bbox.y0 = ymin; |
270 | 26.7k | font->bbox.x1 = xmax; |
271 | 26.7k | font->bbox.y1 = ymax; |
272 | 26.7k | } |
273 | 27.5k | } |
274 | | |
275 | | float fz_font_ascender(fz_context *ctx, fz_font *font) |
276 | 0 | { |
277 | 0 | return font->ascender; |
278 | 0 | } |
279 | | |
280 | | float fz_font_descender(fz_context *ctx, fz_font *font) |
281 | 0 | { |
282 | 0 | return font->descender; |
283 | 0 | } |
284 | | |
285 | | /* |
286 | | * Freetype hooks |
287 | | */ |
288 | | |
289 | | struct fz_font_context |
290 | | { |
291 | | int ctx_refs; |
292 | | FT_Library ftlib; |
293 | | struct FT_MemoryRec_ ftmemory; |
294 | | int ftlib_refs; |
295 | | fz_load_system_font_fn *load_font; |
296 | | fz_load_system_cjk_font_fn *load_cjk_font; |
297 | | fz_load_system_fallback_font_fn *load_fallback_font; |
298 | | |
299 | | /* Cached fallback fonts */ |
300 | | fz_font *base14[14]; |
301 | | fz_font *cjk[4]; |
302 | | struct { fz_font *serif, *sans; } fallback[256]; |
303 | | fz_font *symbol1, *symbol2, *math, *music, *boxes; |
304 | | fz_font *emoji; |
305 | | }; |
306 | | |
307 | | #undef __FTERRORS_H__ |
308 | | #define FT_ERRORDEF(e, v, s) { (e), (s) }, |
309 | | #define FT_ERROR_START_LIST |
310 | | #define FT_ERROR_END_LIST { 0, NULL } |
311 | | |
312 | | struct ft_error |
313 | | { |
314 | | int err; |
315 | | char *str; |
316 | | }; |
317 | | |
318 | | static void *ft_alloc(FT_Memory memory, long size) |
319 | 12.8M | { |
320 | 12.8M | fz_context *ctx = (fz_context *) memory->user; |
321 | 12.8M | return Memento_label(fz_malloc_no_throw(ctx, size), "ft_alloc"); |
322 | 12.8M | } |
323 | | |
324 | | static void ft_free(FT_Memory memory, void *block) |
325 | 12.8M | { |
326 | 12.8M | fz_context *ctx = (fz_context *) memory->user; |
327 | 12.8M | fz_free(ctx, block); |
328 | 12.8M | } |
329 | | |
330 | | static void *ft_realloc(FT_Memory memory, long cur_size, long new_size, void *block) |
331 | 1.27M | { |
332 | 1.27M | fz_context *ctx = (fz_context *) memory->user; |
333 | 1.27M | void *newblock = NULL; |
334 | 1.27M | if (new_size == 0) |
335 | 0 | { |
336 | 0 | fz_free(ctx, block); |
337 | 0 | return newblock; |
338 | 0 | } |
339 | 1.27M | if (block == NULL) |
340 | 0 | return ft_alloc(memory, new_size); |
341 | 1.27M | return fz_realloc_no_throw(ctx, block, new_size); |
342 | 1.27M | } |
343 | | |
344 | | void |
345 | | fz_ft_lock(fz_context *ctx) |
346 | 105M | { |
347 | 105M | fz_lock(ctx, FZ_LOCK_FREETYPE); |
348 | 105M | fz_lock(ctx, FZ_LOCK_ALLOC); |
349 | 105M | assert(ctx->font->ftmemory.user == NULL); |
350 | 105M | ctx->font->ftmemory.user = ctx; |
351 | 105M | fz_unlock(ctx, FZ_LOCK_ALLOC); |
352 | 105M | } |
353 | | |
354 | | void |
355 | | fz_ft_unlock(fz_context *ctx) |
356 | 105M | { |
357 | 105M | fz_lock(ctx, FZ_LOCK_ALLOC); |
358 | 105M | ctx->font->ftmemory.user = NULL; |
359 | 105M | fz_unlock(ctx, FZ_LOCK_ALLOC); |
360 | 105M | fz_unlock(ctx, FZ_LOCK_FREETYPE); |
361 | 105M | } |
362 | | |
363 | | int |
364 | | fz_ft_lock_held(fz_context *ctx) |
365 | 2 | { |
366 | | /* If this thread has locked the freetype lock already, then |
367 | | * the stored context will be this one. */ |
368 | 2 | return (ctx->font->ftmemory.user == ctx); |
369 | 2 | } |
370 | | |
371 | | void fz_new_font_context(fz_context *ctx) |
372 | 13.4k | { |
373 | 13.4k | ctx->font = fz_malloc_struct(ctx, fz_font_context); |
374 | 13.4k | ctx->font->ctx_refs = 1; |
375 | 13.4k | ctx->font->ftlib = NULL; |
376 | 13.4k | ctx->font->ftlib_refs = 0; |
377 | 13.4k | ctx->font->load_font = NULL; |
378 | 13.4k | ctx->font->ftmemory.user = NULL; |
379 | 13.4k | ctx->font->ftmemory.alloc = ft_alloc; |
380 | 13.4k | ctx->font->ftmemory.free = ft_free; |
381 | 13.4k | ctx->font->ftmemory.realloc = ft_realloc; |
382 | 13.4k | } |
383 | | |
384 | | fz_font_context * |
385 | | fz_keep_font_context(fz_context *ctx) |
386 | 0 | { |
387 | 0 | if (!ctx) |
388 | 0 | return NULL; |
389 | 0 | return fz_keep_imp(ctx, ctx->font, &ctx->font->ctx_refs); |
390 | 0 | } |
391 | | |
392 | | void fz_drop_font_context(fz_context *ctx) |
393 | 13.4k | { |
394 | 13.4k | if (!ctx) |
395 | 0 | return; |
396 | | |
397 | 13.4k | if (fz_drop_imp(ctx, ctx->font, &ctx->font->ctx_refs)) |
398 | 13.4k | { |
399 | 13.4k | int i; |
400 | | |
401 | 202k | for (i = 0; i < (int)nelem(ctx->font->base14); ++i) |
402 | 188k | fz_drop_font(ctx, ctx->font->base14[i]); |
403 | 67.4k | for (i = 0; i < (int)nelem(ctx->font->cjk); ++i) |
404 | 53.9k | fz_drop_font(ctx, ctx->font->cjk[i]); |
405 | 3.46M | for (i = 0; i < (int)nelem(ctx->font->fallback); ++i) |
406 | 3.45M | { |
407 | 3.45M | fz_drop_font(ctx, ctx->font->fallback[i].serif); |
408 | 3.45M | fz_drop_font(ctx, ctx->font->fallback[i].sans); |
409 | 3.45M | } |
410 | 13.4k | fz_drop_font(ctx, ctx->font->symbol1); |
411 | 13.4k | fz_drop_font(ctx, ctx->font->symbol2); |
412 | 13.4k | fz_drop_font(ctx, ctx->font->math); |
413 | 13.4k | fz_drop_font(ctx, ctx->font->music); |
414 | 13.4k | fz_drop_font(ctx, ctx->font->emoji); |
415 | 13.4k | fz_drop_font(ctx, ctx->font->boxes); |
416 | 13.4k | fz_free(ctx, ctx->font); |
417 | 13.4k | ctx->font = NULL; |
418 | 13.4k | } |
419 | 13.4k | } |
420 | | |
421 | | void fz_install_load_system_font_funcs(fz_context *ctx, |
422 | | fz_load_system_font_fn *f, |
423 | | fz_load_system_cjk_font_fn *f_cjk, |
424 | | fz_load_system_fallback_font_fn *f_back) |
425 | 0 | { |
426 | 0 | ctx->font->load_font = f; |
427 | 0 | ctx->font->load_cjk_font = f_cjk; |
428 | 0 | ctx->font->load_fallback_font = f_back; |
429 | 0 | } |
430 | | |
431 | | /* fz_load_*_font returns NULL if no font could be loaded (also on error) */ |
432 | | fz_font *fz_load_system_font(fz_context *ctx, const char *name, int bold, int italic, int needs_exact_metrics) |
433 | 6.84k | { |
434 | 6.84k | fz_font *font = NULL; |
435 | | |
436 | 6.84k | if (ctx->font->load_font) |
437 | 0 | { |
438 | 0 | fz_try(ctx) |
439 | 0 | font = ctx->font->load_font(ctx, name, bold, italic, needs_exact_metrics); |
440 | 0 | fz_catch(ctx) |
441 | 0 | { |
442 | 0 | fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); |
443 | 0 | fz_rethrow_if(ctx, FZ_ERROR_SYSTEM); |
444 | 0 | fz_report_error(ctx); |
445 | 0 | font = NULL; |
446 | 0 | } |
447 | 0 | } |
448 | | |
449 | 6.84k | return font; |
450 | 6.84k | } |
451 | | |
452 | | fz_font *fz_load_system_cjk_font(fz_context *ctx, const char *name, int ros, int serif) |
453 | 83 | { |
454 | 83 | fz_font *font = NULL; |
455 | | |
456 | 83 | if (ctx->font->load_cjk_font) |
457 | 0 | { |
458 | 0 | fz_try(ctx) |
459 | 0 | font = ctx->font->load_cjk_font(ctx, name, ros, serif); |
460 | 0 | fz_catch(ctx) |
461 | 0 | { |
462 | 0 | fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); |
463 | 0 | fz_rethrow_if(ctx, FZ_ERROR_SYSTEM); |
464 | 0 | fz_report_error(ctx); |
465 | 0 | font = NULL; |
466 | 0 | } |
467 | 0 | } |
468 | | |
469 | 83 | return font; |
470 | 83 | } |
471 | | |
472 | | fz_font *fz_load_system_fallback_font(fz_context *ctx, int script, int language, int serif, int bold, int italic) |
473 | 7.57k | { |
474 | 7.57k | fz_font *font = NULL; |
475 | | |
476 | 7.57k | if (ctx->font->load_fallback_font) |
477 | 0 | { |
478 | 0 | fz_try(ctx) |
479 | 0 | font = ctx->font->load_fallback_font(ctx, script, language, serif, bold, italic); |
480 | 0 | fz_catch(ctx) |
481 | 0 | { |
482 | 0 | fz_rethrow_if(ctx, FZ_ERROR_TRYLATER); |
483 | 0 | fz_rethrow_if(ctx, FZ_ERROR_SYSTEM); |
484 | 0 | fz_report_error(ctx); |
485 | 0 | font = NULL; |
486 | 0 | } |
487 | 0 | } |
488 | | |
489 | 7.57k | return font; |
490 | 7.57k | } |
491 | | |
492 | | fz_font *fz_load_fallback_font(fz_context *ctx, int script, int language, int serif, int bold, int italic) |
493 | 427k | { |
494 | 427k | fz_font **fontp; |
495 | 427k | const unsigned char *data; |
496 | 427k | int ordering = FZ_ADOBE_JAPAN; |
497 | 427k | int index; |
498 | 427k | int subfont; |
499 | 427k | int size; |
500 | | |
501 | 427k | if (script < 0 || script >= (int)nelem(ctx->font->fallback)) |
502 | 0 | return NULL; |
503 | | |
504 | | /* TODO: bold and italic */ |
505 | | |
506 | 427k | index = script; |
507 | 427k | if (script == UCDN_SCRIPT_HAN) |
508 | 296k | { |
509 | 296k | switch (language) |
510 | 296k | { |
511 | 34.9k | case FZ_LANG_ja: index = UCDN_LAST_SCRIPT + 1; ordering = FZ_ADOBE_JAPAN; break; |
512 | 34.9k | case FZ_LANG_ko: index = UCDN_LAST_SCRIPT + 2; ordering = FZ_ADOBE_KOREA; break; |
513 | 34.9k | case FZ_LANG_zh_Hans: index = UCDN_LAST_SCRIPT + 3; ordering = FZ_ADOBE_GB; break; |
514 | 34.9k | case FZ_LANG_zh_Hant: index = UCDN_LAST_SCRIPT + 4; ordering = FZ_ADOBE_CNS; break; |
515 | 296k | } |
516 | 296k | } |
517 | 427k | if (script == UCDN_SCRIPT_ARABIC) |
518 | 44.1k | { |
519 | 44.1k | if (language == FZ_LANG_ur || language == FZ_LANG_urd) |
520 | 0 | index = UCDN_LAST_SCRIPT + 5; |
521 | 44.1k | } |
522 | | |
523 | 427k | if (serif) |
524 | 427k | fontp = &ctx->font->fallback[index].serif; |
525 | 0 | else |
526 | 0 | fontp = &ctx->font->fallback[index].sans; |
527 | | |
528 | 427k | if (!*fontp) |
529 | 7.57k | { |
530 | 7.57k | *fontp = fz_load_system_fallback_font(ctx, script, language, serif, bold, italic); |
531 | 7.57k | if (!*fontp) |
532 | 7.57k | { |
533 | 7.57k | data = fz_lookup_noto_font(ctx, script, language, &size, &subfont); |
534 | 7.57k | if (data) |
535 | 7.57k | { |
536 | 7.57k | *fontp = fz_new_font_from_memory(ctx, NULL, data, size, subfont, 0); |
537 | | /* Noto fonts can be embedded. */ |
538 | 7.57k | fz_set_font_embedding(ctx, *fontp, 1); |
539 | 7.57k | } |
540 | 7.57k | } |
541 | 7.57k | } |
542 | | |
543 | 427k | switch (script) |
544 | 427k | { |
545 | 11.0k | case UCDN_SCRIPT_HANGUL: script = UCDN_SCRIPT_HAN; ordering = FZ_ADOBE_KOREA; break; |
546 | 187 | case UCDN_SCRIPT_HIRAGANA: script = UCDN_SCRIPT_HAN; ordering = FZ_ADOBE_JAPAN; break; |
547 | 3.15k | case UCDN_SCRIPT_KATAKANA: script = UCDN_SCRIPT_HAN; ordering = FZ_ADOBE_JAPAN; break; |
548 | 2.65k | case UCDN_SCRIPT_BOPOMOFO: script = UCDN_SCRIPT_HAN; ordering = FZ_ADOBE_CNS; break; |
549 | 427k | } |
550 | 427k | if (*fontp && (script == UCDN_SCRIPT_HAN)) |
551 | 313k | { |
552 | 313k | (*fontp)->flags.cjk = 1; |
553 | 313k | (*fontp)->flags.cjk_lang = ordering; |
554 | 313k | } |
555 | | |
556 | 427k | return *fontp; |
557 | 427k | } |
558 | | |
559 | | static fz_font *fz_load_fallback_math_font(fz_context *ctx) |
560 | 58.3k | { |
561 | 58.3k | const unsigned char *data; |
562 | 58.3k | int size; |
563 | 58.3k | if (!ctx->font->math) |
564 | 546 | { |
565 | 546 | data = fz_lookup_noto_math_font(ctx, &size); |
566 | 546 | if (data) |
567 | 546 | ctx->font->math = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0); |
568 | 546 | } |
569 | 58.3k | return ctx->font->math; |
570 | 58.3k | } |
571 | | |
572 | | static fz_font *fz_load_fallback_music_font(fz_context *ctx) |
573 | 53.9k | { |
574 | 53.9k | const unsigned char *data; |
575 | 53.9k | int size; |
576 | 53.9k | if (!ctx->font->music) |
577 | 545 | { |
578 | 545 | data = fz_lookup_noto_music_font(ctx, &size); |
579 | 545 | if (data) |
580 | 545 | ctx->font->music = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0); |
581 | 545 | } |
582 | 53.9k | return ctx->font->music; |
583 | 53.9k | } |
584 | | |
585 | | static fz_font *fz_load_fallback_symbol1_font(fz_context *ctx) |
586 | 53.9k | { |
587 | 53.9k | const unsigned char *data; |
588 | 53.9k | int size; |
589 | 53.9k | if (!ctx->font->symbol1) |
590 | 545 | { |
591 | 545 | data = fz_lookup_noto_symbol1_font(ctx, &size); |
592 | 545 | if (data) |
593 | 545 | ctx->font->symbol1 = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0); |
594 | 545 | } |
595 | 53.9k | return ctx->font->symbol1; |
596 | 53.9k | } |
597 | | |
598 | | static fz_font *fz_load_fallback_symbol2_font(fz_context *ctx) |
599 | 53.3k | { |
600 | 53.3k | const unsigned char *data; |
601 | 53.3k | int size; |
602 | 53.3k | if (!ctx->font->symbol2) |
603 | 545 | { |
604 | 545 | data = fz_lookup_noto_symbol2_font(ctx, &size); |
605 | 545 | if (data) |
606 | 545 | ctx->font->symbol2 = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0); |
607 | 545 | } |
608 | 53.3k | return ctx->font->symbol2; |
609 | 53.3k | } |
610 | | |
611 | | static fz_font *fz_load_fallback_emoji_font(fz_context *ctx) |
612 | 43.5k | { |
613 | 43.5k | const unsigned char *data; |
614 | 43.5k | int size; |
615 | 43.5k | if (!ctx->font->emoji) |
616 | 329 | { |
617 | 329 | data = fz_lookup_noto_emoji_font(ctx, &size); |
618 | 329 | if (data) |
619 | 329 | ctx->font->emoji = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0); |
620 | 329 | } |
621 | 43.5k | return ctx->font->emoji; |
622 | 43.5k | } |
623 | | |
624 | | static fz_font *fz_load_fallback_boxes_font(fz_context *ctx) |
625 | 43.5k | { |
626 | 43.5k | const unsigned char *data; |
627 | 43.5k | int size; |
628 | 43.5k | if (!ctx->font->boxes) |
629 | 329 | { |
630 | 329 | data = fz_lookup_noto_boxes_font(ctx, &size); |
631 | 329 | if (data) |
632 | 329 | ctx->font->boxes = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0); |
633 | 329 | } |
634 | 43.5k | return ctx->font->boxes; |
635 | 43.5k | } |
636 | | |
637 | | static const struct ft_error ft_errors[] = |
638 | | { |
639 | | #include FT_ERRORS_H |
640 | | }; |
641 | | |
642 | | const char *ft_error_string(int err) |
643 | 603k | { |
644 | 603k | const struct ft_error *e; |
645 | | |
646 | 13.2M | for (e = ft_errors; e->str; e++) |
647 | 13.2M | if (e->err == err) |
648 | 603k | return e->str; |
649 | | |
650 | 0 | return "Unknown error"; |
651 | 603k | } |
652 | | |
653 | | static void |
654 | | fz_keep_freetype(fz_context *ctx) |
655 | 29.2k | { |
656 | 29.2k | int fterr; |
657 | 29.2k | int maj, min, pat; |
658 | 29.2k | fz_font_context *fct = ctx->font; |
659 | | |
660 | 29.2k | fz_ft_lock(ctx); |
661 | 29.2k | if (fct->ftlib) |
662 | 21.7k | { |
663 | 21.7k | fct->ftlib_refs++; |
664 | 21.7k | fz_ft_unlock(ctx); |
665 | 21.7k | return; |
666 | 21.7k | } |
667 | | |
668 | 7.44k | fterr = FT_New_Library(&fct->ftmemory, &fct->ftlib); |
669 | 7.44k | if (fterr) |
670 | 0 | { |
671 | 0 | const char *mess = ft_error_string(fterr); |
672 | 0 | fz_ft_unlock(ctx); |
673 | 0 | fz_throw(ctx, FZ_ERROR_LIBRARY, "cannot init freetype: %s", mess); |
674 | 0 | } |
675 | | |
676 | 7.44k | FT_Add_Default_Modules(fct->ftlib); |
677 | | |
678 | 7.44k | FT_Library_Version(fct->ftlib, &maj, &min, &pat); |
679 | 7.44k | if (maj == 2 && min == 1 && pat < 7) |
680 | 0 | { |
681 | 0 | fterr = FT_Done_Library(fct->ftlib); |
682 | 0 | if (fterr) |
683 | 0 | fz_warn(ctx, "FT_Done_Library(): %s", ft_error_string(fterr)); |
684 | 0 | fz_ft_unlock(ctx); |
685 | 0 | fz_throw(ctx, FZ_ERROR_LIBRARY, "freetype version too old: %d.%d.%d", maj, min, pat); |
686 | 0 | } |
687 | | |
688 | 7.44k | fct->ftlib_refs++; |
689 | 7.44k | fz_ft_unlock(ctx); |
690 | 7.44k | } |
691 | | |
692 | | static void |
693 | | fz_drop_freetype(fz_context *ctx) |
694 | 29.2k | { |
695 | 29.2k | int fterr; |
696 | 29.2k | fz_font_context *fct = ctx->font; |
697 | | |
698 | 29.2k | fz_ft_lock(ctx); |
699 | 29.2k | if (--fct->ftlib_refs == 0) |
700 | 7.44k | { |
701 | 7.44k | fterr = FT_Done_Library(fct->ftlib); |
702 | 7.44k | if (fterr) |
703 | 0 | fz_warn(ctx, "FT_Done_Library(): %s", ft_error_string(fterr)); |
704 | 7.44k | fct->ftlib = NULL; |
705 | 7.44k | } |
706 | 29.2k | fz_ft_unlock(ctx); |
707 | 29.2k | } |
708 | | |
709 | | fz_font * |
710 | | fz_new_font_from_buffer(fz_context *ctx, const char *name, fz_buffer *buffer, int index, int use_glyph_bbox) |
711 | 29.2k | { |
712 | 29.2k | FT_Face face; |
713 | 29.2k | TT_OS2 *os2; |
714 | 29.2k | fz_font *font; |
715 | 29.2k | int fterr; |
716 | 29.2k | FT_ULong tag, size, i, n; |
717 | 29.2k | FT_UShort flags; |
718 | 29.2k | char namebuf[sizeof(font->name)]; |
719 | | |
720 | 29.2k | fz_keep_freetype(ctx); |
721 | | |
722 | 29.2k | fz_ft_lock(ctx); |
723 | 29.2k | fterr = FT_New_Memory_Face(ctx->font->ftlib, buffer->data, (FT_Long)buffer->len, index, &face); |
724 | 29.2k | fz_ft_unlock(ctx); |
725 | 29.2k | if (fterr) |
726 | 2.16k | { |
727 | 2.16k | fz_drop_freetype(ctx); |
728 | 2.16k | fz_throw(ctx, FZ_ERROR_LIBRARY, "FT_New_Memory_Face(%s): %s", name, ft_error_string(fterr)); |
729 | 2.16k | } |
730 | | |
731 | 27.0k | if (!name) |
732 | 11.3k | { |
733 | 11.3k | if (!face->family_name) |
734 | 0 | { |
735 | 0 | name = face->style_name; |
736 | 0 | } |
737 | 11.3k | else if (!face->style_name) |
738 | 0 | { |
739 | 0 | name = face->family_name; |
740 | 0 | } |
741 | 11.3k | else if (strstr(face->style_name, face->family_name) == face->style_name) |
742 | 0 | { |
743 | 0 | name = face->style_name; |
744 | 0 | } |
745 | 11.3k | else |
746 | 11.3k | { |
747 | 11.3k | fz_strlcpy(namebuf, face->family_name, sizeof(namebuf)); |
748 | 11.3k | fz_strlcat(namebuf, " ", sizeof(namebuf)); |
749 | 11.3k | fz_strlcat(namebuf, face->style_name, sizeof(namebuf)); |
750 | 11.3k | name = namebuf; |
751 | 11.3k | } |
752 | 11.3k | } |
753 | | |
754 | 54.0k | fz_try(ctx) |
755 | 54.0k | font = fz_new_font(ctx, name, use_glyph_bbox, face->num_glyphs); |
756 | 54.0k | fz_catch(ctx) |
757 | 0 | { |
758 | 0 | fz_ft_lock(ctx); |
759 | 0 | fterr = FT_Done_Face(face); |
760 | 0 | fz_ft_unlock(ctx); |
761 | 0 | if (fterr) |
762 | 0 | fz_warn(ctx, "FT_Done_Face(%s): %s", name, ft_error_string(fterr)); |
763 | 0 | fz_drop_freetype(ctx); |
764 | 0 | fz_rethrow(ctx); |
765 | 0 | } |
766 | | |
767 | 27.0k | font->ft_face = face; |
768 | 27.0k | fz_set_font_bbox(ctx, font, |
769 | 27.0k | (float) face->bbox.xMin / face->units_per_EM, |
770 | 27.0k | (float) face->bbox.yMin / face->units_per_EM, |
771 | 27.0k | (float) face->bbox.xMax / face->units_per_EM, |
772 | 27.0k | (float) face->bbox.yMax / face->units_per_EM); |
773 | | |
774 | 27.0k | if (face->ascender == 0) |
775 | 69 | font->ascender = 0.8f; |
776 | 26.9k | else |
777 | 26.9k | font->ascender = (float)face->ascender / face->units_per_EM; |
778 | | |
779 | 27.0k | if (face->descender == 0) |
780 | 184 | font->descender = -0.2f; |
781 | 26.8k | else |
782 | 26.8k | font->descender = (float)face->descender / face->units_per_EM; |
783 | | |
784 | 27.0k | font->subfont = index; |
785 | | |
786 | 27.0k | font->flags.is_mono = !!(face->face_flags & FT_FACE_FLAG_FIXED_WIDTH); |
787 | 27.0k | font->flags.is_serif = 1; |
788 | 27.0k | font->flags.is_bold = !!(face->style_flags & FT_STYLE_FLAG_BOLD); |
789 | 27.0k | font->flags.is_italic = !!(face->style_flags & FT_STYLE_FLAG_ITALIC); |
790 | 27.0k | font->flags.embed = 1; |
791 | 27.0k | font->flags.never_embed = 0; |
792 | | |
793 | 27.0k | if (FT_IS_SFNT(face)) |
794 | 12.6k | { |
795 | 12.6k | fz_ft_lock(ctx); |
796 | 12.6k | os2 = FT_Get_Sfnt_Table(face, FT_SFNT_OS2); |
797 | 12.6k | if (os2) |
798 | 11.2k | font->flags.is_serif = !(os2->sFamilyClass & 2048); /* Class 8 is sans-serif */ |
799 | | |
800 | 12.6k | flags = FT_Get_FSType_Flags(face); |
801 | 12.6k | if (flags & (FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING | |
802 | 12.6k | FT_FSTYPE_BITMAP_EMBEDDING_ONLY)) |
803 | 33 | { |
804 | 33 | font->flags.never_embed = 1; |
805 | 33 | font->flags.embed = 0; |
806 | 33 | } |
807 | | |
808 | 12.6k | FT_Sfnt_Table_Info(face, 0, NULL, &n); |
809 | 171k | for (i = 0; i < n; ++i) |
810 | 159k | { |
811 | 159k | FT_Sfnt_Table_Info(face, i, &tag, &size); |
812 | 159k | if (tag == TTAG_GDEF || tag == TTAG_GPOS || tag == TTAG_GSUB) |
813 | 26.6k | font->flags.has_opentype = 1; |
814 | 159k | } |
815 | 12.6k | fz_ft_unlock(ctx); |
816 | 12.6k | } |
817 | | |
818 | 27.0k | if (name) |
819 | 27.0k | { |
820 | 27.0k | if (!font->flags.is_bold) |
821 | 25.3k | { |
822 | 25.3k | if (strstr(name, "Semibold")) font->flags.is_bold = 1; |
823 | 25.3k | if (strstr(name, "Bold")) font->flags.is_bold = 1; |
824 | 25.3k | } |
825 | 27.0k | if (!font->flags.is_italic) |
826 | 25.9k | { |
827 | 25.9k | if (strstr(name, "Italic")) font->flags.is_italic = 1; |
828 | 25.9k | if (strstr(name, "Oblique")) font->flags.is_italic = 1; |
829 | 25.9k | } |
830 | 27.0k | } |
831 | | |
832 | 27.0k | font->buffer = fz_keep_buffer(ctx, buffer); |
833 | | |
834 | 27.0k | return font; |
835 | 27.0k | } |
836 | | |
837 | | fz_font * |
838 | | fz_new_font_from_memory(fz_context *ctx, const char *name, const unsigned char *data, int len, int index, int use_glyph_bbox) |
839 | 19.2k | { |
840 | 19.2k | fz_buffer *buffer = fz_new_buffer_from_shared_data(ctx, data, len); |
841 | 19.2k | fz_font *font = NULL; |
842 | 38.4k | fz_try(ctx) |
843 | 38.4k | font = fz_new_font_from_buffer(ctx, name, buffer, index, use_glyph_bbox); |
844 | 38.4k | fz_always(ctx) |
845 | 19.2k | fz_drop_buffer(ctx, buffer); |
846 | 19.2k | fz_catch(ctx) |
847 | 0 | fz_rethrow(ctx); |
848 | 19.2k | return font; |
849 | 19.2k | } |
850 | | |
851 | | fz_font * |
852 | | fz_new_font_from_file(fz_context *ctx, const char *name, const char *path, int index, int use_glyph_bbox) |
853 | 0 | { |
854 | 0 | fz_buffer *buffer = fz_read_file(ctx, path); |
855 | 0 | fz_font *font = NULL; |
856 | 0 | fz_try(ctx) |
857 | 0 | font = fz_new_font_from_buffer(ctx, name, buffer, index, use_glyph_bbox); |
858 | 0 | fz_always(ctx) |
859 | 0 | fz_drop_buffer(ctx, buffer); |
860 | 0 | fz_catch(ctx) |
861 | 0 | fz_rethrow(ctx); |
862 | 0 | return font; |
863 | 0 | } |
864 | | |
865 | | void fz_set_font_embedding(fz_context *ctx, fz_font *font, int embed) |
866 | 8.48k | { |
867 | 8.48k | if (!font) |
868 | 0 | return; |
869 | 8.48k | if (embed) |
870 | 8.48k | { |
871 | 8.48k | if (font->flags.never_embed) |
872 | 0 | fz_warn(ctx, "not allowed to embed font: %s", font->name); |
873 | 8.48k | else |
874 | 8.48k | font->flags.embed = 1; |
875 | 8.48k | } |
876 | 0 | else |
877 | 0 | { |
878 | 0 | font->flags.embed = 0; |
879 | 0 | } |
880 | 8.48k | } |
881 | | |
882 | | static int |
883 | | find_base14_index(const char *name) |
884 | 46.8k | { |
885 | 46.8k | if (!strcmp(name, "Courier")) return 0; |
886 | 45.9k | if (!strcmp(name, "Courier-Oblique")) return 1; |
887 | 45.9k | if (!strcmp(name, "Courier-Bold")) return 2; |
888 | 45.9k | if (!strcmp(name, "Courier-BoldOblique")) return 3; |
889 | 45.9k | if (!strcmp(name, "Helvetica")) return 4; |
890 | 44.2k | if (!strcmp(name, "Helvetica-Oblique")) return 5; |
891 | 44.2k | if (!strcmp(name, "Helvetica-Bold")) return 6; |
892 | 44.2k | if (!strcmp(name, "Helvetica-BoldOblique")) return 7; |
893 | 44.2k | if (!strcmp(name, "Times-Roman")) return 8; |
894 | 43.9k | if (!strcmp(name, "Times-Italic")) return 9; |
895 | 43.9k | if (!strcmp(name, "Times-Bold")) return 10; |
896 | 43.9k | if (!strcmp(name, "Times-BoldItalic")) return 11; |
897 | 43.9k | if (!strcmp(name, "Symbol")) return 12; |
898 | 390 | if (!strcmp(name, "ZapfDingbats")) return 13; |
899 | 0 | return -1; |
900 | 390 | } |
901 | | |
902 | | fz_font * |
903 | | fz_new_base14_font(fz_context *ctx, const char *name) |
904 | 46.8k | { |
905 | 46.8k | const unsigned char *data; |
906 | 46.8k | int size; |
907 | 46.8k | int x = find_base14_index(name); |
908 | 46.8k | if (x >= 0) |
909 | 46.8k | { |
910 | 46.8k | if (ctx->font->base14[x]) |
911 | 45.8k | return fz_keep_font(ctx, ctx->font->base14[x]); |
912 | 916 | data = fz_lookup_base14_font(ctx, name, &size); |
913 | 916 | if (data) |
914 | 916 | { |
915 | 916 | ctx->font->base14[x] = fz_new_font_from_memory(ctx, name, data, size, 0, 1); |
916 | 916 | ctx->font->base14[x]->flags.is_serif = (name[0] == 'T'); /* Times-Roman */ |
917 | | /* Ideally we should not embed base14 fonts by default, but we have to |
918 | | * allow it for now until we have written code in pdf-device to output |
919 | | * base14s in a 'special' manner. */ |
920 | 916 | fz_set_font_embedding(ctx, ctx->font->base14[x], 1); |
921 | 916 | return fz_keep_font(ctx, ctx->font->base14[x]); |
922 | 916 | } |
923 | 916 | } |
924 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot find builtin font with name '%s'", name); |
925 | 46.8k | } |
926 | | |
927 | | fz_font * |
928 | | fz_new_cjk_font(fz_context *ctx, int ordering) |
929 | 0 | { |
930 | 0 | const unsigned char *data; |
931 | 0 | int size, index; |
932 | 0 | fz_font *font; |
933 | 0 | if (ordering >= 0 && ordering < (int)nelem(ctx->font->cjk)) |
934 | 0 | { |
935 | 0 | if (ctx->font->cjk[ordering]) |
936 | 0 | return fz_keep_font(ctx, ctx->font->cjk[ordering]); |
937 | 0 | data = fz_lookup_cjk_font(ctx, ordering, &size, &index); |
938 | 0 | if (data) |
939 | 0 | font = fz_new_font_from_memory(ctx, NULL, data, size, index, 0); |
940 | 0 | else |
941 | 0 | font = fz_load_system_cjk_font(ctx, "SourceHanSerif", ordering, 1); |
942 | | /* FIXME: Currently the builtin one at least will be set to embed. Is that right? */ |
943 | 0 | if (font) |
944 | 0 | { |
945 | 0 | font->flags.cjk = 1; |
946 | 0 | font->flags.cjk_lang = ordering; |
947 | 0 | ctx->font->cjk[ordering] = font; |
948 | 0 | return fz_keep_font(ctx, ctx->font->cjk[ordering]); |
949 | 0 | } |
950 | 0 | } |
951 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot find builtin CJK font"); |
952 | 0 | } |
953 | | |
954 | | fz_font * |
955 | | fz_new_builtin_font(fz_context *ctx, const char *name, int is_bold, int is_italic) |
956 | 0 | { |
957 | 0 | const unsigned char *data; |
958 | 0 | int size; |
959 | 0 | fz_font *font; |
960 | 0 | data = fz_lookup_builtin_font(ctx, name, is_bold, is_italic, &size); |
961 | 0 | if (!data) |
962 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot find builtin font with name '%s'", name); |
963 | 0 | font = fz_new_font_from_memory(ctx, NULL, data, size, 0, 0); |
964 | | |
965 | | /* Don't embed builtin fonts. */ |
966 | 0 | fz_set_font_embedding(ctx, font, 0); |
967 | |
|
968 | 0 | return font; |
969 | 0 | } |
970 | | |
971 | | static fz_matrix * |
972 | | fz_adjust_ft_glyph_width(fz_context *ctx, fz_font *font, int gid, fz_matrix *trm) |
973 | 1.65M | { |
974 | | /* Fudge the font matrix to stretch the glyph if we've substituted the font. */ |
975 | 1.65M | if (font->flags.ft_stretch && font->width_table /* && font->wmode == 0 */) |
976 | 249k | { |
977 | 249k | FT_Error fterr; |
978 | 249k | FT_Fixed adv = 0; |
979 | 249k | float subw; |
980 | 249k | float realw; |
981 | | |
982 | 249k | fz_ft_lock(ctx); |
983 | 249k | fterr = FT_Get_Advance(font->ft_face, gid, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_TRANSFORM, &adv); |
984 | 249k | fz_ft_unlock(ctx); |
985 | 249k | if (fterr && fterr != FT_Err_Invalid_Argument) |
986 | 715 | fz_warn(ctx, "FT_Get_Advance(%s,%d): %s", font->name, gid, ft_error_string(fterr)); |
987 | | |
988 | 249k | realw = adv * 1000.0f / ((FT_Face)font->ft_face)->units_per_EM; |
989 | 249k | if (gid < font->width_count) |
990 | 244k | subw = font->width_table[gid]; |
991 | 4.74k | else |
992 | 4.74k | subw = font->width_default; |
993 | | |
994 | | /* Sanity check scaling in case of broken metrics. */ |
995 | 249k | if (realw > 0 && subw > 0) |
996 | 225k | *trm = fz_pre_scale(*trm, subw / realw, 1); |
997 | 249k | } |
998 | | |
999 | 1.65M | return trm; |
1000 | 1.65M | } |
1001 | | |
1002 | | static fz_glyph * |
1003 | | glyph_from_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap) |
1004 | 771k | { |
1005 | 771k | (void)Memento_label(bitmap->buffer, "ft_bitmap"); |
1006 | 771k | if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO) |
1007 | 0 | return fz_new_glyph_from_1bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch); |
1008 | 771k | else |
1009 | 771k | return fz_new_glyph_from_8bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch); |
1010 | 771k | } |
1011 | | |
1012 | | static fz_pixmap * |
1013 | | pixmap_from_ft_bitmap(fz_context *ctx, int left, int top, FT_Bitmap *bitmap) |
1014 | 0 | { |
1015 | 0 | (void)Memento_label(bitmap->buffer, "ft_bitmap"); |
1016 | 0 | if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO) |
1017 | 0 | return fz_new_pixmap_from_1bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch); |
1018 | 0 | else |
1019 | 0 | return fz_new_pixmap_from_8bpp_data(ctx, left, top - bitmap->rows, bitmap->width, bitmap->rows, bitmap->buffer + (bitmap->rows-1)*bitmap->pitch, -bitmap->pitch); |
1020 | 0 | } |
1021 | | |
1022 | | /* Takes the freetype lock, and returns with it held */ |
1023 | | static FT_GlyphSlot |
1024 | | do_ft_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, int aa) |
1025 | 896k | { |
1026 | 896k | FT_Face face = font->ft_face; |
1027 | 896k | FT_Matrix m; |
1028 | 896k | FT_Vector v; |
1029 | 896k | FT_Error fterr; |
1030 | | |
1031 | 896k | float strength = fz_matrix_expansion(trm) * 0.02f; |
1032 | | |
1033 | 896k | fz_adjust_ft_glyph_width(ctx, font, gid, &trm); |
1034 | | |
1035 | 896k | if (font->flags.fake_italic) |
1036 | 0 | trm = fz_pre_shear(trm, SHEAR, 0); |
1037 | | |
1038 | 896k | fz_ft_lock(ctx); |
1039 | | |
1040 | 896k | if (aa == 0) |
1041 | 0 | { |
1042 | | /* enable grid fitting for non-antialiased rendering */ |
1043 | 0 | float scale = fz_matrix_expansion(trm); |
1044 | 0 | m.xx = trm.a * 65536 / scale; |
1045 | 0 | m.yx = trm.b * 65536 / scale; |
1046 | 0 | m.xy = trm.c * 65536 / scale; |
1047 | 0 | m.yy = trm.d * 65536 / scale; |
1048 | 0 | v.x = 0; |
1049 | 0 | v.y = 0; |
1050 | |
|
1051 | 0 | fterr = FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72); |
1052 | 0 | if (fterr) |
1053 | 0 | fz_warn(ctx, "FT_Set_Char_Size(%s,%d,72): %s", font->name, (int)(64*scale), ft_error_string(fterr)); |
1054 | 0 | FT_Set_Transform(face, &m, &v); |
1055 | 0 | fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_TARGET_MONO); |
1056 | 0 | if (fterr) |
1057 | 0 | { |
1058 | 0 | fz_warn(ctx, "FT_Load_Glyph(%s,%d,FT_LOAD_TARGET_MONO): %s", font->name, gid, ft_error_string(fterr)); |
1059 | 0 | goto retry_unhinted; |
1060 | 0 | } |
1061 | 0 | } |
1062 | 896k | else |
1063 | 896k | { |
1064 | 896k | retry_unhinted: |
1065 | | /* |
1066 | | * Freetype mutilates complex glyphs if they are loaded with |
1067 | | * FT_Set_Char_Size 1.0. It rounds the coordinates before applying |
1068 | | * transformation. To get more precision in freetype, we shift part of |
1069 | | * the scale in the matrix into FT_Set_Char_Size instead. |
1070 | | */ |
1071 | | |
1072 | | /* Check for overflow; FreeType matrices use 16.16 fixed-point numbers */ |
1073 | 896k | if (trm.a < -512 || trm.a > 512) return NULL; |
1074 | 845k | if (trm.b < -512 || trm.b > 512) return NULL; |
1075 | 819k | if (trm.c < -512 || trm.c > 512) return NULL; |
1076 | 816k | if (trm.d < -512 || trm.d > 512) return NULL; |
1077 | | |
1078 | 793k | m.xx = trm.a * 64; /* should be 65536 */ |
1079 | 793k | m.yx = trm.b * 64; |
1080 | 793k | m.xy = trm.c * 64; |
1081 | 793k | m.yy = trm.d * 64; |
1082 | 793k | v.x = trm.e * 64; |
1083 | 793k | v.y = trm.f * 64; |
1084 | | |
1085 | 793k | fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ |
1086 | 793k | if (fterr) |
1087 | 0 | fz_warn(ctx, "FT_Set_Char_Size(%s,65536,72): %s", font->name, ft_error_string(fterr)); |
1088 | 793k | FT_Set_Transform(face, &m, &v); |
1089 | 793k | fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); |
1090 | 793k | if (fterr) |
1091 | 159k | { |
1092 | 159k | fz_warn(ctx, "FT_Load_Glyph(%s,%d,FT_LOAD_NO_HINTING): %s", font->name, gid, ft_error_string(fterr)); |
1093 | 159k | return NULL; |
1094 | 159k | } |
1095 | 793k | } |
1096 | | |
1097 | 634k | if (font->flags.fake_bold) |
1098 | 0 | { |
1099 | 0 | FT_Outline_Embolden(&face->glyph->outline, strength * 64); |
1100 | 0 | FT_Outline_Translate(&face->glyph->outline, -strength * 32, -strength * 32); |
1101 | 0 | } |
1102 | | |
1103 | 634k | fterr = FT_Render_Glyph(face->glyph, aa > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); |
1104 | 634k | if (fterr) |
1105 | 1 | { |
1106 | 1 | if (aa > 0) |
1107 | 1 | fz_warn(ctx, "FT_Render_Glyph(%s,%d,FT_RENDER_MODE_NORMAL): %s", font->name, gid, ft_error_string(fterr)); |
1108 | 0 | else |
1109 | 0 | fz_warn(ctx, "FT_Render_Glyph(%s,%d,FT_RENDER_MODE_MONO): %s", font->name, gid, ft_error_string(fterr)); |
1110 | 1 | return NULL; |
1111 | 1 | } |
1112 | 634k | return face->glyph; |
1113 | 634k | } |
1114 | | |
1115 | | fz_pixmap * |
1116 | | fz_render_ft_glyph_pixmap(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, int aa) |
1117 | 0 | { |
1118 | 0 | FT_GlyphSlot slot = do_ft_render_glyph(ctx, font, gid, trm, aa); |
1119 | 0 | fz_pixmap *pixmap = NULL; |
1120 | |
|
1121 | 0 | if (slot == NULL) |
1122 | 0 | { |
1123 | 0 | fz_ft_unlock(ctx); |
1124 | 0 | return NULL; |
1125 | 0 | } |
1126 | | |
1127 | 0 | fz_try(ctx) |
1128 | 0 | { |
1129 | 0 | pixmap = pixmap_from_ft_bitmap(ctx, slot->bitmap_left, slot->bitmap_top, &slot->bitmap); |
1130 | 0 | } |
1131 | 0 | fz_always(ctx) |
1132 | 0 | { |
1133 | 0 | fz_ft_unlock(ctx); |
1134 | 0 | } |
1135 | 0 | fz_catch(ctx) |
1136 | 0 | { |
1137 | 0 | fz_rethrow(ctx); |
1138 | 0 | } |
1139 | | |
1140 | 0 | return pixmap; |
1141 | 0 | } |
1142 | | |
1143 | | /* The glyph cache lock is always taken when this is called. */ |
1144 | | fz_glyph * |
1145 | | fz_render_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, int aa) |
1146 | 896k | { |
1147 | 896k | FT_GlyphSlot slot = do_ft_render_glyph(ctx, font, gid, trm, aa); |
1148 | 896k | fz_glyph *glyph = NULL; |
1149 | | |
1150 | 896k | if (slot == NULL) |
1151 | 262k | { |
1152 | 262k | fz_ft_unlock(ctx); |
1153 | 262k | return NULL; |
1154 | 262k | } |
1155 | | |
1156 | 1.26M | fz_try(ctx) |
1157 | 1.26M | { |
1158 | 634k | glyph = glyph_from_ft_bitmap(ctx, slot->bitmap_left, slot->bitmap_top, &slot->bitmap); |
1159 | 634k | } |
1160 | 1.26M | fz_always(ctx) |
1161 | 634k | { |
1162 | 634k | fz_ft_unlock(ctx); |
1163 | 634k | } |
1164 | 634k | fz_catch(ctx) |
1165 | 0 | { |
1166 | 0 | fz_rethrow(ctx); |
1167 | 0 | } |
1168 | | |
1169 | 634k | return glyph; |
1170 | 634k | } |
1171 | | |
1172 | | /* Takes the freetype lock, and returns with it held */ |
1173 | | static FT_Glyph |
1174 | | do_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, const fz_stroke_state *state, int aa) |
1175 | 163k | { |
1176 | 163k | FT_Face face = font->ft_face; |
1177 | 163k | float expansion = fz_matrix_expansion(ctm); |
1178 | 163k | int linewidth = state->linewidth * expansion * 64 / 2; |
1179 | 163k | FT_Matrix m; |
1180 | 163k | FT_Vector v; |
1181 | 163k | FT_Error fterr; |
1182 | 163k | FT_Stroker stroker; |
1183 | 163k | FT_Glyph glyph; |
1184 | 163k | FT_Stroker_LineJoin line_join; |
1185 | 163k | FT_Stroker_LineCap line_cap; |
1186 | | |
1187 | 163k | fz_adjust_ft_glyph_width(ctx, font, gid, &trm); |
1188 | | |
1189 | 163k | if (font->flags.fake_italic) |
1190 | 0 | trm = fz_pre_shear(trm, SHEAR, 0); |
1191 | | |
1192 | 163k | m.xx = trm.a * 64; /* should be 65536 */ |
1193 | 163k | m.yx = trm.b * 64; |
1194 | 163k | m.xy = trm.c * 64; |
1195 | 163k | m.yy = trm.d * 64; |
1196 | 163k | v.x = trm.e * 64; |
1197 | 163k | v.y = trm.f * 64; |
1198 | | |
1199 | 163k | fz_ft_lock(ctx); |
1200 | 163k | fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ |
1201 | 163k | if (fterr) |
1202 | 0 | { |
1203 | 0 | fz_warn(ctx, "FT_Set_Char_Size(%s,65536,72): %s", font->name, ft_error_string(fterr)); |
1204 | 0 | return NULL; |
1205 | 0 | } |
1206 | | |
1207 | 163k | FT_Set_Transform(face, &m, &v); |
1208 | | |
1209 | 163k | fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); |
1210 | 163k | if (fterr) |
1211 | 15.8k | { |
1212 | 15.8k | fz_warn(ctx, "FT_Load_Glyph(%s,%d,FT_LOAD_NO_HINTING): %s", font->name, gid, ft_error_string(fterr)); |
1213 | 15.8k | return NULL; |
1214 | 15.8k | } |
1215 | | |
1216 | 147k | fterr = FT_Stroker_New(ctx->font->ftlib, &stroker); |
1217 | 147k | if (fterr) |
1218 | 0 | { |
1219 | 0 | fz_warn(ctx, "FT_Stroker_New(): %s", ft_error_string(fterr)); |
1220 | 0 | return NULL; |
1221 | 0 | } |
1222 | | |
1223 | 147k | line_join = |
1224 | 147k | state->linejoin == FZ_LINEJOIN_MITER ? FT_STROKER_LINEJOIN_MITER_FIXED : |
1225 | 147k | state->linejoin == FZ_LINEJOIN_ROUND ? FT_STROKER_LINEJOIN_ROUND : |
1226 | 2.81k | state->linejoin == FZ_LINEJOIN_BEVEL ? FT_STROKER_LINEJOIN_BEVEL : |
1227 | 1.20k | FT_STROKER_LINEJOIN_MITER_VARIABLE; |
1228 | 147k | line_cap = |
1229 | 147k | state->start_cap == FZ_LINECAP_BUTT ? FT_STROKER_LINECAP_BUTT : |
1230 | 147k | state->start_cap == FZ_LINECAP_ROUND ? FT_STROKER_LINECAP_ROUND : |
1231 | 2.48k | state->start_cap == FZ_LINECAP_SQUARE ? FT_STROKER_LINECAP_SQUARE : |
1232 | 330 | state->start_cap == FZ_LINECAP_TRIANGLE ? FT_STROKER_LINECAP_BUTT : |
1233 | 0 | FT_STROKER_LINECAP_BUTT; |
1234 | | |
1235 | 147k | FT_Stroker_Set(stroker, linewidth, line_cap, line_join, state->miterlimit * 65536); |
1236 | | |
1237 | 147k | fterr = FT_Get_Glyph(face->glyph, &glyph); |
1238 | 147k | if (fterr) |
1239 | 4.11k | { |
1240 | 4.11k | fz_warn(ctx, "FT_Get_Glyph(): %s", ft_error_string(fterr)); |
1241 | 4.11k | FT_Stroker_Done(stroker); |
1242 | 4.11k | return NULL; |
1243 | 4.11k | } |
1244 | | |
1245 | 143k | fterr = FT_Glyph_Stroke(&glyph, stroker, 1); |
1246 | 143k | if (fterr) |
1247 | 0 | { |
1248 | 0 | fz_warn(ctx, "FT_Glyph_Stroke(): %s", ft_error_string(fterr)); |
1249 | 0 | FT_Done_Glyph(glyph); |
1250 | 0 | FT_Stroker_Done(stroker); |
1251 | 0 | return NULL; |
1252 | 0 | } |
1253 | | |
1254 | 143k | FT_Stroker_Done(stroker); |
1255 | | |
1256 | 143k | fterr = FT_Glyph_To_Bitmap(&glyph, aa > 0 ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1); |
1257 | 143k | if (fterr) |
1258 | 5.64k | { |
1259 | 5.64k | fz_warn(ctx, "FT_Glyph_To_Bitmap(): %s", ft_error_string(fterr)); |
1260 | 5.64k | FT_Done_Glyph(glyph); |
1261 | 5.64k | return NULL; |
1262 | 5.64k | } |
1263 | 137k | return glyph; |
1264 | 143k | } |
1265 | | |
1266 | | fz_glyph * |
1267 | | fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, const fz_stroke_state *state, int aa) |
1268 | 163k | { |
1269 | 163k | FT_Glyph glyph = do_render_ft_stroked_glyph(ctx, font, gid, trm, ctm, state, aa); |
1270 | 163k | FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph; |
1271 | 163k | fz_glyph *result = NULL; |
1272 | | |
1273 | 163k | if (bitmap == NULL) |
1274 | 25.6k | { |
1275 | 25.6k | fz_ft_unlock(ctx); |
1276 | 25.6k | return NULL; |
1277 | 25.6k | } |
1278 | | |
1279 | 275k | fz_try(ctx) |
1280 | 275k | { |
1281 | 137k | result = glyph_from_ft_bitmap(ctx, bitmap->left, bitmap->top, &bitmap->bitmap); |
1282 | 137k | } |
1283 | 275k | fz_always(ctx) |
1284 | 137k | { |
1285 | 137k | FT_Done_Glyph(glyph); |
1286 | 137k | fz_ft_unlock(ctx); |
1287 | 137k | } |
1288 | 137k | fz_catch(ctx) |
1289 | 0 | { |
1290 | 0 | fz_rethrow(ctx); |
1291 | 0 | } |
1292 | | |
1293 | 137k | return result; |
1294 | 137k | } |
1295 | | |
1296 | | static fz_rect * |
1297 | | get_gid_bbox(fz_context *ctx, fz_font *font, int gid) |
1298 | 6.27M | { |
1299 | 6.27M | int i; |
1300 | | |
1301 | 6.27M | if (gid < 0 || gid >= font->glyph_count || !font->use_glyph_bbox) |
1302 | 31.0k | return NULL; |
1303 | | |
1304 | 6.24M | if (font->bbox_table == NULL) { |
1305 | 14.4k | i = (font->glyph_count + 255)/256; |
1306 | 14.4k | font->bbox_table = Memento_label(fz_malloc_array(ctx, i, fz_rect *), "bbox_table(top)"); |
1307 | 14.4k | memset(font->bbox_table, 0, sizeof(fz_rect *) * i); |
1308 | 14.4k | } |
1309 | | |
1310 | 6.24M | if (font->bbox_table[gid>>8] == NULL) { |
1311 | 30.4k | font->bbox_table[gid>>8] = Memento_label(fz_malloc_array(ctx, 256, fz_rect), "bbox_table"); |
1312 | 7.82M | for (i = 0; i < 256; i++) { |
1313 | 7.79M | font->bbox_table[gid>>8][i] = fz_empty_rect; |
1314 | 7.79M | } |
1315 | 30.4k | } |
1316 | | |
1317 | 6.24M | return &font->bbox_table[gid>>8][gid & 255]; |
1318 | 6.27M | } |
1319 | | |
1320 | | static fz_rect * |
1321 | | fz_bound_ft_glyph(fz_context *ctx, fz_font *font, int gid) |
1322 | 256k | { |
1323 | 256k | FT_Face face = font->ft_face; |
1324 | 256k | FT_Error fterr; |
1325 | 256k | FT_BBox cbox; |
1326 | 256k | FT_Matrix m; |
1327 | 256k | FT_Vector v; |
1328 | 256k | fz_rect *bounds = get_gid_bbox(ctx, font, gid); |
1329 | | |
1330 | | // TODO: refactor loading into fz_load_ft_glyph |
1331 | | // TODO: cache results |
1332 | | |
1333 | 256k | const int scale = face->units_per_EM; |
1334 | 256k | const float recip = 1.0f / scale; |
1335 | 256k | const float strength = 0.02f; |
1336 | 256k | fz_matrix trm = fz_identity; |
1337 | | |
1338 | 256k | fz_adjust_ft_glyph_width(ctx, font, gid, &trm); |
1339 | | |
1340 | 256k | if (font->flags.fake_italic) |
1341 | 0 | trm = fz_pre_shear(trm, SHEAR, 0); |
1342 | | |
1343 | 256k | m.xx = trm.a * 65536; |
1344 | 256k | m.yx = trm.b * 65536; |
1345 | 256k | m.xy = trm.c * 65536; |
1346 | 256k | m.yy = trm.d * 65536; |
1347 | 256k | v.x = trm.e * 65536; |
1348 | 256k | v.y = trm.f * 65536; |
1349 | | |
1350 | 256k | fz_ft_lock(ctx); |
1351 | | /* Set the char size to scale=face->units_per_EM to effectively give |
1352 | | * us unscaled results. This avoids quantisation. We then apply the |
1353 | | * scale ourselves below. */ |
1354 | 256k | fterr = FT_Set_Char_Size(face, scale, scale, 72, 72); |
1355 | 256k | if (fterr) |
1356 | 0 | fz_warn(ctx, "FT_Set_Char_Size(%s,%d,72): %s", font->name, scale, ft_error_string(fterr)); |
1357 | 256k | FT_Set_Transform(face, &m, &v); |
1358 | | |
1359 | 256k | fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); |
1360 | 256k | if (fterr) |
1361 | 11.7k | { |
1362 | 11.7k | fz_warn(ctx, "FT_Load_Glyph(%s,%d,FT_LOAD_NO_HINTING): %s", font->name, gid, ft_error_string(fterr)); |
1363 | 11.7k | fz_ft_unlock(ctx); |
1364 | 11.7k | bounds->x0 = bounds->x1 = trm.e; |
1365 | 11.7k | bounds->y0 = bounds->y1 = trm.f; |
1366 | 11.7k | return bounds; |
1367 | 11.7k | } |
1368 | | |
1369 | 244k | if (font->flags.fake_bold) |
1370 | 0 | { |
1371 | 0 | FT_Outline_Embolden(&face->glyph->outline, strength * scale); |
1372 | 0 | FT_Outline_Translate(&face->glyph->outline, -strength * 0.5f * scale, -strength * 0.5f * scale); |
1373 | 0 | } |
1374 | | |
1375 | 244k | FT_Outline_Get_CBox(&face->glyph->outline, &cbox); |
1376 | 244k | fz_ft_unlock(ctx); |
1377 | 244k | bounds->x0 = cbox.xMin * recip; |
1378 | 244k | bounds->y0 = cbox.yMin * recip; |
1379 | 244k | bounds->x1 = cbox.xMax * recip; |
1380 | 244k | bounds->y1 = cbox.yMax * recip; |
1381 | | |
1382 | 244k | if (fz_is_empty_rect(*bounds)) |
1383 | 19.9k | { |
1384 | 19.9k | bounds->x0 = bounds->x1 = trm.e; |
1385 | 19.9k | bounds->y0 = bounds->y1 = trm.f; |
1386 | 19.9k | } |
1387 | | |
1388 | 244k | return bounds; |
1389 | 256k | } |
1390 | | |
1391 | | /* Turn FT_Outline into a fz_path */ |
1392 | | |
1393 | | struct closure { |
1394 | | fz_context *ctx; |
1395 | | fz_path *path; |
1396 | | fz_matrix trm; |
1397 | | }; |
1398 | | |
1399 | | static int move_to(const FT_Vector *p, void *cc_) |
1400 | 154k | { |
1401 | 154k | struct closure *cc = (struct closure *)cc_; |
1402 | 154k | fz_context *ctx = cc->ctx; |
1403 | 154k | fz_path *path = cc->path; |
1404 | 154k | fz_point pt; |
1405 | | |
1406 | 154k | pt = fz_transform_point_xy(p->x, p->y, cc->trm); |
1407 | 154k | fz_moveto(ctx, path, pt.x, pt.y); |
1408 | 154k | return 0; |
1409 | 154k | } |
1410 | | |
1411 | | static int line_to(const FT_Vector *p, void *cc_) |
1412 | 773k | { |
1413 | 773k | struct closure *cc = (struct closure *)cc_; |
1414 | 773k | fz_context *ctx = cc->ctx; |
1415 | 773k | fz_path *path = cc->path; |
1416 | 773k | fz_point pt; |
1417 | | |
1418 | 773k | pt = fz_transform_point_xy(p->x, p->y, cc->trm); |
1419 | 773k | fz_lineto(ctx, path, pt.x, pt.y); |
1420 | 773k | return 0; |
1421 | 773k | } |
1422 | | |
1423 | | static int conic_to(const FT_Vector *c, const FT_Vector *p, void *cc_) |
1424 | 28.7k | { |
1425 | 28.7k | struct closure *cc = (struct closure *)cc_; |
1426 | 28.7k | fz_context *ctx = cc->ctx; |
1427 | 28.7k | fz_path *path = cc->path; |
1428 | 28.7k | fz_point ct, pt; |
1429 | | |
1430 | 28.7k | ct = fz_transform_point_xy(c->x, c->y, cc->trm); |
1431 | 28.7k | pt = fz_transform_point_xy(p->x, p->y, cc->trm); |
1432 | | |
1433 | 28.7k | fz_quadto(ctx, path, ct.x, ct.y, pt.x, pt.y); |
1434 | 28.7k | return 0; |
1435 | 28.7k | } |
1436 | | |
1437 | | static int cubic_to(const FT_Vector *c1, const FT_Vector *c2, const FT_Vector *p, void *cc_) |
1438 | 849k | { |
1439 | 849k | struct closure *cc = (struct closure *)cc_; |
1440 | 849k | fz_context *ctx = cc->ctx; |
1441 | 849k | fz_path *path = cc->path; |
1442 | 849k | fz_point c1t, c2t, pt; |
1443 | | |
1444 | 849k | c1t = fz_transform_point_xy(c1->x, c1->y, cc->trm); |
1445 | 849k | c2t = fz_transform_point_xy(c2->x, c2->y, cc->trm); |
1446 | 849k | pt = fz_transform_point_xy(p->x, p->y, cc->trm); |
1447 | | |
1448 | 849k | fz_curveto(ctx, path, c1t.x, c1t.y, c2t.x, c2t.y, pt.x, pt.y); |
1449 | 849k | return 0; |
1450 | 849k | } |
1451 | | |
1452 | | static const FT_Outline_Funcs outline_funcs = { |
1453 | | move_to, line_to, conic_to, cubic_to, 0, 0 |
1454 | | }; |
1455 | | |
1456 | | fz_path * |
1457 | | fz_outline_ft_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) |
1458 | 334k | { |
1459 | 334k | struct closure cc; |
1460 | 334k | FT_Face face = font->ft_face; |
1461 | 334k | int fterr; |
1462 | | |
1463 | 334k | const int scale = 65536; |
1464 | 334k | const float recip = 1.0f / scale; |
1465 | 334k | const float strength = 0.02f; |
1466 | | |
1467 | 334k | fz_adjust_ft_glyph_width(ctx, font, gid, &trm); |
1468 | | |
1469 | 334k | if (font->flags.fake_italic) |
1470 | 0 | trm = fz_pre_shear(trm, SHEAR, 0); |
1471 | | |
1472 | 334k | fz_ft_lock(ctx); |
1473 | | |
1474 | 334k | fterr = FT_Set_Char_Size(face, scale, scale, 72, 72); |
1475 | 334k | if (fterr) |
1476 | 0 | fz_warn(ctx, "FT_Set_Char_Size(%s,%d,72): %s", font->name, scale, ft_error_string(fterr)); |
1477 | | |
1478 | 334k | fterr = FT_Load_Glyph(face, gid, FT_LOAD_IGNORE_TRANSFORM); |
1479 | 334k | if (fterr) |
1480 | 204k | { |
1481 | 204k | fz_warn(ctx, "FT_Load_Glyph(%s,%d,FT_LOAD_IGNORE_TRANSFORM): %s", font->name, gid, ft_error_string(fterr)); |
1482 | 204k | fterr = FT_Load_Glyph(face, gid, FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_NO_HINTING); |
1483 | 204k | } |
1484 | 334k | if (fterr) |
1485 | 184k | { |
1486 | 184k | fz_warn(ctx, "FT_Load_Glyph(%s,%d,FT_LOAD_IGNORE_TRANSFORM | FT_LOAD_NO_HINTING): %s", font->name, gid, ft_error_string(fterr)); |
1487 | 184k | fz_ft_unlock(ctx); |
1488 | 184k | return NULL; |
1489 | 184k | } |
1490 | | |
1491 | 149k | if (font->flags.fake_bold) |
1492 | 0 | { |
1493 | 0 | FT_Outline_Embolden(&face->glyph->outline, strength * scale); |
1494 | 0 | FT_Outline_Translate(&face->glyph->outline, -strength * 0.5f * scale, -strength * 0.5f * scale); |
1495 | 0 | } |
1496 | | |
1497 | 149k | cc.path = NULL; |
1498 | 299k | fz_try(ctx) |
1499 | 299k | { |
1500 | 149k | cc.ctx = ctx; |
1501 | 149k | cc.path = fz_new_path(ctx); |
1502 | 149k | cc.trm = fz_concat(fz_scale(recip, recip), trm); |
1503 | 149k | fz_moveto(ctx, cc.path, cc.trm.e, cc.trm.f); |
1504 | 149k | FT_Outline_Decompose(&face->glyph->outline, &outline_funcs, &cc); |
1505 | 149k | fz_closepath(ctx, cc.path); |
1506 | 149k | } |
1507 | 299k | fz_always(ctx) |
1508 | 149k | { |
1509 | 149k | fz_ft_unlock(ctx); |
1510 | 149k | } |
1511 | 149k | fz_catch(ctx) |
1512 | 0 | { |
1513 | 0 | fz_warn(ctx, "freetype cannot decompose outline"); |
1514 | 0 | fz_drop_path(ctx, cc.path); |
1515 | 0 | return NULL; |
1516 | 0 | } |
1517 | | |
1518 | 149k | return cc.path; |
1519 | 149k | } |
1520 | | |
1521 | | /* |
1522 | | Type 3 fonts... |
1523 | | */ |
1524 | | |
1525 | | fz_font * |
1526 | | fz_new_type3_font(fz_context *ctx, const char *name, fz_matrix matrix) |
1527 | 547 | { |
1528 | 547 | fz_font *font; |
1529 | | |
1530 | 547 | font = fz_new_font(ctx, name, 1, 256); |
1531 | 1.09k | fz_try(ctx) |
1532 | 1.09k | { |
1533 | 547 | font->t3procs = fz_calloc(ctx, 256, sizeof(fz_buffer*)); |
1534 | 547 | font->t3lists = fz_calloc(ctx, 256, sizeof(fz_display_list*)); |
1535 | 547 | font->t3widths = fz_calloc(ctx, 256, sizeof(float)); |
1536 | 547 | font->t3flags = fz_calloc(ctx, 256, sizeof(unsigned short)); |
1537 | 547 | } |
1538 | 1.09k | fz_catch(ctx) |
1539 | 0 | { |
1540 | 0 | fz_drop_font(ctx, font); |
1541 | 0 | fz_rethrow(ctx); |
1542 | 0 | } |
1543 | | |
1544 | 547 | font->t3matrix = matrix; |
1545 | | |
1546 | 547 | return font; |
1547 | 547 | } |
1548 | | |
1549 | | static void |
1550 | | fz_bound_t3_glyph(fz_context *ctx, fz_font *font, int gid) |
1551 | 8.48k | { |
1552 | 8.48k | fz_display_list *list; |
1553 | 8.48k | fz_device *dev; |
1554 | 8.48k | fz_rect *r = get_gid_bbox(ctx, font, gid); |
1555 | | |
1556 | 8.48k | list = font->t3lists[gid]; |
1557 | 8.48k | if (!list) |
1558 | 1.49k | { |
1559 | 1.49k | *r = fz_empty_rect; |
1560 | 1.49k | return; |
1561 | 1.49k | } |
1562 | | |
1563 | 6.98k | dev = fz_new_bbox_device(ctx, r); |
1564 | 13.9k | fz_try(ctx) |
1565 | 13.9k | { |
1566 | 6.98k | fz_run_display_list(ctx, list, dev, font->t3matrix, fz_infinite_rect, NULL); |
1567 | 6.98k | fz_close_device(ctx, dev); |
1568 | 6.98k | } |
1569 | 13.9k | fz_always(ctx) |
1570 | 6.98k | { |
1571 | 6.98k | fz_drop_device(ctx, dev); |
1572 | 6.98k | } |
1573 | 6.98k | fz_catch(ctx) |
1574 | 0 | { |
1575 | 0 | fz_rethrow(ctx); |
1576 | 0 | } |
1577 | | |
1578 | | /* Update font bbox with glyph's computed bbox if the font bbox is invalid */ |
1579 | 6.98k | if (font->flags.invalid_bbox) |
1580 | 2.10k | font->bbox = fz_union_rect(font->bbox, *r); |
1581 | 6.98k | } |
1582 | | |
1583 | | void |
1584 | | fz_prepare_t3_glyph(fz_context *ctx, fz_font *font, int gid) |
1585 | 8.45k | { |
1586 | 8.45k | fz_device *dev; |
1587 | 8.45k | fz_rect d1_rect; |
1588 | | |
1589 | | /* We've not already loaded this one! */ |
1590 | 8.45k | assert(font->t3lists[gid] == NULL); |
1591 | | |
1592 | 8.45k | font->t3lists[gid] = fz_new_display_list(ctx, font->bbox); |
1593 | | |
1594 | 8.45k | dev = fz_new_list_device(ctx, font->t3lists[gid]); |
1595 | 8.45k | dev->flags = FZ_DEVFLAG_FILLCOLOR_UNDEFINED | |
1596 | 8.45k | FZ_DEVFLAG_STROKECOLOR_UNDEFINED | |
1597 | 8.45k | FZ_DEVFLAG_STARTCAP_UNDEFINED | |
1598 | 8.45k | FZ_DEVFLAG_DASHCAP_UNDEFINED | |
1599 | 8.45k | FZ_DEVFLAG_ENDCAP_UNDEFINED | |
1600 | 8.45k | FZ_DEVFLAG_LINEJOIN_UNDEFINED | |
1601 | 8.45k | FZ_DEVFLAG_MITERLIMIT_UNDEFINED | |
1602 | 8.45k | FZ_DEVFLAG_LINEWIDTH_UNDEFINED | |
1603 | 8.45k | FZ_DEVFLAG_DASH_PATTERN_UNDEFINED; |
1604 | | |
1605 | 16.9k | fz_try(ctx) |
1606 | 16.9k | { |
1607 | 8.45k | font->t3run(ctx, font->t3doc, font->t3resources, font->t3procs[gid], dev, fz_identity, NULL, NULL, NULL, NULL); |
1608 | 8.45k | fz_close_device(ctx, dev); |
1609 | 8.45k | font->t3flags[gid] = dev->flags; |
1610 | 8.45k | d1_rect = dev->d1_rect; |
1611 | 8.45k | } |
1612 | 16.9k | fz_always(ctx) |
1613 | 8.45k | { |
1614 | 8.45k | fz_drop_device(ctx, dev); |
1615 | 8.45k | } |
1616 | 8.45k | fz_catch(ctx) |
1617 | 1 | fz_rethrow(ctx); |
1618 | 8.45k | if (fz_display_list_is_empty(ctx, font->t3lists[gid])) |
1619 | 808 | { |
1620 | 808 | fz_rect *r = get_gid_bbox(ctx, font, gid); |
1621 | | /* If empty, no need for a huge bbox, especially as the logic |
1622 | | * in the 'else if' can make it huge. */ |
1623 | 808 | r->x0 = font->flags.invalid_bbox ? 0 : font->bbox.x0; |
1624 | 808 | r->y0 = font->flags.invalid_bbox ? 0 : font->bbox.y0; |
1625 | 808 | r->x1 = r->x0 + .00001f; |
1626 | 808 | r->y1 = r->y0 + .00001f; |
1627 | 808 | } |
1628 | 7.64k | else if (font->t3flags[gid] & FZ_DEVFLAG_BBOX_DEFINED) |
1629 | 7.35k | { |
1630 | 7.35k | fz_rect *r = get_gid_bbox(ctx, font, gid); |
1631 | 7.35k | *r = fz_transform_rect(d1_rect, font->t3matrix); |
1632 | | |
1633 | 7.35k | if (font->flags.invalid_bbox || !fz_contains_rect(font->bbox, d1_rect)) |
1634 | 6.58k | { |
1635 | | /* Either the font bbox is invalid, or the d1_rect returned is |
1636 | | * incompatible with it. Either way, don't trust the d1 rect |
1637 | | * and calculate it from the contents. */ |
1638 | 6.58k | fz_bound_t3_glyph(ctx, font, gid); |
1639 | 6.58k | } |
1640 | 7.35k | } |
1641 | 292 | else |
1642 | 292 | { |
1643 | | /* No bbox has been defined for this glyph, so compute it. */ |
1644 | 292 | fz_bound_t3_glyph(ctx, font, gid); |
1645 | 292 | } |
1646 | 8.45k | } |
1647 | | |
1648 | | void |
1649 | | fz_run_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_device *dev) |
1650 | 4.10k | { |
1651 | 4.10k | fz_display_list *list; |
1652 | 4.10k | fz_matrix ctm; |
1653 | | |
1654 | 4.10k | list = font->t3lists[gid]; |
1655 | 4.10k | if (!list) |
1656 | 0 | return; |
1657 | | |
1658 | 4.10k | ctm = fz_concat(font->t3matrix, trm); |
1659 | 4.10k | fz_run_display_list(ctx, list, dev, ctm, fz_infinite_rect, NULL); |
1660 | 4.10k | } |
1661 | | |
1662 | | fz_pixmap * |
1663 | | fz_render_t3_glyph_pixmap(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_colorspace *model, const fz_irect *scissor, int aa) |
1664 | 12.2k | { |
1665 | 12.2k | fz_display_list *list; |
1666 | 12.2k | fz_rect bounds; |
1667 | 12.2k | fz_irect bbox; |
1668 | 12.2k | fz_device *dev = NULL; |
1669 | 12.2k | fz_pixmap *glyph; |
1670 | 12.2k | fz_pixmap *result = NULL; |
1671 | | |
1672 | 12.2k | if (gid < 0 || gid > 255) |
1673 | 0 | return NULL; |
1674 | | |
1675 | 12.2k | list = font->t3lists[gid]; |
1676 | 12.2k | if (!list) |
1677 | 8.19k | return NULL; |
1678 | | |
1679 | 4.10k | if (font->t3flags[gid] & FZ_DEVFLAG_MASK) |
1680 | 3.51k | { |
1681 | 3.51k | if (font->t3flags[gid] & FZ_DEVFLAG_COLOR) |
1682 | 0 | fz_warn(ctx, "type3 glyph claims to be both masked and colored"); |
1683 | 3.51k | model = NULL; |
1684 | 3.51k | } |
1685 | 589 | else if (font->t3flags[gid] & FZ_DEVFLAG_COLOR) |
1686 | 117 | { |
1687 | 117 | if (!model) |
1688 | 0 | fz_warn(ctx, "colored type3 glyph wanted in masked context"); |
1689 | 117 | } |
1690 | 472 | else |
1691 | 472 | { |
1692 | 472 | fz_warn(ctx, "type3 glyph doesn't specify masked or colored"); |
1693 | 472 | model = NULL; /* Treat as masked */ |
1694 | 472 | } |
1695 | | |
1696 | 4.10k | bounds = fz_expand_rect(fz_bound_glyph(ctx, font, gid, trm), 1); |
1697 | 4.10k | bbox = fz_irect_from_rect(bounds); |
1698 | 4.10k | bbox = fz_intersect_irect(bbox, *scissor); |
1699 | | |
1700 | | /* Glyphs must always have alpha */ |
1701 | 4.10k | glyph = fz_new_pixmap_with_bbox(ctx, model, bbox, NULL/* FIXME */, 1); |
1702 | | |
1703 | 4.10k | fz_var(dev); |
1704 | 8.20k | fz_try(ctx) |
1705 | 8.20k | { |
1706 | 4.10k | fz_clear_pixmap(ctx, glyph); |
1707 | 4.10k | dev = fz_new_draw_device_type3(ctx, fz_identity, glyph); |
1708 | 4.10k | fz_run_t3_glyph(ctx, font, gid, trm, dev); |
1709 | 4.10k | fz_close_device(ctx, dev); |
1710 | 4.10k | } |
1711 | 8.20k | fz_always(ctx) |
1712 | 4.10k | { |
1713 | 4.10k | fz_drop_device(ctx, dev); |
1714 | 4.10k | } |
1715 | 4.10k | fz_catch(ctx) |
1716 | 3 | { |
1717 | 3 | fz_drop_pixmap(ctx, glyph); |
1718 | 3 | fz_rethrow(ctx); |
1719 | 3 | } |
1720 | | |
1721 | 4.10k | if (!model) |
1722 | 3.98k | { |
1723 | 7.97k | fz_try(ctx) |
1724 | 7.97k | { |
1725 | 3.98k | result = fz_alpha_from_gray(ctx, glyph); |
1726 | 3.98k | } |
1727 | 7.97k | fz_always(ctx) |
1728 | 3.98k | { |
1729 | 3.98k | fz_drop_pixmap(ctx, glyph); |
1730 | 3.98k | } |
1731 | 3.98k | fz_catch(ctx) |
1732 | 7 | { |
1733 | 7 | fz_rethrow(ctx); |
1734 | 7 | } |
1735 | 3.98k | } |
1736 | 119 | else |
1737 | 119 | result = glyph; |
1738 | | |
1739 | 4.09k | return result; |
1740 | 4.10k | } |
1741 | | |
1742 | | fz_glyph * |
1743 | | fz_render_t3_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm, fz_colorspace *model, const fz_irect *scissor, int aa) |
1744 | 12.2k | { |
1745 | 12.2k | fz_pixmap *pixmap = fz_render_t3_glyph_pixmap(ctx, font, gid, trm, model, scissor, aa); |
1746 | 12.2k | return fz_new_glyph_from_pixmap(ctx, pixmap); |
1747 | 12.2k | } |
1748 | | |
1749 | | void |
1750 | | fz_render_t3_glyph_direct(fz_context *ctx, fz_device *dev, fz_font *font, int gid, fz_matrix trm, void *gstate, fz_default_colorspaces *def_cs, void *fill_gstate, void *stroke_gstate) |
1751 | 807 | { |
1752 | 807 | fz_matrix ctm; |
1753 | | |
1754 | 807 | if (gid < 0 || gid > 255) |
1755 | 0 | return; |
1756 | | |
1757 | 807 | if (font->t3flags[gid] & FZ_DEVFLAG_MASK) |
1758 | 389 | { |
1759 | 389 | if (font->t3flags[gid] & FZ_DEVFLAG_COLOR) |
1760 | 0 | fz_warn(ctx, "type3 glyph claims to be both masked and colored"); |
1761 | 389 | } |
1762 | 418 | else if (!(font->t3flags[gid] & FZ_DEVFLAG_COLOR)) |
1763 | 268 | { |
1764 | 268 | fz_warn(ctx, "type3 glyph doesn't specify masked or colored"); |
1765 | 268 | } |
1766 | | |
1767 | 807 | ctm = fz_concat(font->t3matrix, trm); |
1768 | 807 | font->t3run(ctx, font->t3doc, font->t3resources, font->t3procs[gid], dev, ctm, gstate, def_cs, fill_gstate, stroke_gstate); |
1769 | 807 | } |
1770 | | |
1771 | | fz_rect |
1772 | | fz_bound_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix trm) |
1773 | 6.00M | { |
1774 | 6.00M | fz_rect rect; |
1775 | 6.00M | fz_rect *r = get_gid_bbox(ctx, font, gid); |
1776 | 6.00M | if (r) |
1777 | 5.97M | { |
1778 | | /* If the bbox is infinite or empty, distrust it */ |
1779 | 5.97M | if (fz_is_infinite_rect(*r) || fz_is_empty_rect(*r)) |
1780 | 257k | { |
1781 | | /* Get the real size from the glyph */ |
1782 | 257k | if (font->ft_face) |
1783 | 256k | fz_bound_ft_glyph(ctx, font, gid); |
1784 | 1.60k | else if (font->t3lists) |
1785 | 1.60k | fz_bound_t3_glyph(ctx, font, gid); |
1786 | 0 | else |
1787 | | /* If we can't get a real size, fall back to the font |
1788 | | * bbox. */ |
1789 | 0 | *r = font->bbox; |
1790 | | /* If the real size came back as empty, then store it as |
1791 | | * a very small rectangle to avoid us calling this same |
1792 | | * check every time. */ |
1793 | 257k | if (fz_is_empty_rect(*r)) |
1794 | 33.3k | { |
1795 | 33.3k | r->x0 = 0; |
1796 | 33.3k | r->y0 = 0; |
1797 | 33.3k | r->x1 = 0.0000001f; |
1798 | 33.3k | r->y1 = 0.0000001f; |
1799 | 33.3k | } |
1800 | 257k | } |
1801 | 5.97M | rect = *r; |
1802 | 5.97M | } |
1803 | 31.0k | else |
1804 | 31.0k | { |
1805 | | /* fall back to font bbox */ |
1806 | 31.0k | rect = font->bbox; |
1807 | 31.0k | } |
1808 | 6.00M | return fz_transform_rect(rect, trm); |
1809 | 6.00M | } |
1810 | | |
1811 | | fz_path * |
1812 | | fz_outline_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix ctm) |
1813 | 342k | { |
1814 | 342k | if (!font->ft_face) |
1815 | 8.19k | return NULL; |
1816 | 334k | return fz_outline_ft_glyph(ctx, font, gid, ctm); |
1817 | 342k | } |
1818 | | |
1819 | | int fz_glyph_cacheable(fz_context *ctx, fz_font *font, int gid) |
1820 | 5.75M | { |
1821 | 5.75M | if (!font->t3procs || !font->t3flags || gid < 0 || gid >= font->glyph_count) |
1822 | 5.73M | return 1; |
1823 | 19.5k | return (font->t3flags[gid] & FZ_DEVFLAG_UNCACHEABLE) == 0; |
1824 | 5.75M | } |
1825 | | |
1826 | | static float |
1827 | | fz_advance_ft_glyph_aux(fz_context *ctx, fz_font *font, int gid, int wmode, int locked) |
1828 | 21.1M | { |
1829 | 21.1M | FT_Error fterr; |
1830 | 21.1M | FT_Fixed adv = 0; |
1831 | 21.1M | int mask; |
1832 | | |
1833 | | /* PDF and substitute font widths. */ |
1834 | 21.1M | if (font->flags.ft_stretch) |
1835 | 0 | { |
1836 | 0 | if (font->width_table) |
1837 | 0 | { |
1838 | 0 | if (gid < font->width_count) |
1839 | 0 | return font->width_table[gid] / 1000.0f; |
1840 | 0 | return font->width_default / 1000.0f; |
1841 | 0 | } |
1842 | 0 | } |
1843 | | |
1844 | 21.1M | mask = FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_TRANSFORM; |
1845 | 21.1M | if (wmode) |
1846 | 0 | mask |= FT_LOAD_VERTICAL_LAYOUT; |
1847 | 21.1M | if (!locked) |
1848 | 0 | fz_ft_lock(ctx); |
1849 | 21.1M | fterr = FT_Get_Advance(font->ft_face, gid, mask, &adv); |
1850 | 21.1M | if (!locked) |
1851 | 0 | fz_ft_unlock(ctx); |
1852 | 21.1M | if (fterr && fterr != FT_Err_Invalid_Argument) |
1853 | 0 | { |
1854 | 0 | fz_warn(ctx, "FT_Get_Advance(%s,%d): %s", font->name, gid, ft_error_string(fterr)); |
1855 | 0 | if (font->width_table) |
1856 | 0 | { |
1857 | 0 | if (gid < font->width_count) |
1858 | 0 | return font->width_table[gid] / 1000.0f; |
1859 | 0 | return font->width_default / 1000.0f; |
1860 | 0 | } |
1861 | 0 | } |
1862 | 21.1M | return (float) adv / ((FT_Face)font->ft_face)->units_per_EM; |
1863 | 21.1M | } |
1864 | | |
1865 | | static float |
1866 | | fz_advance_ft_glyph(fz_context *ctx, fz_font *font, int gid, int wmode) |
1867 | 0 | { |
1868 | 0 | return fz_advance_ft_glyph_aux(ctx, font, gid, wmode, 0); |
1869 | 0 | } |
1870 | | |
1871 | | static float |
1872 | | fz_advance_t3_glyph(fz_context *ctx, fz_font *font, int gid) |
1873 | 0 | { |
1874 | 0 | if (gid < 0 || gid > 255) |
1875 | 0 | return 0; |
1876 | 0 | return font->t3widths[gid]; |
1877 | 0 | } |
1878 | | |
1879 | | void |
1880 | | fz_get_glyph_name(fz_context *ctx, fz_font *font, int glyph, char *buf, int size) |
1881 | 0 | { |
1882 | 0 | FT_Face face = font->ft_face; |
1883 | 0 | if (face) |
1884 | 0 | { |
1885 | 0 | if (FT_HAS_GLYPH_NAMES(face)) |
1886 | 0 | { |
1887 | 0 | int fterr; |
1888 | 0 | fz_ft_lock(ctx); |
1889 | 0 | fterr = FT_Get_Glyph_Name(face, glyph, buf, size); |
1890 | 0 | fz_ft_unlock(ctx); |
1891 | 0 | if (fterr) |
1892 | 0 | fz_warn(ctx, "FT_Get_Glyph_Name(%s,%d): %s", font->name, glyph, ft_error_string(fterr)); |
1893 | 0 | } |
1894 | 0 | else |
1895 | 0 | fz_snprintf(buf, size, "%d", glyph); |
1896 | 0 | } |
1897 | 0 | else |
1898 | 0 | { |
1899 | 0 | fz_snprintf(buf, size, "%d", glyph); |
1900 | 0 | } |
1901 | 0 | } |
1902 | | |
1903 | | float |
1904 | | fz_advance_glyph(fz_context *ctx, fz_font *font, int gid, int wmode) |
1905 | 20.1M | { |
1906 | 20.1M | if (font->ft_face) |
1907 | 20.1M | { |
1908 | 20.1M | if (wmode) |
1909 | 0 | return fz_advance_ft_glyph(ctx, font, gid, 1); |
1910 | 20.1M | if (gid >= 0 && gid < font->glyph_count) |
1911 | 20.1M | { |
1912 | 20.1M | float f; |
1913 | 20.1M | int block = gid>>8; |
1914 | 20.1M | fz_ft_lock(ctx); |
1915 | 20.1M | if (!font->advance_cache) |
1916 | 6.24k | { |
1917 | 6.24k | int n = (font->glyph_count+255)/256; |
1918 | 12.4k | fz_try(ctx) |
1919 | 12.4k | font->advance_cache = Memento_label(fz_malloc_array(ctx, n, float *), "font_advance_cache"); |
1920 | 12.4k | fz_catch(ctx) |
1921 | 0 | { |
1922 | 0 | fz_ft_unlock(ctx); |
1923 | 0 | fz_rethrow(ctx); |
1924 | 0 | } |
1925 | 6.24k | memset(font->advance_cache, 0, n * sizeof(float *)); |
1926 | 6.24k | } |
1927 | 20.1M | if (!font->advance_cache[block]) |
1928 | 84.3k | { |
1929 | 84.3k | int i, n; |
1930 | 168k | fz_try(ctx) |
1931 | 168k | font->advance_cache[block] = Memento_label(fz_malloc_array(ctx, 256, float), "font_advance_cache"); |
1932 | 168k | fz_catch(ctx) |
1933 | 0 | { |
1934 | 0 | fz_ft_unlock(ctx); |
1935 | 0 | fz_rethrow(ctx); |
1936 | 0 | } |
1937 | 84.3k | n = (block<<8)+256; |
1938 | 84.3k | if (n > font->glyph_count) |
1939 | 3.62k | n = font->glyph_count; |
1940 | 84.3k | n -= (block<<8); |
1941 | 21.2M | for (i = 0; i < n; ++i) |
1942 | 21.1M | font->advance_cache[block][i] = fz_advance_ft_glyph_aux(ctx, font, (block<<8)+i, 0, 1); |
1943 | 84.3k | } |
1944 | 20.1M | f = font->advance_cache[block][gid & 255]; |
1945 | 20.1M | fz_ft_unlock(ctx); |
1946 | 20.1M | return f; |
1947 | 20.1M | } |
1948 | | |
1949 | 0 | return fz_advance_ft_glyph(ctx, font, gid, 0); |
1950 | 20.1M | } |
1951 | 0 | if (font->t3procs) |
1952 | 0 | return fz_advance_t3_glyph(ctx, font, gid); |
1953 | 0 | return 0; |
1954 | 0 | } |
1955 | | |
1956 | | int |
1957 | | fz_encode_character(fz_context *ctx, fz_font *font, int ucs) |
1958 | 1.17M | { |
1959 | 1.17M | if (font->ft_face) |
1960 | 1.17M | { |
1961 | 1.17M | int idx; |
1962 | 1.17M | if (ucs >= 0 && ucs < 0x10000) |
1963 | 1.17M | { |
1964 | 1.17M | int pg = ucs >> 8; |
1965 | 1.17M | int ix = ucs & 0xFF; |
1966 | 1.17M | if (!font->encoding_cache[pg]) |
1967 | 95.0k | { |
1968 | 95.0k | int i; |
1969 | 95.0k | font->encoding_cache[pg] = fz_malloc_array(ctx, 256, uint16_t); |
1970 | 95.0k | fz_ft_lock(ctx); |
1971 | 24.4M | for (i = 0; i < 256; ++i) |
1972 | 24.3M | font->encoding_cache[pg][i] = FT_Get_Char_Index(font->ft_face, (pg << 8) + i); |
1973 | 95.0k | fz_ft_unlock(ctx); |
1974 | 95.0k | } |
1975 | 1.17M | return font->encoding_cache[pg][ix]; |
1976 | 1.17M | } |
1977 | 6.07k | fz_ft_lock(ctx); |
1978 | 6.07k | idx = FT_Get_Char_Index(font->ft_face, ucs); |
1979 | 6.07k | fz_ft_unlock(ctx); |
1980 | 6.07k | return idx; |
1981 | 1.17M | } |
1982 | 0 | return ucs; |
1983 | 1.17M | } |
1984 | | |
1985 | | int |
1986 | | fz_encode_character_sc(fz_context *ctx, fz_font *font, int unicode) |
1987 | 0 | { |
1988 | 0 | if (font->ft_face) |
1989 | 0 | { |
1990 | 0 | int cat = ucdn_get_general_category(unicode); |
1991 | 0 | if (cat == UCDN_GENERAL_CATEGORY_LL || cat == UCDN_GENERAL_CATEGORY_LT) |
1992 | 0 | { |
1993 | 0 | int glyph; |
1994 | 0 | const char *name; |
1995 | 0 | char buf[20]; |
1996 | |
|
1997 | 0 | name = fz_glyph_name_from_unicode_sc(unicode); |
1998 | 0 | if (name) |
1999 | 0 | { |
2000 | 0 | fz_ft_lock(ctx); |
2001 | 0 | glyph = FT_Get_Name_Index(font->ft_face, (char*)name); |
2002 | 0 | fz_ft_unlock(ctx); |
2003 | 0 | if (glyph > 0) |
2004 | 0 | return glyph; |
2005 | 0 | } |
2006 | | |
2007 | 0 | sprintf(buf, "uni%04X.sc", unicode); |
2008 | 0 | fz_ft_lock(ctx); |
2009 | 0 | glyph = FT_Get_Name_Index(font->ft_face, buf); |
2010 | 0 | fz_ft_unlock(ctx); |
2011 | 0 | if (glyph > 0) |
2012 | 0 | return glyph; |
2013 | 0 | } |
2014 | 0 | } |
2015 | 0 | return fz_encode_character(ctx, font, unicode); |
2016 | 0 | } |
2017 | | |
2018 | | int |
2019 | | fz_encode_character_by_glyph_name(fz_context *ctx, fz_font *font, const char *glyphname) |
2020 | 0 | { |
2021 | 0 | int glyph = 0; |
2022 | 0 | if (font->ft_face) |
2023 | 0 | { |
2024 | 0 | fz_ft_lock(ctx); |
2025 | 0 | glyph = ft_name_index(font->ft_face, glyphname); |
2026 | 0 | if (glyph == 0) |
2027 | 0 | glyph = ft_char_index(font->ft_face, fz_unicode_from_glyph_name(glyphname)); |
2028 | 0 | fz_ft_unlock(ctx); |
2029 | 0 | } |
2030 | | // TODO: type3 fonts (not needed for now) |
2031 | 0 | return glyph; |
2032 | 0 | } |
2033 | | |
2034 | | /* FIXME: This should take language too eventually, to allow for fonts where we can select different |
2035 | | * languages using opentype features. */ |
2036 | | int |
2037 | | fz_encode_character_with_fallback(fz_context *ctx, fz_font *user_font, int unicode, int script, int language, fz_font **out_font) |
2038 | 365k | { |
2039 | 365k | fz_font *font; |
2040 | 365k | int is_serif = user_font->flags.is_serif; |
2041 | 365k | int is_italic = user_font->flags.is_italic | user_font->flags.fake_italic; |
2042 | 365k | int is_bold = user_font->flags.is_bold | user_font->flags.fake_bold; |
2043 | 365k | int gid; |
2044 | | |
2045 | 365k | gid = fz_encode_character(ctx, user_font, unicode); |
2046 | 365k | if (gid > 0) |
2047 | 77.5k | return *out_font = user_font, gid; |
2048 | | |
2049 | 288k | if (script == 0) |
2050 | 28.5k | script = ucdn_get_script(unicode); |
2051 | | |
2052 | | /* Fix for ideographic/halfwidth/fullwidth punctuation forms. */ |
2053 | 288k | if ((unicode >= 0x3000 && unicode <= 0x303F) || (unicode >= 0xFF00 && unicode <= 0xFFEF)) |
2054 | 6.25k | { |
2055 | 6.25k | if (script != UCDN_SCRIPT_HANGUL && |
2056 | 6.25k | script != UCDN_SCRIPT_HIRAGANA && |
2057 | 6.25k | script != UCDN_SCRIPT_KATAKANA && |
2058 | 6.25k | script != UCDN_SCRIPT_BOPOMOFO) |
2059 | 4.55k | script = UCDN_SCRIPT_HAN; |
2060 | 6.25k | } |
2061 | | |
2062 | 288k | font = fz_load_fallback_font(ctx, script, language, is_serif, is_bold, is_italic); |
2063 | 288k | if (font) |
2064 | 288k | { |
2065 | 288k | gid = fz_encode_character(ctx, font, unicode); |
2066 | 288k | if (gid > 0) |
2067 | 229k | return *out_font = font, gid; |
2068 | 288k | } |
2069 | | |
2070 | 58.3k | #ifndef TOFU_CJK_LANG |
2071 | 58.3k | if (script == UCDN_SCRIPT_HAN) |
2072 | 34.9k | { |
2073 | 34.9k | font = fz_load_fallback_font(ctx, script, FZ_LANG_zh_Hant, is_serif, is_bold, is_italic); |
2074 | 34.9k | if (font) |
2075 | 34.9k | { |
2076 | 34.9k | gid = fz_encode_character(ctx, font, unicode); |
2077 | 34.9k | if (gid > 0) |
2078 | 0 | return *out_font = font, gid; |
2079 | 34.9k | } |
2080 | 34.9k | font = fz_load_fallback_font(ctx, script, FZ_LANG_ja, is_serif, is_bold, is_italic); |
2081 | 34.9k | if (font) |
2082 | 34.9k | { |
2083 | 34.9k | gid = fz_encode_character(ctx, font, unicode); |
2084 | 34.9k | if (gid > 0) |
2085 | 0 | return *out_font = font, gid; |
2086 | 34.9k | } |
2087 | 34.9k | font = fz_load_fallback_font(ctx, script, FZ_LANG_ko, is_serif, is_bold, is_italic); |
2088 | 34.9k | if (font) |
2089 | 34.9k | { |
2090 | 34.9k | gid = fz_encode_character(ctx, font, unicode); |
2091 | 34.9k | if (gid > 0) |
2092 | 0 | return *out_font = font, gid; |
2093 | 34.9k | } |
2094 | 34.9k | font = fz_load_fallback_font(ctx, script, FZ_LANG_zh_Hans, is_serif, is_bold, is_italic); |
2095 | 34.9k | if (font) |
2096 | 34.9k | { |
2097 | 34.9k | gid = fz_encode_character(ctx, font, unicode); |
2098 | 34.9k | if (gid > 0) |
2099 | 0 | return *out_font = font, gid; |
2100 | 34.9k | } |
2101 | 34.9k | } |
2102 | 58.3k | #endif |
2103 | | |
2104 | 58.3k | font = fz_load_fallback_math_font(ctx); |
2105 | 58.3k | if (font) |
2106 | 58.3k | { |
2107 | 58.3k | gid = fz_encode_character(ctx, font, unicode); |
2108 | 58.3k | if (gid > 0) |
2109 | 4.33k | return *out_font = font, gid; |
2110 | 58.3k | } |
2111 | | |
2112 | 53.9k | font = fz_load_fallback_music_font(ctx); |
2113 | 53.9k | if (font) |
2114 | 53.9k | { |
2115 | 53.9k | gid = fz_encode_character(ctx, font, unicode); |
2116 | 53.9k | if (gid > 0) |
2117 | 0 | return *out_font = font, gid; |
2118 | 53.9k | } |
2119 | | |
2120 | 53.9k | font = fz_load_fallback_symbol1_font(ctx); |
2121 | 53.9k | if (font) |
2122 | 53.9k | { |
2123 | 53.9k | gid = fz_encode_character(ctx, font, unicode); |
2124 | 53.9k | if (gid > 0) |
2125 | 596 | return *out_font = font, gid; |
2126 | 53.9k | } |
2127 | | |
2128 | 53.3k | font = fz_load_fallback_symbol2_font(ctx); |
2129 | 53.3k | if (font) |
2130 | 53.3k | { |
2131 | 53.3k | gid = fz_encode_character(ctx, font, unicode); |
2132 | 53.3k | if (gid > 0) |
2133 | 9.86k | return *out_font = font, gid; |
2134 | 53.3k | } |
2135 | | |
2136 | 43.5k | font = fz_load_fallback_emoji_font(ctx); |
2137 | 43.5k | if (font) |
2138 | 43.5k | { |
2139 | 43.5k | gid = fz_encode_character(ctx, font, unicode); |
2140 | 43.5k | if (gid > 0) |
2141 | 3 | return *out_font = font, gid; |
2142 | 43.5k | } |
2143 | | |
2144 | 43.5k | font = fz_load_fallback_boxes_font(ctx); |
2145 | 43.5k | if (font) |
2146 | 43.5k | { |
2147 | 43.5k | gid = fz_encode_character(ctx, font, unicode); |
2148 | 43.5k | if (gid > 0) |
2149 | 0 | return *out_font = font, gid; |
2150 | 43.5k | } |
2151 | | |
2152 | 43.5k | font = fz_new_base14_font(ctx, "Symbol"); |
2153 | 43.5k | if (font) |
2154 | 43.5k | { |
2155 | 43.5k | fz_drop_font(ctx, font); /* it's cached in the font context, return a borrowed pointer */ |
2156 | 43.5k | gid = fz_encode_character(ctx, font, unicode); |
2157 | 43.5k | if (gid > 0) |
2158 | 9 | return *out_font = font, gid; |
2159 | 43.5k | } |
2160 | | |
2161 | 43.5k | return *out_font = user_font, 0; |
2162 | 43.5k | } |
2163 | | |
2164 | | int fz_font_is_bold(fz_context *ctx, fz_font *font) |
2165 | 0 | { |
2166 | 0 | return font ? font->flags.is_bold : 0; |
2167 | 0 | } |
2168 | | |
2169 | | int fz_font_is_italic(fz_context *ctx, fz_font *font) |
2170 | 0 | { |
2171 | 0 | return font ? font->flags.is_italic : 0; |
2172 | 0 | } |
2173 | | |
2174 | | int fz_font_is_serif(fz_context *ctx, fz_font *font) |
2175 | 0 | { |
2176 | 0 | return font ? font->flags.is_serif : 0; |
2177 | 0 | } |
2178 | | |
2179 | | int fz_font_is_monospaced(fz_context *ctx, fz_font *font) |
2180 | 0 | { |
2181 | 0 | return font ? font->flags.is_mono : 0; |
2182 | 0 | } |
2183 | | |
2184 | | const char *fz_font_name(fz_context *ctx, fz_font *font) |
2185 | 0 | { |
2186 | 0 | return font ? font->name : ""; |
2187 | 0 | } |
2188 | | |
2189 | | fz_buffer **fz_font_t3_procs(fz_context *ctx, fz_font *font) |
2190 | 140k | { |
2191 | 140k | return font ? font->t3procs : NULL; |
2192 | 140k | } |
2193 | | |
2194 | | fz_rect fz_font_bbox(fz_context *ctx, fz_font *font) |
2195 | 0 | { |
2196 | 0 | return font->bbox; |
2197 | 0 | } |
2198 | | |
2199 | | void *fz_font_ft_face(fz_context *ctx, fz_font *font) |
2200 | 6.13M | { |
2201 | 6.13M | return font ? font->ft_face : NULL; |
2202 | 6.13M | } |
2203 | | |
2204 | | fz_font_flags_t *fz_font_flags(fz_font *font) |
2205 | 51.7k | { |
2206 | 51.7k | return font ? &font->flags : NULL; |
2207 | 51.7k | } |
2208 | | |
2209 | | fz_shaper_data_t *fz_font_shaper_data(fz_context *ctx, fz_font *font) |
2210 | 205k | { |
2211 | 205k | return font ? &font->shaper_data : NULL; |
2212 | 205k | } |
2213 | | |
2214 | | void fz_font_digest(fz_context *ctx, fz_font *font, unsigned char digest[16]) |
2215 | 7.41k | { |
2216 | 7.41k | if (!font->buffer) |
2217 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "no font file for digest"); |
2218 | 7.41k | if (!font->has_digest) |
2219 | 4.71k | { |
2220 | 4.71k | fz_md5_buffer(ctx, font->buffer, font->digest); |
2221 | 4.71k | font->has_digest = 1; |
2222 | 4.71k | } |
2223 | 7.41k | memcpy(digest, font->digest, 16); |
2224 | 7.41k | } |
2225 | | |
2226 | 3.90k | #define CHR(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | d) |
2227 | | |
2228 | | typedef struct |
2229 | | { |
2230 | | uint32_t offset; |
2231 | | uint32_t length; |
2232 | | } ttc_block_details_t; |
2233 | | |
2234 | | /* The operation of the following is largely based on the operation of |
2235 | | * https://github.com/fontist/extract_ttc/blob/main/ext/stripttc/stripttc.c |
2236 | | * released under a BSD 3-clause license. |
2237 | | */ |
2238 | | fz_buffer * |
2239 | | fz_extract_ttf_from_ttc(fz_context *ctx, fz_font *font) |
2240 | 244 | { |
2241 | 244 | fz_stream *stream; |
2242 | 244 | uint32_t tmp; |
2243 | 244 | int i, count; |
2244 | 244 | fz_buffer *buf = NULL; |
2245 | 244 | fz_output *out = NULL; |
2246 | 244 | ttc_block_details_t *bd = NULL; |
2247 | 244 | uint32_t start_pos; |
2248 | 244 | uint32_t csumpos = 0; |
2249 | | |
2250 | 244 | if (!font || !font->buffer) |
2251 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "missing input"); |
2252 | | |
2253 | 244 | stream = fz_open_buffer(ctx, font->buffer); |
2254 | | |
2255 | 244 | fz_var(buf); |
2256 | 244 | fz_var(out); |
2257 | 244 | fz_var(bd); |
2258 | | |
2259 | 488 | fz_try(ctx) |
2260 | 488 | { |
2261 | | /* Signature */ |
2262 | 244 | if (fz_read_uint32(ctx, stream) != CHR('t','t','c','f')) |
2263 | 0 | fz_throw(ctx, FZ_ERROR_FORMAT, "Not a ttc"); |
2264 | | |
2265 | | /* Version */ |
2266 | 244 | tmp = fz_read_uint32(ctx, stream); |
2267 | 244 | if (tmp != 0x10000 && tmp != 0x20000) |
2268 | 0 | fz_throw(ctx, FZ_ERROR_FORMAT, "Unsupported TTC version"); |
2269 | | |
2270 | | /* How many subfonts are there? */ |
2271 | 244 | tmp = fz_read_uint32(ctx, stream); |
2272 | 244 | if ((uint32_t)font->subfont >= tmp || font->subfont < 0) |
2273 | 0 | fz_throw(ctx, FZ_ERROR_FORMAT, "Bad subfont in TTC"); |
2274 | | |
2275 | | /* Read through the index table until we get the one for our subfont. */ |
2276 | 1.19k | for (i = 0; i <= font->subfont; i++) |
2277 | 952 | tmp = fz_read_uint32(ctx, stream); |
2278 | | |
2279 | 244 | fz_seek(ctx, stream, tmp, SEEK_SET); |
2280 | 244 | buf = fz_new_buffer(ctx, 1); |
2281 | 244 | out = fz_new_output_with_buffer(ctx, buf); |
2282 | | |
2283 | 244 | fz_write_uint32_be(ctx, out, fz_read_uint32(ctx, stream)); /* sfnt version */ |
2284 | 244 | fz_write_uint16_be(ctx, out, count = fz_read_uint16(ctx, stream)); /* table count */ |
2285 | 244 | fz_write_uint16_be(ctx, out, fz_read_uint16(ctx, stream)); /* bsearch header */ |
2286 | 244 | fz_write_uint16_be(ctx, out, fz_read_uint16(ctx, stream)); |
2287 | 244 | fz_write_uint16_be(ctx, out, fz_read_uint16(ctx, stream)); |
2288 | | |
2289 | | /* We are currently here... */ |
2290 | 244 | start_pos = 4+2+2+2+2; |
2291 | | /* And after we've written the header, we will be here. */ |
2292 | 244 | start_pos += count*4*4; |
2293 | 244 | bd = fz_malloc_array(ctx, count, ttc_block_details_t); |
2294 | 3.90k | for (i = 0; i < count; i++) |
2295 | 3.66k | { |
2296 | 3.66k | uint32_t tag; |
2297 | | |
2298 | 3.66k | fz_write_uint32_be(ctx, out, tag = fz_read_uint32(ctx, stream)); |
2299 | 3.66k | fz_write_uint32_be(ctx, out, fz_read_uint32(ctx, stream)); /* checksum */ |
2300 | 3.66k | bd[i].offset = fz_read_uint32(ctx, stream); |
2301 | 3.66k | fz_write_uint32_be(ctx, out, start_pos); |
2302 | 3.66k | if (tag == CHR('h','e','a','d')) |
2303 | 244 | csumpos = start_pos + 8; |
2304 | 3.66k | fz_write_uint32_be(ctx, out, bd[i].length = fz_read_uint32(ctx, stream)); |
2305 | 3.66k | start_pos += (bd[i].length + 3) & ~3; |
2306 | 3.66k | } |
2307 | | |
2308 | 3.90k | for (i = 0; i < count; i++) |
2309 | 3.66k | { |
2310 | 3.66k | uint32_t j; |
2311 | | |
2312 | 3.66k | fz_seek(ctx, stream, bd[i].offset, SEEK_SET); |
2313 | 5.76G | for (j = 0; j < bd[i].length; j++) |
2314 | 5.76G | fz_write_byte(ctx, out, fz_read_byte(ctx, stream)); |
2315 | 3.66k | if (bd[i].length & 1) |
2316 | 488 | { |
2317 | 488 | fz_write_byte(ctx, out, 0); |
2318 | 488 | bd[i].length++; |
2319 | 488 | } |
2320 | 3.66k | if (bd[i].length & 2) |
2321 | 1.20k | fz_write_uint16_be(ctx, out, 0); |
2322 | 3.66k | } |
2323 | | |
2324 | 244 | fz_close_output(ctx, out); |
2325 | 244 | } |
2326 | 488 | fz_always(ctx) |
2327 | 244 | { |
2328 | 244 | fz_free(ctx, bd); |
2329 | 244 | fz_drop_output(ctx, out); |
2330 | 244 | fz_drop_stream(ctx, stream); |
2331 | 244 | } |
2332 | 244 | fz_catch(ctx) |
2333 | 0 | { |
2334 | 0 | fz_drop_buffer(ctx, buf); |
2335 | 0 | fz_rethrow(ctx); |
2336 | 0 | } |
2337 | | |
2338 | | /* Now fixup the checksum */ |
2339 | 244 | if (csumpos) |
2340 | 244 | { |
2341 | 244 | unsigned char *data; |
2342 | 244 | uint32_t sum = 0; |
2343 | 244 | uint32_t j; |
2344 | 244 | size_t len = fz_buffer_storage(ctx, buf, &data); |
2345 | | |
2346 | | /* First off, blat the old checksum */ |
2347 | 244 | memset(data+csumpos, 0, 4); |
2348 | | |
2349 | | /* Calculate the new sum. */ |
2350 | 1.44G | for (j = 0; j < len; j += 4) |
2351 | 1.44G | { |
2352 | 1.44G | uint32_t v = (data[j]<<24) | (data[j+1]<<16) | (data[j+2]<<8) | (data[j+3]); |
2353 | 1.44G | sum += v; |
2354 | 1.44G | } |
2355 | 244 | sum = 0xb1b0afba-sum; |
2356 | | |
2357 | | /* Insert it. */ |
2358 | 244 | data[csumpos] = sum>>24; |
2359 | 244 | data[csumpos+1] = sum>>16; |
2360 | 244 | data[csumpos+2] = sum>>8; |
2361 | 244 | data[csumpos+3] = sum; |
2362 | 244 | } |
2363 | | |
2364 | 244 | return buf; |
2365 | 244 | } |
2366 | | |
2367 | | void fz_enumerate_font_cmap(fz_context *ctx, fz_font *font, fz_cmap_callback *cb, void *opaque) |
2368 | 0 | { |
2369 | 0 | unsigned long ucs; |
2370 | 0 | unsigned int gid; |
2371 | |
|
2372 | 0 | if (font == NULL || font->ft_face == NULL) |
2373 | 0 | return; |
2374 | | |
2375 | 0 | fz_ft_lock(ctx); |
2376 | 0 | for (ucs = FT_Get_First_Char(font->ft_face, &gid); gid > 0; ucs = FT_Get_Next_Char(font->ft_face, ucs, &gid)) |
2377 | 0 | { |
2378 | 0 | fz_ft_unlock(ctx); |
2379 | 0 | cb(ctx, opaque, ucs, gid); |
2380 | 0 | fz_ft_lock(ctx); |
2381 | 0 | } |
2382 | 0 | fz_ft_unlock(ctx); |
2383 | 0 | } |