Coverage Report

Created: 2025-08-28 07:06

/src/ghostpdl/pdf/pdf_font3.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2019-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
/* code for type 3 font handling */
17
18
#include "pdf_int.h"
19
#include "pdf_stack.h"
20
#include "pdf_array.h"
21
#include "pdf_dict.h"
22
#include "pdf_font_types.h"
23
#include "pdf_gstate.h"
24
#include "pdf_font.h"
25
#include "pdf_font3.h"
26
#include "pdf_deref.h"
27
#include "gscencs.h"
28
#include "gscedata.h"       /* For the encoding arrays */
29
#include "gsccode.h"        /* For the Encoding indices */
30
#include "gsuid.h"          /* For no_UniqueID */
31
#include "gsutil.h"        /* For gs_next_ids() */
32
33
static int
34
pdfi_type3_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont,
35
                     gs_char chr, gs_glyph glyph)
36
77.4k
{
37
77.4k
    int code = 0;
38
77.4k
    pdf_font_type3 *font;
39
77.4k
    pdf_name *GlyphName = NULL;
40
77.4k
    pdf_stream *CharProc = NULL;
41
77.4k
    int SavedTextBlockDepth = 0;
42
77.4k
    char Notdef[8] = {".notdef"};
43
44
77.4k
    font = (pdf_font_type3 *)pfont->client_data;
45
46
77.4k
    SavedTextBlockDepth = OBJ_CTX(font)->text.BlockDepth;
47
77.4k
    code = pdfi_array_get(OBJ_CTX(font), font->Encoding, (uint64_t)chr, (pdf_obj **)&GlyphName);
48
77.4k
    if (code < 0)
49
0
        return code;
50
51
77.4k
    code = pdfi_dict_get_by_key(OBJ_CTX(font), font->CharProcs, GlyphName, (pdf_obj **)&CharProc);
52
77.4k
    if (code == gs_error_undefined) {
53
27.3k
        byte *Key = NULL;
54
        /* Can't find the named glyph, try to find a /.notdef as a substitute */
55
27.3k
        Key = gs_alloc_bytes(OBJ_MEMORY(font), 8, "working buffer for BuildChar");
56
27.3k
        if (Key == NULL)
57
0
            goto build_char_error;
58
27.3k
        memset(Key, 0x00, 8);
59
27.3k
        memcpy(Key, Notdef, 8);
60
27.3k
        code = pdfi_dict_get(OBJ_CTX(font), font->CharProcs, (const char *)Key, (pdf_obj **)&CharProc);
61
27.3k
        gs_free_object(OBJ_MEMORY(font), Key, "working buffer for BuildChar");
62
27.3k
        if (code == gs_error_undefined) {
63
27.0k
            code = 0;
64
27.0k
            goto build_char_error;
65
27.0k
        }
66
27.3k
    }
67
50.4k
    if (code < 0)
68
1.56k
        goto build_char_error;
69
48.8k
    if (pdfi_type_of(CharProc) != PDF_STREAM) {
70
389
        code = gs_note_error(gs_error_typecheck);
71
389
        goto build_char_error;
72
389
    }
73
74
48.4k
    OBJ_CTX(font)->text.BlockDepth = 0;
75
48.4k
    OBJ_CTX(font)->text.inside_CharProc = true;
76
48.4k
    OBJ_CTX(font)->text.CharProc_d_type = pdf_type3_d_none;
77
78
    /* We used to have code here to emulate some Acrobat behaviour, but it interferes with getting
79
     * the result of /tests/pdf/safedocs/ContentStreamNoCycleType3insideType3.pdf because for that
80
     * file the nested type 3 font CharProc must inherit the stroke colour from the outer type 3
81
     * font CharProc graphics state at the time the glyph is drawn. So the code was removed. The
82
     * Acrobat behaviour is not mentioned in the spec and Acrobat is completely incapable of
83
     * getting Patterns right, per the spec, when they are 'inside' multiple levels of content
84
     * streams.
85
     * The old comment began :
86
     *
87
     *    * It turns out that if a type 3 font uses a stroke to draw, and does not
88
     *    * acrually set the stroke colour, then we must use the fill colour instead.
89
     *    * In effect we start a type 3 BuildChar with stroke colour = fill colour.
90
     */
91
48.4k
    code = pdfi_gsave(OBJ_CTX(font));
92
48.4k
    if (code >= 0) {
93
48.4k
        code = pdfi_run_context(OBJ_CTX(font), CharProc, font->PDF_font, true, "CharProc");
94
48.4k
        (void)pdfi_grestore(OBJ_CTX(font));
95
48.4k
    }
96
97
48.4k
    OBJ_CTX(font)->text.inside_CharProc = false;
98
48.4k
    OBJ_CTX(font)->text.CharProc_d_type = pdf_type3_d_none;
99
48.4k
    OBJ_CTX(font)->text.BlockDepth = SavedTextBlockDepth;
100
101
77.4k
build_char_error:
102
77.4k
    pdfi_countdown(GlyphName);
103
77.4k
    pdfi_countdown(CharProc);
104
77.4k
    return code;
105
48.4k
}
106
107
static int alloc_type3_font(pdf_context *ctx, pdf_font_type3 **font)
108
3.12k
{
109
3.12k
    pdf_font_type3 *t3font = NULL;
110
111
3.12k
    t3font = (pdf_font_type3 *)gs_alloc_bytes(ctx->memory, sizeof(pdf_font_type3), "pdfi_alloc_type3_font");
112
3.12k
    if (t3font == NULL)
113
0
        return_error(gs_error_VMerror);
114
115
3.12k
    memset(t3font, 0x00, sizeof(pdf_font_type3));
116
3.12k
    (t3font)->ctx = ctx;
117
3.12k
    (t3font)->type = PDF_FONT;
118
119
#if REFCNT_DEBUG
120
    (t3font)->UID = ctx->UID++;
121
    outprintf(ctx->memory, "Allocated object of type %c with UID %"PRIi64"\n", t3font->type, t3font->UID);
122
#endif
123
124
125
3.12k
    pdfi_countup(t3font);
126
127
3.12k
    t3font->pfont = gs_alloc_struct(ctx->memory, gs_font_base, &st_gs_font_base,
128
3.12k
                            "pdfi (type 3 font)");
129
3.12k
    if (t3font->pfont == NULL) {
130
0
        pdfi_countdown(t3font);
131
0
        return_error(gs_error_VMerror);
132
0
    }
133
134
3.12k
    memset(t3font->pfont, 0x00, sizeof(gs_font_base));
135
3.12k
    t3font->ctx = ctx;
136
3.12k
    t3font->pdfi_font_type = e_pdf_font_type3;
137
138
3.12k
    gs_make_identity(&t3font->pfont->orig_FontMatrix);
139
3.12k
    gs_make_identity(&t3font->pfont->FontMatrix);
140
3.12k
    t3font->pfont->next = t3font->pfont->prev = 0;
141
3.12k
    t3font->pfont->memory = ctx->memory;
142
3.12k
    t3font->pfont->dir = ctx->font_dir;
143
3.12k
    t3font->pfont->is_resource = false;
144
3.12k
    gs_notify_init(&t3font->pfont->notify_list, ctx->memory);
145
3.12k
    t3font->pfont->base = (gs_font *) t3font->pfont;
146
3.12k
    t3font->pfont->client_data = t3font;
147
3.12k
    t3font->pfont->WMode = 0;
148
3.12k
    t3font->pfont->PaintType = 0;
149
3.12k
    t3font->pfont->StrokeWidth = 0;
150
3.12k
    t3font->pfont->is_cached = 0;
151
3.12k
    t3font->pfont->procs.init_fstack = gs_default_init_fstack;
152
3.12k
    t3font->pfont->procs.next_char_glyph = gs_default_next_char_glyph;
153
3.12k
    t3font->pfont->FAPI = NULL;
154
3.12k
    t3font->pfont->FAPI_font_data = NULL;
155
3.12k
    t3font->pfont->procs.glyph_name = ctx->get_glyph_name;
156
3.12k
    t3font->pfont->procs.decode_glyph = pdfi_decode_glyph;
157
3.12k
    t3font->pfont->procs.define_font = gs_no_define_font;
158
3.12k
    t3font->pfont->procs.make_font = gs_no_make_font;
159
160
3.12k
    t3font->default_font_info = gs_default_font_info;
161
3.12k
    t3font->pfont->procs.font_info = pdfi_default_font_info;
162
163
3.12k
    t3font->pfont->procs.glyph_info = gs_default_glyph_info;
164
3.12k
    t3font->pfont->procs.glyph_outline = gs_no_glyph_outline;
165
3.12k
    t3font->pfont->procs.encode_char = pdfi_encode_char;
166
3.12k
    t3font->pfont->procs.build_char = pdfi_type3_build_char;
167
3.12k
    t3font->pfont->procs.same_font = gs_default_same_font;
168
3.12k
    t3font->pfont->procs.enumerate_glyph = gs_no_enumerate_glyph;
169
170
3.12k
    t3font->pfont->FontType = ft_PDF_user_defined;
171
    /* outlines ? Bitmaps ? */
172
3.12k
    t3font->pfont->ExactSize = fbit_use_bitmaps;
173
3.12k
    t3font->pfont->InBetweenSize = fbit_use_bitmaps;
174
3.12k
    t3font->pfont->TransformedChar = fbit_transform_bitmaps;
175
176
3.12k
    t3font->pfont->encoding_index = ENCODING_INDEX_UNKNOWN;
177
3.12k
    t3font->pfont->nearest_encoding_index = ENCODING_INDEX_UNKNOWN;
178
179
3.12k
    t3font->pfont->client_data = (void *)t3font;
180
3.12k
    t3font->pfont->id = gs_next_ids(ctx->memory, 1);
181
3.12k
    uid_set_UniqueID(&t3font->pfont->UID, no_UniqueID);
182
183
3.12k
    *font = (pdf_font_type3 *)t3font;
184
3.12k
    return 0;
185
3.12k
}
186
187
int pdfi_free_font_type3(pdf_obj *font)
188
3.12k
{
189
3.12k
    pdf_font_type3 *t3font = (pdf_font_type3 *)font;
190
191
3.12k
    if (t3font->pfont)
192
3.12k
        gs_free_object(OBJ_MEMORY(t3font), t3font->pfont, "Free type 3 font");
193
194
3.12k
    if (t3font->Widths)
195
2.56k
        gs_free_object(OBJ_MEMORY(t3font), t3font->Widths, "Free type 3 font Widths array");
196
197
3.12k
    pdfi_countdown(t3font->PDF_font);
198
3.12k
    pdfi_countdown(t3font->FontDescriptor);
199
3.12k
    pdfi_countdown(t3font->CharProcs);
200
3.12k
    pdfi_countdown(t3font->Encoding);
201
3.12k
    pdfi_countdown(t3font->ToUnicode);
202
3.12k
    pdfi_countdown(t3font->filename); /* Should never exist, but just in case */
203
3.12k
    pdfi_countdown(t3font->copyright);
204
3.12k
    pdfi_countdown(t3font->notice);
205
3.12k
    pdfi_countdown(t3font->fullname);
206
3.12k
    pdfi_countdown(t3font->familyname);
207
208
3.12k
    gs_free_object(OBJ_MEMORY(font), font, "Free type 3 font");
209
3.12k
    return 0;
210
3.12k
}
211
212
213
int pdfi_read_type3_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, pdf_font **ppdffont)
214
3.12k
{
215
3.12k
    int code = 0;
216
3.12k
    pdf_font_type3 *font = NULL;
217
3.12k
    pdf_obj *obj = NULL;
218
3.12k
    pdf_obj *tounicode = NULL;
219
220
3.12k
    *ppdffont = NULL;
221
3.12k
    code = alloc_type3_font(ctx, &font);
222
3.12k
    if (code < 0)
223
0
        return code;
224
225
3.12k
    font->object_num = font_dict->object_num;
226
3.12k
    font->generation_num = font_dict->generation_num;
227
3.12k
    font->indirect_num = font_dict->indirect_num;
228
3.12k
    font->indirect_gen = font_dict->indirect_gen;
229
230
3.12k
    code = pdfi_dict_get_type(ctx, font_dict, "FontBBox", PDF_ARRAY, &obj);
231
3.12k
    if (code < 0)
232
25
        goto font3_error;
233
3.09k
    code = pdfi_array_to_gs_rect(ctx, (pdf_array *)obj, &font->pfont->FontBBox);
234
3.09k
    if (code < 0)
235
8
        goto font3_error;
236
3.08k
    pdfi_countdown(obj);
237
3.08k
    obj = NULL;
238
239
3.08k
    code = pdfi_dict_get_type(ctx, font_dict, "FontMatrix", PDF_ARRAY, &obj);
240
3.08k
    if (code < 0)
241
38
        goto font3_error;
242
3.05k
    code = pdfi_array_to_gs_matrix(ctx, (pdf_array *)obj, &font->pfont->orig_FontMatrix);
243
3.05k
    if (code < 0)
244
24
        goto font3_error;
245
3.02k
    code = pdfi_array_to_gs_matrix(ctx, (pdf_array *)obj, &font->pfont->FontMatrix);
246
3.02k
    if (code < 0)
247
0
        goto font3_error;
248
3.02k
    pdfi_countdown(obj);
249
3.02k
    obj = NULL;
250
251
3.02k
    code = pdfi_dict_get(ctx, font_dict, "CharProcs", (pdf_obj **)&font->CharProcs);
252
3.02k
    if (code < 0)
253
160
        goto font3_error;
254
255
256
2.86k
    code = pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, (pdf_obj **)&font->FontDescriptor);
257
2.86k
    if (code < 0)
258
16
        goto font3_error;
259
260
2.85k
    if (font->FontDescriptor != NULL) {
261
256
        pdf_obj *Name = NULL;
262
263
256
        code = pdfi_dict_get_type(ctx, (pdf_dict *) font->FontDescriptor, "FontName", PDF_NAME, (pdf_obj**)&Name);
264
256
        if (code < 0)
265
5
            pdfi_set_warning(ctx, 0, NULL, W_PDF_FDESC_BAD_FONTNAME, "pdfi_load_font", "");
266
256
        pdfi_countdown(Name);
267
256
    }
268
269
2.85k
    pdfi_font_set_first_last_char(ctx, font_dict, (pdf_font *)font);
270
    /* ignore errors with widths... for now */
271
2.85k
    (void)pdfi_font_create_widths(ctx, font_dict, (pdf_font*)font, 1.0);
272
273
274
2.85k
    code = pdfi_dict_get(ctx, font_dict, "Encoding", &obj);
275
2.85k
    if (code < 0)
276
309
        goto font3_error;
277
278
2.54k
    code = pdfi_create_Encoding(ctx, (pdf_font *)font, obj, NULL, (pdf_obj **)&font->Encoding);
279
2.54k
    if (code < 0)
280
34
        goto font3_error;
281
2.50k
    pdfi_countdown(obj);
282
283
2.50k
    font->PDF_font = font_dict;
284
2.50k
    pdfi_countup(font_dict);
285
286
2.50k
    if (ctx->args.ignoretounicode != true) {
287
2.50k
        code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
288
2.50k
        if (code >= 0 && pdfi_type_of(tounicode) == PDF_STREAM) {
289
818
            pdf_cmap *tu = NULL;
290
818
            code = pdfi_read_cmap(ctx, tounicode, &tu);
291
818
            pdfi_countdown(tounicode);
292
818
            tounicode = (pdf_obj *)tu;
293
818
        }
294
2.50k
        if (code < 0 || (tounicode != NULL && pdfi_type_of(tounicode) != PDF_CMAP)) {
295
1.71k
            pdfi_countdown(tounicode);
296
1.71k
            tounicode = NULL;
297
1.71k
            code = 0;
298
1.71k
        }
299
2.50k
    }
300
0
    else {
301
0
        tounicode = NULL;
302
0
    }
303
304
2.50k
    font->ToUnicode = tounicode;
305
2.50k
    tounicode = NULL;
306
307
2.50k
    code = replace_cache_entry(ctx, (pdf_obj *)font);
308
2.50k
    if (code < 0)
309
0
        goto font3_error;
310
311
2.50k
    pdfi_font_set_orig_fonttype(ctx, (pdf_font *)font);
312
2.50k
    code = gs_definefont(ctx->font_dir, (gs_font *)font->pfont);
313
2.50k
    if (code < 0)
314
0
        goto font3_error;
315
316
2.50k
    *ppdffont = (pdf_font *)font;
317
318
2.50k
    return code;
319
320
614
font3_error:
321
614
    pdfi_countdown(obj);
322
614
    pdfi_countdown(font);
323
614
    return code;
324
2.50k
}