Coverage Report

Created: 2025-09-04 06:50

/src/mupdf/source/pdf/pdf-font-add.c
Line
Count
Source (jump to first uncovered line)
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/pdf.h"
25
26
#include <ft2build.h>
27
#include FT_FREETYPE_H
28
#ifdef FT_FONT_FORMATS_H
29
#include FT_FONT_FORMATS_H
30
#else
31
#include FT_XFREE86_H
32
#endif
33
#include FT_TRUETYPE_TABLES_H
34
35
#ifndef FT_SFNT_HEAD
36
0
#define FT_SFNT_HEAD ft_sfnt_head
37
#endif
38
39
static int ft_font_file_kind(fz_context *ctx, FT_Face face)
40
0
{
41
0
  const char *kind;
42
0
  fz_ft_lock(ctx);
43
0
#ifdef FT_FONT_FORMATS_H
44
0
  kind = FT_Get_Font_Format(face);
45
#else
46
  kind = FT_Get_X11_Font_Format(face);
47
#endif
48
0
  fz_ft_unlock(ctx);
49
0
  if (!strcmp(kind, "TrueType")) return 2;
50
0
  if (!strcmp(kind, "Type 1")) return 1;
51
0
  if (!strcmp(kind, "CFF")) return 3;
52
0
  if (!strcmp(kind, "CID Type 1")) return 1;
53
0
  return 0;
54
0
}
55
56
static int is_ttc(fz_font *font)
57
0
{
58
0
  if (!font || !font->buffer || font->buffer->len < 4)
59
0
    return 0;
60
0
  return !memcmp(font->buffer->data, "ttcf", 4);
61
0
}
62
63
static int is_truetype(fz_context *ctx, FT_Face face)
64
0
{
65
0
  return ft_font_file_kind(ctx, face) == 2;
66
0
}
67
68
static int is_postscript(fz_context *ctx, FT_Face face)
69
0
{
70
0
  int kind = ft_font_file_kind(ctx, face);
71
0
  return (kind == 1 || kind == 3);
72
0
}
73
74
static int is_builtin_font(fz_context *ctx, fz_font *font)
75
0
{
76
0
  int size;
77
0
  unsigned char *data;
78
0
  if (!font->buffer)
79
0
    return 0;
80
0
  fz_buffer_storage(ctx, font->buffer, &data);
81
0
  return fz_lookup_base14_font(ctx, pdf_clean_font_name(font->name), &size) == data;
82
0
}
83
84
static pdf_obj*
85
pdf_add_font_file(fz_context *ctx, pdf_document *doc, fz_font *font)
86
0
{
87
0
  fz_buffer *buf = font->buffer;
88
0
  pdf_obj *obj = NULL;
89
0
  pdf_obj *ref = NULL;
90
0
  int drop_buf = 0;
91
92
0
  fz_var(obj);
93
0
  fz_var(ref);
94
95
  /* Check for substitute fonts */
96
0
  if (font->flags.ft_substitute)
97
0
    return NULL;
98
99
0
  if (is_ttc(font))
100
0
  {
101
0
    buf = NULL;
102
0
    drop_buf = 1;
103
0
    buf = fz_extract_ttf_from_ttc(ctx, font);
104
0
  }
105
106
0
  fz_try(ctx)
107
0
  {
108
0
    size_t len = fz_buffer_storage(ctx, buf, NULL);
109
0
    int is_opentype;
110
0
    obj = pdf_new_dict(ctx, doc, 3);
111
0
    pdf_dict_put_int(ctx, obj, PDF_NAME(Length1), (int)len);
112
0
    switch (ft_font_file_kind(ctx, font->ft_face))
113
0
    {
114
0
    case 1:
115
      /* TODO: these may not be the correct values, but I doubt it matters */
116
0
      pdf_dict_put_int(ctx, obj, PDF_NAME(Length2), len);
117
0
      pdf_dict_put_int(ctx, obj, PDF_NAME(Length3), 0);
118
0
      break;
119
0
    case 2:
120
0
      break;
121
0
    case 3:
122
0
      fz_ft_lock(ctx);
123
0
      is_opentype = !!FT_Get_Sfnt_Table(font->ft_face, FT_SFNT_HEAD);
124
0
      fz_ft_unlock(ctx);
125
0
      if (is_opentype)
126
0
        pdf_dict_put(ctx, obj, PDF_NAME(Subtype), PDF_NAME(OpenType));
127
0
      else
128
0
        pdf_dict_put(ctx, obj, PDF_NAME(Subtype), PDF_NAME(CIDFontType0C));
129
0
      break;
130
0
    }
131
0
    ref = pdf_add_object(ctx, doc, obj);
132
0
    pdf_update_stream(ctx, doc, ref, buf, 0);
133
0
  }
134
0
  fz_always(ctx)
135
0
  {
136
0
    pdf_drop_obj(ctx, obj);
137
0
    if (drop_buf)
138
0
      fz_drop_buffer(ctx, buf);
139
0
  }
140
0
  fz_catch(ctx)
141
0
  {
142
0
    pdf_drop_obj(ctx, ref);
143
0
    fz_rethrow(ctx);
144
0
  }
145
0
  return ref;
146
0
}
147
148
static void
149
pdf_add_font_descriptor(fz_context *ctx, pdf_document *doc, pdf_obj *fobj, fz_font *font)
150
0
{
151
0
  FT_Face face = font->ft_face;
152
0
  pdf_obj *fdobj = NULL;
153
0
  pdf_obj *fileref;
154
0
  fz_rect bbox;
155
156
0
  fdobj = pdf_new_dict(ctx, doc, 10);
157
0
  fz_try(ctx)
158
0
  {
159
0
    pdf_dict_put(ctx, fdobj, PDF_NAME(Type), PDF_NAME(FontDescriptor));
160
0
    pdf_dict_put_name(ctx, fdobj, PDF_NAME(FontName), font->name);
161
162
0
    bbox.x0 = font->bbox.x0 * 1000;
163
0
    bbox.y0 = font->bbox.y0 * 1000;
164
0
    bbox.x1 = font->bbox.x1 * 1000;
165
0
    bbox.y1 = font->bbox.y1 * 1000;
166
0
    pdf_dict_put_rect(ctx, fdobj, PDF_NAME(FontBBox), bbox);
167
168
0
    pdf_dict_put_int(ctx, fdobj, PDF_NAME(ItalicAngle), 0);
169
0
    pdf_dict_put_int(ctx, fdobj, PDF_NAME(Ascent), face->ascender * 1000.0f / face->units_per_EM);
170
0
    pdf_dict_put_int(ctx, fdobj, PDF_NAME(Descent), face->descender * 1000.0f / face->units_per_EM);
171
0
    pdf_dict_put_int(ctx, fdobj, PDF_NAME(StemV), 80);
172
0
    pdf_dict_put_int(ctx, fdobj, PDF_NAME(Flags), PDF_FD_NONSYMBOLIC);
173
174
0
    fileref = pdf_add_font_file(ctx, doc, font);
175
0
    if (fileref)
176
0
    {
177
0
      switch (ft_font_file_kind(ctx, face))
178
0
      {
179
0
      default:
180
0
      case 1: pdf_dict_put_drop(ctx, fdobj, PDF_NAME(FontFile), fileref); break;
181
0
      case 2: pdf_dict_put_drop(ctx, fdobj, PDF_NAME(FontFile2), fileref); break;
182
0
      case 3: pdf_dict_put_drop(ctx, fdobj, PDF_NAME(FontFile3), fileref); break;
183
0
      }
184
0
    }
185
186
0
    pdf_dict_put_drop(ctx, fobj, PDF_NAME(FontDescriptor), pdf_add_object(ctx, doc, fdobj));
187
0
  }
188
0
  fz_always(ctx)
189
0
    pdf_drop_obj(ctx, fdobj);
190
0
  fz_catch(ctx)
191
0
    fz_rethrow(ctx);
192
0
}
193
194
static void
195
pdf_add_simple_font_widths(fz_context *ctx, pdf_document *doc, pdf_obj *fobj, fz_font *font, const char * const encoding[])
196
0
{
197
0
  int width_table[256];
198
0
  pdf_obj *widths;
199
0
  int i, first, last;
200
201
0
  first = 0;
202
0
  last = 0;
203
204
0
  for (i = 0; i < 256; ++i)
205
0
  {
206
0
    int glyph = 0;
207
0
    if (encoding[i])
208
0
    {
209
0
      glyph = fz_encode_character_by_glyph_name(ctx, font, encoding[i]);
210
0
    }
211
0
    if (glyph > 0)
212
0
    {
213
0
      if (!first)
214
0
        first = i;
215
0
      last = i;
216
0
      width_table[i] = fz_advance_glyph(ctx, font, glyph, 0) * 1000;
217
0
    }
218
0
    else
219
0
      width_table[i] = 0;
220
0
  }
221
222
0
  widths = pdf_new_array(ctx, doc, last - first + 1);
223
0
  pdf_dict_put_drop(ctx, fobj, PDF_NAME(Widths), widths);
224
0
  for (i = first; i <= last; ++i)
225
0
    pdf_array_push_int(ctx, widths, width_table[i]);
226
0
  pdf_dict_put_int(ctx, fobj, PDF_NAME(FirstChar), first);
227
0
  pdf_dict_put_int(ctx, fobj, PDF_NAME(LastChar), last);
228
0
}
229
230
static void
231
pdf_add_cid_system_info(fz_context *ctx, pdf_document *doc, pdf_obj *fobj, const char *reg, const char *ord, int supp)
232
0
{
233
0
  pdf_obj *csi = pdf_dict_put_dict(ctx, fobj, PDF_NAME(CIDSystemInfo), 3);
234
0
  pdf_dict_put_string(ctx, csi, PDF_NAME(Registry), reg, strlen(reg));
235
0
  pdf_dict_put_string(ctx, csi, PDF_NAME(Ordering), ord, strlen(ord));
236
0
  pdf_dict_put_int(ctx, csi, PDF_NAME(Supplement), supp);
237
0
}
238
239
/* Different states of starting, same width as last, or consecutive glyph */
240
enum { FW_START = 0, FW_SAME, FW_DIFFER };
241
242
/* ToDo: Ignore the default sized characters */
243
static void
244
pdf_add_cid_font_widths(fz_context *ctx, pdf_document *doc, pdf_obj *fobj, fz_font *font)
245
0
{
246
0
  FT_Face face = font->ft_face;
247
0
  pdf_obj *run_obj = NULL;
248
0
  pdf_obj *fw;
249
0
  int curr_code;
250
0
  int curr_size;
251
0
  int first_code;
252
0
  int state = FW_START;
253
254
0
  fz_var(run_obj);
255
256
0
  fw = pdf_add_new_array(ctx, doc, 10);
257
0
  fz_try(ctx)
258
0
  {
259
0
    curr_code = 0;
260
0
    curr_size = fz_advance_glyph(ctx, font, 0, 0) * 1000;
261
0
    first_code = 0;
262
263
0
    for (curr_code = 1; curr_code < face->num_glyphs; curr_code++)
264
0
    {
265
0
      int prev_size = curr_size;
266
267
0
      curr_size = fz_advance_glyph(ctx, font, curr_code, 0) * 1000;
268
269
      /* So each time around the loop when we reach here, we have sizes
270
       * for curr_code-1 (prev_size) and curr_code (curr_size), neither
271
       * of which have been published yet. By the time we reach the end
272
       * of the loop we must have disposed of prev_size. */
273
0
      switch (state)
274
0
      {
275
0
      case FW_SAME:
276
        /* Until now, we've been in a run of identical values, extending
277
         * from first_code to curr_code-1. If the current and prev sizes
278
         * match, then this now extends from first_code to curr_code and
279
         * we don't need to do anything. If not, we need to flush and
280
         * restart. */
281
0
        if (curr_size != prev_size)
282
0
        {
283
          /* Add three entries. First cid, last cid and width */
284
0
          pdf_array_push_int(ctx, fw, first_code);
285
0
          pdf_array_push_int(ctx, fw, curr_code-1);
286
0
          pdf_array_push_int(ctx, fw, prev_size);
287
          /* And the new first code is our current code. */
288
0
          first_code = curr_code;
289
0
          state = FW_START;
290
0
        }
291
0
        break;
292
0
      case FW_DIFFER:
293
        /* Until now, we've been in a run of differing values, extending
294
         * from first_code to curr_code-1 (though prev_size, the size for
295
         * curr_code-1 has not yet been pushed). */
296
0
        if (curr_size == prev_size)
297
0
        {
298
          /* Same width, so flush the run of differences. */
299
0
          pdf_array_push_int(ctx, fw, first_code);
300
0
          pdf_array_push(ctx, fw, run_obj);
301
0
          pdf_drop_obj(ctx, run_obj);
302
0
          run_obj = NULL;
303
          /* Start a new 'same' entry starting with curr_code-1.
304
           * i.e. the prev size is not put in the run. */
305
0
          state = FW_SAME;
306
0
          first_code = curr_code-1;
307
0
        }
308
0
        else
309
0
        {
310
          /* Continue our differing run by adding prev size to run_obj. */
311
0
          pdf_array_push_int(ctx, run_obj, prev_size);
312
0
        }
313
0
        break;
314
0
      case FW_START:
315
        /* Starting fresh. Determine our state. */
316
0
        if (curr_size == prev_size)
317
0
        {
318
0
          state = FW_SAME;
319
0
        }
320
0
        else
321
0
        {
322
0
          run_obj = pdf_new_array(ctx, doc, 10);
323
0
          pdf_array_push_int(ctx, run_obj, prev_size);
324
0
          state = FW_DIFFER;
325
0
        }
326
0
        break;
327
0
      }
328
0
    }
329
330
    /* So curr_code-1 is the last valid char, and curr_size was its size. */
331
0
    switch (state)
332
0
    {
333
0
    case FW_SAME:
334
      /* We have an unflushed run of same entries. */
335
0
      if (first_code != curr_code-1)
336
0
      {
337
0
        pdf_array_push_int(ctx, fw, first_code);
338
0
        pdf_array_push_int(ctx, fw, curr_code-1);
339
0
        pdf_array_push_int(ctx, fw, curr_size);
340
0
      }
341
0
      break;
342
0
    case FW_DIFFER:
343
      /* We have not yet pushed curr_size to the object. */
344
0
      pdf_array_push_int(ctx, fw, first_code);
345
0
      pdf_array_push_int(ctx, run_obj, curr_size);
346
0
      pdf_array_push(ctx, fw, run_obj);
347
0
      pdf_drop_obj(ctx, run_obj);
348
0
      run_obj = NULL;
349
0
      break;
350
0
    case FW_START:
351
      /* Lone wolf! */
352
0
      pdf_array_push_int(ctx, fw, curr_code-1);
353
0
      pdf_array_push_int(ctx, fw, curr_code-1);
354
0
      pdf_array_push_int(ctx, fw, curr_size);
355
0
      break;
356
0
    }
357
358
0
    if (font->width_table != NULL)
359
0
      pdf_dict_put_int(ctx, fobj, PDF_NAME(DW), font->width_default);
360
0
    if (pdf_array_len(ctx, fw) > 0)
361
0
      pdf_dict_put(ctx, fobj, PDF_NAME(W), fw);
362
0
  }
363
0
  fz_always(ctx)
364
0
  {
365
0
    pdf_drop_obj(ctx, fw);
366
0
    pdf_drop_obj(ctx, run_obj);
367
0
  }
368
0
  fz_catch(ctx)
369
0
    fz_rethrow(ctx);
370
0
}
371
372
/* Descendant font construction used for CID font creation from ttf or Adobe type1 */
373
static pdf_obj*
374
pdf_add_descendant_cid_font(fz_context *ctx, pdf_document *doc, fz_font *font)
375
0
{
376
0
  FT_Face face = font->ft_face;
377
0
  pdf_obj *fobj, *fref;
378
0
  const char *ps_name;
379
380
0
  fobj = pdf_new_dict(ctx, doc, 3);
381
0
  fz_try(ctx)
382
0
  {
383
0
    pdf_dict_put(ctx, fobj, PDF_NAME(Type), PDF_NAME(Font));
384
0
    if (is_truetype(ctx, face))
385
0
      pdf_dict_put(ctx, fobj, PDF_NAME(Subtype), PDF_NAME(CIDFontType2));
386
0
    else
387
0
      pdf_dict_put(ctx, fobj, PDF_NAME(Subtype), PDF_NAME(CIDFontType0));
388
389
0
    pdf_add_cid_system_info(ctx, doc, fobj, "Adobe", "Identity", 0);
390
391
0
    fz_ft_lock(ctx);
392
0
    ps_name = FT_Get_Postscript_Name(face);
393
0
    fz_ft_unlock(ctx);
394
0
    if (ps_name)
395
0
      pdf_dict_put_name(ctx, fobj, PDF_NAME(BaseFont), ps_name);
396
0
    else
397
0
      pdf_dict_put_name(ctx, fobj, PDF_NAME(BaseFont), font->name);
398
399
0
    pdf_add_font_descriptor(ctx, doc, fobj, font);
400
401
    /* We may have a cid font already with width info in source font and no cmap in the ft face */
402
0
    pdf_add_cid_font_widths(ctx, doc, fobj, font);
403
404
0
    fref = pdf_add_object(ctx, doc, fobj);
405
0
  }
406
0
  fz_always(ctx)
407
0
    pdf_drop_obj(ctx, fobj);
408
0
  fz_catch(ctx)
409
0
    fz_rethrow(ctx);
410
0
  return fref;
411
0
}
412
413
static int next_range(int *table, int size, int k)
414
0
{
415
0
  int n;
416
0
  for (n = 1; k + n < size; ++n)
417
0
  {
418
0
    if ((k & 0xFF00) != ((k+n) & 0xFF00)) /* high byte changes */
419
0
      break;
420
0
    if (table[k] + n != table[k+n])
421
0
      break;
422
0
  }
423
0
  return n;
424
0
}
425
426
/* Create the ToUnicode CMap. */
427
static void
428
pdf_add_to_unicode(fz_context *ctx, pdf_document *doc, pdf_obj *fobj, fz_font *font)
429
0
{
430
0
  FT_Face face = font->ft_face;
431
0
  fz_buffer *buf = NULL;
432
433
0
  int *table;
434
0
  int num_seq = 0;
435
0
  int num_chr = 0;
436
0
  int n, k;
437
438
  /* Populate reverse cmap table */
439
0
  {
440
0
    FT_ULong ucs;
441
0
    FT_UInt gid;
442
443
0
    table = fz_calloc(ctx, face->num_glyphs, sizeof *table);
444
0
    fz_ft_lock(ctx);
445
0
    ucs = FT_Get_First_Char(face, &gid);
446
0
    while (gid > 0)
447
0
    {
448
0
      if (gid < (FT_ULong)face->num_glyphs && face->num_glyphs > 0)
449
0
        table[gid] = ucs;
450
0
      ucs = FT_Get_Next_Char(face, ucs, &gid);
451
0
    }
452
0
    fz_ft_unlock(ctx);
453
0
  }
454
455
0
  for (k = 0; k < face->num_glyphs; k += n)
456
0
  {
457
0
    n = next_range(table, face->num_glyphs, k);
458
0
    if (n > 1)
459
0
      ++num_seq;
460
0
    else if (table[k] > 0)
461
0
      ++num_chr;
462
0
  }
463
464
  /* No mappings available... */
465
0
  if (num_seq + num_chr == 0)
466
0
  {
467
0
    fz_warn(ctx, "cannot create ToUnicode mapping for %s", font->name);
468
0
    fz_free(ctx, table);
469
0
    return;
470
0
  }
471
472
0
  fz_var(buf);
473
474
0
  fz_try(ctx)
475
0
  {
476
0
    buf = fz_new_buffer(ctx, 0);
477
478
    /* Header boiler plate */
479
0
    fz_append_string(ctx, buf, "/CIDInit /ProcSet findresource begin\n");
480
0
    fz_append_string(ctx, buf, "12 dict begin\n");
481
0
    fz_append_string(ctx, buf, "begincmap\n");
482
0
    fz_append_string(ctx, buf, "/CIDSystemInfo <</Registry(Adobe)/Ordering(UCS)/Supplement 0>> def\n");
483
0
    fz_append_string(ctx, buf, "/CMapName /Adobe-Identity-UCS def\n");
484
0
    fz_append_string(ctx, buf, "/CMapType 2 def\n");
485
0
    fz_append_string(ctx, buf, "1 begincodespacerange\n");
486
0
    fz_append_string(ctx, buf, "<0000> <FFFF>\n");
487
0
    fz_append_string(ctx, buf, "endcodespacerange\n");
488
489
    /* Note to have a valid CMap, the number of entries in table set can
490
     * not exceed 100, so we have to break into multiple tables. Also, note
491
     * that to reduce the file size we should be looking for sequential
492
     * ranges. Per Adobe technical note #5411, we can't have a range
493
     * cross a boundary where the high order byte changes */
494
495
    /* First the ranges */
496
0
    if (num_seq > 0)
497
0
    {
498
0
      int count = 0;
499
0
      if (num_seq > 100)
500
0
      {
501
0
        fz_append_string(ctx, buf, "100 beginbfrange\n");
502
0
        num_seq -= 100;
503
0
      }
504
0
      else
505
0
        fz_append_printf(ctx, buf, "%d beginbfrange\n", num_seq);
506
0
      for (k = 0; k < face->num_glyphs; k += n)
507
0
      {
508
0
        n = next_range(table, face->num_glyphs, k);
509
0
        if (n > 1)
510
0
        {
511
0
          if (count == 100)
512
0
          {
513
0
            fz_append_string(ctx, buf, "endbfrange\n");
514
0
            if (num_seq > 100)
515
0
            {
516
0
              fz_append_string(ctx, buf, "100 beginbfrange\n");
517
0
              num_seq -= 100;
518
0
            }
519
0
            else
520
0
              fz_append_printf(ctx, buf, "%d beginbfrange\n", num_seq);
521
0
            count = 0;
522
0
          }
523
0
          fz_append_printf(ctx, buf, "<%04x> <%04x> <%04x>\n", k, k+n-1, table[k]);
524
0
          ++count;
525
0
        }
526
0
      }
527
0
      fz_append_string(ctx, buf, "endbfrange\n");
528
0
    }
529
530
    /* Then the singles */
531
0
    if (num_chr > 0)
532
0
    {
533
0
      int count = 0;
534
0
      if (num_chr > 100)
535
0
      {
536
0
        fz_append_string(ctx, buf, "100 beginbfchar\n");
537
0
        num_chr -= 100;
538
0
      }
539
0
      else
540
0
        fz_append_printf(ctx, buf, "%d beginbfchar\n", num_chr);
541
0
      for (k = 0; k < face->num_glyphs; k += n)
542
0
      {
543
0
        n = next_range(table, face->num_glyphs, k);
544
0
        if (n == 1 && table[k] > 0)
545
0
        {
546
0
          if (count == 100)
547
0
          {
548
0
            fz_append_string(ctx, buf, "endbfchar\n");
549
0
            if (num_chr > 100)
550
0
            {
551
0
              fz_append_string(ctx, buf, "100 beginbfchar\n");
552
0
              num_chr -= 100;
553
0
            }
554
0
            else
555
0
              fz_append_printf(ctx, buf, "%d beginbfchar\n", num_chr);
556
0
            count = 0;
557
0
          }
558
0
          fz_append_printf(ctx, buf, "<%04x> <%04x>\n", k, table[k]);
559
0
          ++count;
560
0
        }
561
0
      }
562
0
      fz_append_string(ctx, buf, "endbfchar\n");
563
0
    }
564
565
    /* Trailer boiler plate */
566
0
    fz_append_string(ctx, buf, "endcmap\n");
567
0
    fz_append_string(ctx, buf, "CMapName currentdict /CMap defineresource pop\n");
568
0
    fz_append_string(ctx, buf, "end\nend\n");
569
570
0
    pdf_dict_put_drop(ctx, fobj, PDF_NAME(ToUnicode), pdf_add_stream(ctx, doc, buf, NULL, 0));
571
0
  }
572
0
  fz_always(ctx)
573
0
  {
574
0
    fz_free(ctx, table);
575
0
    fz_drop_buffer(ctx, buf);
576
0
  }
577
0
  fz_catch(ctx)
578
0
    fz_rethrow(ctx);
579
0
}
580
581
pdf_obj *
582
pdf_add_cid_font(fz_context *ctx, pdf_document *doc, fz_font *font)
583
0
{
584
0
  pdf_obj *fobj = NULL;
585
0
  pdf_obj *fref = NULL;
586
0
  pdf_obj *dfonts = NULL;
587
0
  pdf_font_resource_key key;
588
589
0
  fref = pdf_find_font_resource(ctx, doc, PDF_CID_FONT_RESOURCE, 0, font, &key);
590
0
  if (fref)
591
0
    return fref;
592
593
0
  fobj = pdf_add_new_dict(ctx, doc, 10);
594
0
  fz_try(ctx)
595
0
  {
596
0
    pdf_dict_put(ctx, fobj, PDF_NAME(Type), PDF_NAME(Font));
597
0
    pdf_dict_put(ctx, fobj, PDF_NAME(Subtype), PDF_NAME(Type0));
598
0
    pdf_dict_put_name(ctx, fobj, PDF_NAME(BaseFont), font->name);
599
0
    pdf_dict_put(ctx, fobj, PDF_NAME(Encoding), PDF_NAME(Identity_H));
600
0
    pdf_add_to_unicode(ctx, doc, fobj, font);
601
602
0
    dfonts = pdf_dict_put_array(ctx, fobj, PDF_NAME(DescendantFonts), 1);
603
0
    pdf_array_push_drop(ctx, dfonts, pdf_add_descendant_cid_font(ctx, doc, font));
604
605
0
    fref = pdf_insert_font_resource(ctx, doc, &key, fobj);
606
0
  }
607
0
  fz_always(ctx)
608
0
    pdf_drop_obj(ctx, fobj);
609
0
  fz_catch(ctx)
610
0
    fz_rethrow(ctx);
611
0
  return fref;
612
0
}
613
614
/* Create simple (8-bit encoding) fonts */
615
616
static void
617
pdf_add_simple_font_encoding_imp(fz_context *ctx, pdf_document *doc, pdf_obj *font, const char *glyph_names[])
618
0
{
619
0
  pdf_obj *enc, *diff;
620
0
  int i, last;
621
622
0
  enc = pdf_dict_put_dict(ctx, font, PDF_NAME(Encoding), 2);
623
0
  pdf_dict_put(ctx, enc, PDF_NAME(BaseEncoding), PDF_NAME(WinAnsiEncoding));
624
0
  diff = pdf_dict_put_array(ctx, enc, PDF_NAME(Differences), 129);
625
0
  last = 0;
626
0
  for (i = 128; i < 256; ++i)
627
0
  {
628
0
    const char *glyph = glyph_names[i];
629
0
    if (glyph)
630
0
    {
631
0
      if (last != i-1)
632
0
        pdf_array_push_int(ctx, diff, i);
633
0
      last = i;
634
0
      pdf_array_push_name(ctx, diff, glyph);
635
0
    }
636
0
  }
637
0
}
638
639
static void
640
pdf_add_simple_font_encoding(fz_context *ctx, pdf_document *doc, pdf_obj *fobj, int encoding)
641
0
{
642
0
  switch (encoding)
643
0
  {
644
0
  default:
645
0
  case PDF_SIMPLE_ENCODING_LATIN:
646
0
    pdf_dict_put(ctx, fobj, PDF_NAME(Encoding), PDF_NAME(WinAnsiEncoding));
647
0
    break;
648
0
  case PDF_SIMPLE_ENCODING_GREEK:
649
0
    pdf_add_simple_font_encoding_imp(ctx, doc, fobj, fz_glyph_name_from_iso8859_7);
650
0
    break;
651
0
  case PDF_SIMPLE_ENCODING_CYRILLIC:
652
0
    pdf_add_simple_font_encoding_imp(ctx, doc, fobj, fz_glyph_name_from_koi8u);
653
0
    break;
654
0
  }
655
0
}
656
657
pdf_obj *
658
pdf_add_simple_font(fz_context *ctx, pdf_document *doc, fz_font *font, int encoding)
659
0
{
660
0
  FT_Face face = font->ft_face;
661
0
  pdf_obj *fobj = NULL;
662
0
  pdf_obj *fref = NULL;
663
0
  const char **enc;
664
0
  pdf_font_resource_key key;
665
666
0
  fref = pdf_find_font_resource(ctx, doc, PDF_SIMPLE_FONT_RESOURCE, encoding, font, &key);
667
0
  if (fref)
668
0
    return fref;
669
670
0
  switch (encoding)
671
0
  {
672
0
  default:
673
0
  case PDF_SIMPLE_ENCODING_LATIN: enc = fz_glyph_name_from_windows_1252; break;
674
0
  case PDF_SIMPLE_ENCODING_GREEK: enc = fz_glyph_name_from_iso8859_7; break;
675
0
  case PDF_SIMPLE_ENCODING_CYRILLIC: enc = fz_glyph_name_from_koi8u; break;
676
0
  }
677
678
0
  fobj = pdf_add_new_dict(ctx, doc, 10);
679
0
  fz_try(ctx)
680
0
  {
681
0
    pdf_dict_put(ctx, fobj, PDF_NAME(Type), PDF_NAME(Font));
682
0
    if (is_truetype(ctx, face))
683
0
      pdf_dict_put(ctx, fobj, PDF_NAME(Subtype), PDF_NAME(TrueType));
684
0
    else
685
0
      pdf_dict_put(ctx, fobj, PDF_NAME(Subtype), PDF_NAME(Type1));
686
687
0
    if (!is_builtin_font(ctx, font))
688
0
    {
689
0
      const char *ps_name;
690
0
      fz_ft_lock(ctx);
691
0
      ps_name = FT_Get_Postscript_Name(face);
692
0
      fz_ft_unlock(ctx);
693
0
      if (!ps_name)
694
0
        ps_name = font->name;
695
0
      pdf_dict_put_name(ctx, fobj, PDF_NAME(BaseFont), ps_name);
696
0
      pdf_add_simple_font_encoding(ctx, doc, fobj, encoding);
697
0
      pdf_add_simple_font_widths(ctx, doc, fobj, font, enc);
698
0
      pdf_add_font_descriptor(ctx, doc, fobj, font);
699
0
    }
700
0
    else
701
0
    {
702
0
      pdf_dict_put_name(ctx, fobj, PDF_NAME(BaseFont), pdf_clean_font_name(font->name));
703
0
      pdf_add_simple_font_encoding(ctx, doc, fobj, encoding);
704
0
      if (encoding != PDF_SIMPLE_ENCODING_LATIN)
705
0
        pdf_add_simple_font_widths(ctx, doc, fobj, font, enc);
706
0
    }
707
708
0
    fref = pdf_insert_font_resource(ctx, doc, &key, fobj);
709
0
  }
710
0
  fz_always(ctx)
711
0
  {
712
0
    pdf_drop_obj(ctx, fobj);
713
0
  }
714
0
  fz_catch(ctx)
715
0
    fz_rethrow(ctx);
716
0
  return fref;
717
0
}
718
719
int
720
pdf_font_writing_supported(fz_context *ctx, fz_font *font)
721
0
{
722
0
  if (font->ft_face == NULL || font->buffer == NULL || font->buffer->len < 4 || !font->flags.embed || font->flags.never_embed)
723
0
    return 0;
724
0
  if (is_ttc(font))
725
0
    return 1;
726
0
  if (is_truetype(ctx, font->ft_face))
727
0
    return 1;
728
0
  if (is_postscript(ctx, font->ft_face))
729
0
    return 1;
730
0
  return 0;
731
0
}
732
733
pdf_obj *
734
pdf_add_cjk_font(fz_context *ctx, pdf_document *doc, fz_font *fzfont, int script, int wmode, int serif)
735
0
{
736
0
  pdf_obj *fref, *font, *subfont, *fontdesc;
737
0
  pdf_obj *dfonts;
738
0
  fz_rect bbox = { -200, -200, 1200, 1200 };
739
0
  pdf_font_resource_key key;
740
0
  int flags;
741
742
0
  const char *basefont, *encoding, *ordering;
743
0
  int supplement;
744
745
0
  switch (script)
746
0
  {
747
0
  default:
748
0
    script = FZ_ADOBE_CNS;
749
    /* fall through */
750
0
  case FZ_ADOBE_CNS: /* traditional chinese */
751
0
    basefont = serif ? "Ming" : "Fangti";
752
0
    encoding = wmode ? "UniCNS-UTF16-V" : "UniCNS-UTF16-H";
753
0
    ordering = "CNS1";
754
0
    supplement = 7;
755
0
    break;
756
0
  case FZ_ADOBE_GB: /* simplified chinese */
757
0
    basefont = serif ? "Song" : "Heiti";
758
0
    encoding = wmode ? "UniGB-UTF16-V" : "UniGB-UTF16-H";
759
0
    ordering = "GB1";
760
0
    supplement = 5;
761
0
    break;
762
0
  case FZ_ADOBE_JAPAN:
763
0
    basefont = serif ? "Mincho" : "Gothic";
764
0
    encoding = wmode ? "UniJIS-UTF16-V" : "UniJIS-UTF16-H";
765
0
    ordering = "Japan1";
766
0
    supplement = 6;
767
0
    break;
768
0
  case FZ_ADOBE_KOREA:
769
0
    basefont = serif ? "Batang" : "Dotum";
770
0
    encoding = wmode ? "UniKS-UTF16-V" : "UniKS-UTF16-H";
771
0
    ordering = "Korea1";
772
0
    supplement = 2;
773
0
    break;
774
0
  }
775
776
0
  flags = PDF_FD_SYMBOLIC;
777
0
  if (serif)
778
0
    flags |= PDF_FD_SERIF;
779
780
0
  fref = pdf_find_font_resource(ctx, doc, PDF_CJK_FONT_RESOURCE, script, fzfont, &key);
781
0
  if (fref)
782
0
    return fref;
783
784
0
  font = pdf_add_new_dict(ctx, doc, 5);
785
0
  fz_try(ctx)
786
0
  {
787
0
    pdf_dict_put(ctx, font, PDF_NAME(Type), PDF_NAME(Font));
788
0
    pdf_dict_put(ctx, font, PDF_NAME(Subtype), PDF_NAME(Type0));
789
0
    pdf_dict_put_name(ctx, font, PDF_NAME(BaseFont), basefont);
790
0
    pdf_dict_put_name(ctx, font, PDF_NAME(Encoding), encoding);
791
0
    dfonts = pdf_dict_put_array(ctx, font, PDF_NAME(DescendantFonts), 1);
792
0
    pdf_array_push_drop(ctx, dfonts, subfont = pdf_add_new_dict(ctx, doc, 5));
793
0
    {
794
0
      pdf_dict_put(ctx, subfont, PDF_NAME(Type), PDF_NAME(Font));
795
0
      pdf_dict_put(ctx, subfont, PDF_NAME(Subtype), PDF_NAME(CIDFontType0));
796
0
      pdf_dict_put_name(ctx, subfont, PDF_NAME(BaseFont), basefont);
797
0
      pdf_add_cid_system_info(ctx, doc, subfont, "Adobe", ordering, supplement);
798
0
      fontdesc = pdf_add_new_dict(ctx, doc, 8);
799
0
      pdf_dict_put_drop(ctx, subfont, PDF_NAME(FontDescriptor), fontdesc);
800
0
      {
801
0
        pdf_dict_put(ctx, fontdesc, PDF_NAME(Type), PDF_NAME(FontDescriptor));
802
0
        pdf_dict_put_text_string(ctx, fontdesc, PDF_NAME(FontName), basefont);
803
0
        pdf_dict_put_rect(ctx, fontdesc, PDF_NAME(FontBBox), bbox);
804
0
        pdf_dict_put_int(ctx, fontdesc, PDF_NAME(Flags), flags);
805
0
        pdf_dict_put_int(ctx, fontdesc, PDF_NAME(ItalicAngle), 0);
806
0
        pdf_dict_put_int(ctx, fontdesc, PDF_NAME(Ascent), 1000);
807
0
        pdf_dict_put_int(ctx, fontdesc, PDF_NAME(Descent), -200);
808
0
        pdf_dict_put_int(ctx, fontdesc, PDF_NAME(StemV), 80);
809
0
      }
810
0
    }
811
812
0
    fref = pdf_insert_font_resource(ctx, doc, &key, font);
813
0
  }
814
0
  fz_always(ctx)
815
0
    pdf_drop_obj(ctx, font);
816
0
  fz_catch(ctx)
817
0
    fz_rethrow(ctx);
818
819
0
  return fref;
820
0
}
821
822
pdf_obj *
823
pdf_add_substitute_font(fz_context *ctx, pdf_document *doc, fz_font *font)
824
0
{
825
0
  fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "substitute font creation is not implemented yet");
826
0
}