Coverage Report

Created: 2025-06-10 07:27

/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
74.2k
{
37
74.2k
    int code = 0;
38
74.2k
    pdf_font_type3 *font;
39
74.2k
    pdf_name *GlyphName = NULL;
40
74.2k
    pdf_stream *CharProc = NULL;
41
74.2k
    int SavedTextBlockDepth = 0;
42
74.2k
    char Notdef[8] = {".notdef"};
43
44
74.2k
    font = (pdf_font_type3 *)pfont->client_data;
45
46
74.2k
    SavedTextBlockDepth = OBJ_CTX(font)->text.BlockDepth;
47
74.2k
    code = pdfi_array_get(OBJ_CTX(font), font->Encoding, (uint64_t)chr, (pdf_obj **)&GlyphName);
48
74.2k
    if (code < 0)
49
0
        return code;
50
51
74.2k
    code = pdfi_dict_get_by_key(OBJ_CTX(font), font->CharProcs, GlyphName, (pdf_obj **)&CharProc);
52
74.2k
    if (code == gs_error_undefined) {
53
25.6k
        byte *Key = NULL;
54
        /* Can't find the named glyph, try to find a /.notdef as a substitute */
55
25.6k
        Key = gs_alloc_bytes(OBJ_MEMORY(font), 8, "working buffer for BuildChar");
56
25.6k
        if (Key == NULL)
57
0
            goto build_char_error;
58
25.6k
        memset(Key, 0x00, 8);
59
25.6k
        memcpy(Key, Notdef, 8);
60
25.6k
        code = pdfi_dict_get(OBJ_CTX(font), font->CharProcs, (const char *)Key, (pdf_obj **)&CharProc);
61
25.6k
        gs_free_object(OBJ_MEMORY(font), Key, "working buffer for BuildChar");
62
25.6k
        if (code == gs_error_undefined) {
63
25.3k
            code = 0;
64
25.3k
            goto build_char_error;
65
25.3k
        }
66
25.6k
    }
67
48.8k
    if (code < 0)
68
1.32k
        goto build_char_error;
69
47.5k
    if (pdfi_type_of(CharProc) != PDF_STREAM) {
70
332
        code = gs_note_error(gs_error_typecheck);
71
332
        goto build_char_error;
72
332
    }
73
74
47.2k
    OBJ_CTX(font)->text.BlockDepth = 0;
75
47.2k
    OBJ_CTX(font)->text.inside_CharProc = true;
76
47.2k
    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
47.2k
    code = pdfi_gsave(OBJ_CTX(font));
92
47.2k
    if (code >= 0) {
93
47.2k
        code = pdfi_run_context(OBJ_CTX(font), CharProc, font->PDF_font, true, "CharProc");
94
47.2k
        (void)pdfi_grestore(OBJ_CTX(font));
95
47.2k
    }
96
97
47.2k
    OBJ_CTX(font)->text.inside_CharProc = false;
98
47.2k
    OBJ_CTX(font)->text.CharProc_d_type = pdf_type3_d_none;
99
47.2k
    OBJ_CTX(font)->text.BlockDepth = SavedTextBlockDepth;
100
101
74.2k
build_char_error:
102
74.2k
    pdfi_countdown(GlyphName);
103
74.2k
    pdfi_countdown(CharProc);
104
74.2k
    return code;
105
47.2k
}
106
107
static int alloc_type3_font(pdf_context *ctx, pdf_font_type3 **font)
108
2.86k
{
109
2.86k
    pdf_font_type3 *t3font = NULL;
110
111
2.86k
    t3font = (pdf_font_type3 *)gs_alloc_bytes(ctx->memory, sizeof(pdf_font_type3), "pdfi_alloc_type3_font");
112
2.86k
    if (t3font == NULL)
113
0
        return_error(gs_error_VMerror);
114
115
2.86k
    memset(t3font, 0x00, sizeof(pdf_font_type3));
116
2.86k
    (t3font)->ctx = ctx;
117
2.86k
    (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
2.86k
    pdfi_countup(t3font);
126
127
2.86k
    t3font->pfont = gs_alloc_struct(ctx->memory, gs_font_base, &st_gs_font_base,
128
2.86k
                            "pdfi (type 3 font)");
129
2.86k
    if (t3font->pfont == NULL) {
130
0
        pdfi_countdown(t3font);
131
0
        return_error(gs_error_VMerror);
132
0
    }
133
134
2.86k
    memset(t3font->pfont, 0x00, sizeof(gs_font_base));
135
2.86k
    t3font->ctx = ctx;
136
2.86k
    t3font->pdfi_font_type = e_pdf_font_type3;
137
138
2.86k
    gs_make_identity(&t3font->pfont->orig_FontMatrix);
139
2.86k
    gs_make_identity(&t3font->pfont->FontMatrix);
140
2.86k
    t3font->pfont->next = t3font->pfont->prev = 0;
141
2.86k
    t3font->pfont->memory = ctx->memory;
142
2.86k
    t3font->pfont->dir = ctx->font_dir;
143
2.86k
    t3font->pfont->is_resource = false;
144
2.86k
    gs_notify_init(&t3font->pfont->notify_list, ctx->memory);
145
2.86k
    t3font->pfont->base = (gs_font *) t3font->pfont;
146
2.86k
    t3font->pfont->client_data = t3font;
147
2.86k
    t3font->pfont->WMode = 0;
148
2.86k
    t3font->pfont->PaintType = 0;
149
2.86k
    t3font->pfont->StrokeWidth = 0;
150
2.86k
    t3font->pfont->is_cached = 0;
151
2.86k
    t3font->pfont->procs.init_fstack = gs_default_init_fstack;
152
2.86k
    t3font->pfont->procs.next_char_glyph = gs_default_next_char_glyph;
153
2.86k
    t3font->pfont->FAPI = NULL;
154
2.86k
    t3font->pfont->FAPI_font_data = NULL;
155
2.86k
    t3font->pfont->procs.glyph_name = ctx->get_glyph_name;
156
2.86k
    t3font->pfont->procs.decode_glyph = pdfi_decode_glyph;
157
2.86k
    t3font->pfont->procs.define_font = gs_no_define_font;
158
2.86k
    t3font->pfont->procs.make_font = gs_no_make_font;
159
160
2.86k
    t3font->default_font_info = gs_default_font_info;
161
2.86k
    t3font->pfont->procs.font_info = pdfi_default_font_info;
162
163
2.86k
    t3font->pfont->procs.glyph_info = gs_default_glyph_info;
164
2.86k
    t3font->pfont->procs.glyph_outline = gs_no_glyph_outline;
165
2.86k
    t3font->pfont->procs.encode_char = pdfi_encode_char;
166
2.86k
    t3font->pfont->procs.build_char = pdfi_type3_build_char;
167
2.86k
    t3font->pfont->procs.same_font = gs_default_same_font;
168
2.86k
    t3font->pfont->procs.enumerate_glyph = gs_no_enumerate_glyph;
169
170
2.86k
    t3font->pfont->FontType = ft_PDF_user_defined;
171
    /* outlines ? Bitmaps ? */
172
2.86k
    t3font->pfont->ExactSize = fbit_use_bitmaps;
173
2.86k
    t3font->pfont->InBetweenSize = fbit_use_bitmaps;
174
2.86k
    t3font->pfont->TransformedChar = fbit_transform_bitmaps;
175
176
2.86k
    t3font->pfont->encoding_index = ENCODING_INDEX_UNKNOWN;
177
2.86k
    t3font->pfont->nearest_encoding_index = ENCODING_INDEX_UNKNOWN;
178
179
2.86k
    t3font->pfont->client_data = (void *)t3font;
180
2.86k
    t3font->pfont->id = gs_next_ids(ctx->memory, 1);
181
2.86k
    uid_set_UniqueID(&t3font->pfont->UID, no_UniqueID);
182
183
2.86k
    *font = (pdf_font_type3 *)t3font;
184
2.86k
    return 0;
185
2.86k
}
186
187
int pdfi_free_font_type3(pdf_obj *font)
188
2.86k
{
189
2.86k
    pdf_font_type3 *t3font = (pdf_font_type3 *)font;
190
191
2.86k
    if (t3font->pfont)
192
2.86k
        gs_free_object(OBJ_MEMORY(t3font), t3font->pfont, "Free type 3 font");
193
194
2.86k
    if (t3font->Widths)
195
2.38k
        gs_free_object(OBJ_MEMORY(t3font), t3font->Widths, "Free type 3 font Widths array");
196
197
2.86k
    pdfi_countdown(t3font->PDF_font);
198
2.86k
    pdfi_countdown(t3font->FontDescriptor);
199
2.86k
    pdfi_countdown(t3font->CharProcs);
200
2.86k
    pdfi_countdown(t3font->Encoding);
201
2.86k
    pdfi_countdown(t3font->ToUnicode);
202
2.86k
    pdfi_countdown(t3font->filename); /* Should never exist, but just in case */
203
2.86k
    pdfi_countdown(t3font->copyright);
204
2.86k
    pdfi_countdown(t3font->notice);
205
2.86k
    pdfi_countdown(t3font->fullname);
206
2.86k
    pdfi_countdown(t3font->familyname);
207
208
2.86k
    gs_free_object(OBJ_MEMORY(font), font, "Free type 3 font");
209
2.86k
    return 0;
210
2.86k
}
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
2.86k
{
215
2.86k
    int code = 0;
216
2.86k
    pdf_font_type3 *font = NULL;
217
2.86k
    pdf_obj *obj = NULL;
218
2.86k
    pdf_obj *tounicode = NULL;
219
220
2.86k
    *ppdffont = NULL;
221
2.86k
    code = alloc_type3_font(ctx, &font);
222
2.86k
    if (code < 0)
223
0
        return code;
224
225
2.86k
    font->object_num = font_dict->object_num;
226
2.86k
    font->generation_num = font_dict->generation_num;
227
2.86k
    font->indirect_num = font_dict->indirect_num;
228
2.86k
    font->indirect_gen = font_dict->indirect_gen;
229
230
2.86k
    code = pdfi_dict_get_type(ctx, font_dict, "FontBBox", PDF_ARRAY, &obj);
231
2.86k
    if (code < 0)
232
15
        goto font3_error;
233
2.85k
    code = pdfi_array_to_gs_rect(ctx, (pdf_array *)obj, &font->pfont->FontBBox);
234
2.85k
    if (code < 0)
235
7
        goto font3_error;
236
2.84k
    pdfi_countdown(obj);
237
2.84k
    obj = NULL;
238
239
2.84k
    code = pdfi_dict_get_type(ctx, font_dict, "FontMatrix", PDF_ARRAY, &obj);
240
2.84k
    if (code < 0)
241
37
        goto font3_error;
242
2.80k
    code = pdfi_array_to_gs_matrix(ctx, (pdf_array *)obj, &font->pfont->orig_FontMatrix);
243
2.80k
    if (code < 0)
244
19
        goto font3_error;
245
2.79k
    code = pdfi_array_to_gs_matrix(ctx, (pdf_array *)obj, &font->pfont->FontMatrix);
246
2.79k
    if (code < 0)
247
0
        goto font3_error;
248
2.79k
    pdfi_countdown(obj);
249
2.79k
    obj = NULL;
250
251
2.79k
    code = pdfi_dict_get(ctx, font_dict, "CharProcs", (pdf_obj **)&font->CharProcs);
252
2.79k
    if (code < 0)
253
144
        goto font3_error;
254
255
256
2.64k
    code = pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, (pdf_obj **)&font->FontDescriptor);
257
2.64k
    if (code < 0)
258
15
        goto font3_error;
259
260
2.63k
    if (font->FontDescriptor != NULL) {
261
225
        pdf_obj *Name = NULL;
262
263
225
        code = pdfi_dict_get_type(ctx, (pdf_dict *) font->FontDescriptor, "FontName", PDF_NAME, (pdf_obj**)&Name);
264
225
        if (code < 0)
265
4
            pdfi_set_warning(ctx, 0, NULL, W_PDF_FDESC_BAD_FONTNAME, "pdfi_load_font", "");
266
225
        pdfi_countdown(Name);
267
225
    }
268
269
2.63k
    pdfi_font_set_first_last_char(ctx, font_dict, (pdf_font *)font);
270
    /* ignore errors with widths... for now */
271
2.63k
    (void)pdfi_font_create_widths(ctx, font_dict, (pdf_font*)font, 1.0);
272
273
274
2.63k
    code = pdfi_dict_get(ctx, font_dict, "Encoding", &obj);
275
2.63k
    if (code < 0)
276
281
        goto font3_error;
277
278
2.35k
    code = pdfi_create_Encoding(ctx, (pdf_font *)font, obj, NULL, (pdf_obj **)&font->Encoding);
279
2.35k
    if (code < 0)
280
29
        goto font3_error;
281
2.32k
    pdfi_countdown(obj);
282
283
2.32k
    font->PDF_font = font_dict;
284
2.32k
    pdfi_countup(font_dict);
285
286
2.32k
    if (ctx->args.ignoretounicode != true) {
287
2.32k
        code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode);
288
2.32k
        if (code >= 0 && pdfi_type_of(tounicode) == PDF_STREAM) {
289
807
            pdf_cmap *tu = NULL;
290
807
            code = pdfi_read_cmap(ctx, tounicode, &tu);
291
807
            pdfi_countdown(tounicode);
292
807
            tounicode = (pdf_obj *)tu;
293
807
        }
294
2.32k
        if (code < 0 || (tounicode != NULL && pdfi_type_of(tounicode) != PDF_CMAP)) {
295
1.53k
            pdfi_countdown(tounicode);
296
1.53k
            tounicode = NULL;
297
1.53k
            code = 0;
298
1.53k
        }
299
2.32k
    }
300
0
    else {
301
0
        tounicode = NULL;
302
0
    }
303
304
2.32k
    font->ToUnicode = tounicode;
305
2.32k
    tounicode = NULL;
306
307
2.32k
    code = replace_cache_entry(ctx, (pdf_obj *)font);
308
2.32k
    if (code < 0)
309
0
        goto font3_error;
310
311
2.32k
    pdfi_font_set_orig_fonttype(ctx, (pdf_font *)font);
312
2.32k
    code = gs_definefont(ctx->font_dir, (gs_font *)font->pfont);
313
2.32k
    if (code < 0)
314
0
        goto font3_error;
315
316
2.32k
    *ppdffont = (pdf_font *)font;
317
318
2.32k
    return code;
319
320
547
font3_error:
321
547
    pdfi_countdown(obj);
322
547
    pdfi_countdown(font);
323
547
    return code;
324
2.32k
}