Coverage Report

Created: 2025-06-24 07:01

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