Coverage Report

Created: 2026-06-30 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}