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