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