Coverage Report

Created: 2025-06-10 07:06

/src/ghostpdl/psi/zfont1.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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
17
/* Type 1 and Type 4 font creation operators */
18
#include "memory_.h"
19
#include "ghost.h"
20
#include "oper.h"
21
#include "gxfixed.h"
22
#include "gsmatrix.h"
23
#include "gxdevice.h"
24
#include "gxfont.h"
25
#include "gxfont1.h"
26
#include "bfont.h"
27
#include "ialloc.h"
28
#include "icharout.h"
29
#include "ichar1.h"
30
#include "idict.h"
31
#include "idparam.h"
32
#include "ifont1.h"
33
#include "iname.h"    /* for name_index in enumerate_glyph */
34
#include "store.h"
35
36
/* Type 1 font procedures (defined in zchar1.c) */
37
extern const gs_type1_data_procs_t z1_data_procs;
38
font_proc_glyph_info(z1_glyph_info);
39
/* Font procedures defined here */
40
static font_proc_same_font(z1_same_font);
41
42
/* ------ Private utilities ------ */
43
44
static void
45
find_zone_height(float *pmax_height, int count, const float *values)
46
4.89k
{
47
4.89k
    int i;
48
4.89k
    float zone_height;
49
50
9.79k
    for (i = 0; i < count; i += 2)
51
4.89k
        if ((zone_height = values[i + 1] - values[i]) > *pmax_height)
52
1.22k
            *pmax_height = zone_height;
53
4.89k
}
54
55
/* ------ Font procedures ------ */
56
57
static int
58
z1_enumerate_glyph(gs_font * pfont, int *pindex, gs_glyph_space_t ignored,
59
                   gs_glyph * pglyph)
60
0
{
61
0
    const gs_font_type1 *const pfont1 = (gs_font_type1 *)pfont;
62
0
    const ref *pcsdict = &pfont_data(pfont1)->CharStrings;
63
64
0
    return zchar_enumerate_glyph(pfont->memory, pcsdict, pindex, pglyph);
65
0
}
66
67
/* ------ Public procedures ------ */
68
69
/* Extract pointers to internal structures. */
70
int
71
charstring_font_get_refs(const_os_ptr op, charstring_font_refs_t *pfr)
72
1.22k
{
73
1.22k
    check_type(*op, t_dictionary);
74
1.22k
    if (dict_find_string(op, "Private", &pfr->Private) <= 0 ||
75
1.22k
        !r_has_type(pfr->Private, t_dictionary)
76
1.22k
        )
77
0
        return_error(gs_error_invalidfont);
78
1.22k
    make_empty_array(&pfr->no_subrs, 0);
79
1.22k
    if (dict_find_string(pfr->Private, "OtherSubrs", &pfr->OtherSubrs) > 0) {
80
1.22k
        if (!r_is_array(pfr->OtherSubrs))
81
0
            return_error(gs_error_typecheck);
82
1.22k
    } else
83
0
        pfr->OtherSubrs = &pfr->no_subrs;
84
1.22k
    if (dict_find_string(pfr->Private, "Subrs", &pfr->Subrs) > 0) {
85
1.22k
        if (!r_is_array(pfr->Subrs))
86
0
            return_error(gs_error_typecheck);
87
1.22k
    } else
88
0
        pfr->Subrs = &pfr->no_subrs;
89
1.22k
    pfr->GlobalSubrs = &pfr->no_subrs;
90
1.22k
    return 0;
91
1.22k
}
92
93
static int
94
charstring_check_mm_params(ref *fdict, unsigned int ndesigns)
95
0
{
96
0
    ref *p1;
97
0
    ref p2, p3;
98
0
    ref *Blend, *FInfo, *BFInfo, *BPriv;
99
0
    int code;
100
0
    int i, j;
101
0
    gs_memory_t *mem = dict_mem(fdict->value.pdict);
102
103
0
    code = dict_find_string(fdict, "$Blend", &p1);
104
0
    if (code < 0 || !r_is_proc(p1))
105
0
        goto bad;
106
107
0
    code = dict_find_string(fdict, "FontInfo", &FInfo);
108
0
    if (code < 0 || !r_has_type(FInfo, t_dictionary))
109
0
        goto bad;
110
111
0
    code = dict_find_string(FInfo, "BlendAxisTypes", &p1);
112
0
    if (code < 0 || !r_is_array(p1))
113
0
        goto bad;
114
0
    for (i = 0; i < r_size(p1); i ++) {
115
0
        code = array_get(mem, p1, i, &p2);
116
0
        if (code < 0 || !r_has_type(&p2, t_name))
117
0
            goto bad;
118
0
    }
119
0
    code = dict_find_string(FInfo, "BlendDesignPositions", &p1);
120
0
    if (code < 0 || !r_is_array(p1))
121
0
        goto bad;
122
0
    for (i = 0; i < r_size(p1); i++) {
123
0
        code = array_get(mem, p1, i, &p2);
124
0
        if (code < 0 || !r_is_array(&p2)) {
125
0
            goto bad;
126
0
        }
127
0
        else {
128
0
            for (j = 0; j < r_size(&p2); j++) {
129
0
                code = array_get(mem, &p2, j, &p3);
130
0
                if (code < 0 || !r_has_type(&p3, t_integer))
131
0
                    goto bad;
132
0
            }
133
0
        }
134
0
    }
135
0
    code = dict_find_string(FInfo, "BlendDesignMap", &p1);
136
0
    if (code < 0 || !r_is_array(p1))
137
0
        goto bad;
138
0
    for (i = 0; i < r_size(p1); i++) {
139
0
        code = array_get(mem, p1, i , &p2);
140
0
        if (code < 0 || !r_is_array(&p2)) {
141
0
            goto bad;
142
0
        }
143
0
        else {
144
0
            for (j = 0; j < r_size(&p2); j++) {
145
0
                code = array_get(mem, &p2, j, &p3);
146
0
                if (code < 0 || !r_is_array(&p3))
147
0
                    goto bad;
148
0
                else {
149
0
                    ref p5;
150
0
                    int k;
151
0
                    for (k = 0; k < r_size(&p3); k++) {
152
0
                        code = array_get(mem, &p3, k, &p5);
153
0
                        if (code < 0 || !r_is_number(&p5))
154
0
                            goto bad;
155
0
                    }
156
0
                }
157
0
            }
158
0
        }
159
0
    }
160
0
    code = dict_find_string(fdict, "Blend", &Blend);
161
0
    if (code < 0 || !r_has_type(Blend, t_dictionary))
162
0
        goto bad;
163
0
    code = dict_find_string(Blend, "FontBBox", &p1);
164
0
    if (code < 0 || !r_is_array(p1))
165
0
        goto bad;
166
0
    for (i = 0; i < r_size(p1); i++) {
167
0
         code = array_get(mem, p1, i, &p2);
168
0
         if (code < 0 || !r_is_array(&p2)) {
169
0
             goto bad;
170
0
         }
171
0
         else {
172
0
             for (j = 0; j < r_size(&p2); j++) {
173
0
                 code = array_get(mem, &p2, j, &p3);
174
0
                 if (code < 0 || !r_is_number(&p3))
175
0
                     goto bad;
176
0
             }
177
0
         }
178
0
    }
179
0
    code = dict_find_string(Blend, "Private", &BPriv);
180
0
    if (code < 0 || !r_has_type(BPriv, t_dictionary))
181
0
        goto bad;
182
0
    code = dict_find_string(BPriv, "BlueValues", &p1);
183
0
    if (code > 0) {
184
0
        if (!r_is_array(p1) || r_size(p1) < 2) {
185
0
            goto bad;
186
0
        }
187
0
        else {
188
0
            for (i = 0; i < r_size(p1); i++) {
189
0
                code = array_get(mem, p1, i, &p2);
190
0
                if (code < 0 || !r_is_array(&p2)) {
191
0
                    goto bad;
192
0
                }
193
0
                else {
194
0
                    for (j = 0; j < r_size(&p2); j++) {
195
0
                        code = array_get(mem, &p2, j, &p3);
196
0
                        if (code < 0 || !r_has_type(&p3, t_integer))
197
0
                            goto bad;
198
0
                    }
199
0
                }
200
0
            }
201
0
        }
202
0
    }
203
0
    code = dict_find_string(BPriv, "OtherBlues", &p1);
204
0
    if (code > 0) {
205
0
        if (!r_is_array(p1) || r_size(p1) < 2) {
206
0
            goto bad;
207
0
        }
208
0
        else {
209
0
            for (i = 0; i < r_size(p1); i++) {
210
0
                code = array_get(mem, p1, i, &p2);
211
0
                if (code < 0 || !r_is_array(&p2))
212
0
                    goto bad;
213
0
                else {
214
0
                    for (j = 0; j < r_size(&p2); j++) {
215
0
                        code = array_get(mem, &p2, j, &p3);
216
0
                        if (code < 0 || !r_has_type(&p3, t_integer))
217
0
                            goto bad;
218
0
                    }
219
0
                }
220
0
            }
221
0
        }
222
0
    }
223
0
    code = dict_find_string(BPriv, "StdHW", &p1);
224
0
    if (code > 0) {
225
0
        if (!r_is_array(p1)) {
226
0
            goto bad;
227
0
        }
228
0
        else {
229
0
            for (i = 0; i < r_size(p1); i++){
230
0
                code = array_get(mem, p1, i, &p2);
231
0
                if (code < 0 || !r_is_array(&p2))
232
0
                    goto bad;
233
0
                else {
234
0
                    for (j = 0; j < r_size(&p2); j++) {
235
0
                        code = array_get(mem, &p2, j, &p3);
236
0
                        if (code < 0 || !r_is_number(&p3))
237
0
                            goto bad;
238
0
                    }
239
0
                }
240
0
            }
241
0
        }
242
0
    }
243
0
    code = dict_find_string(BPriv, "StdVW", &p1);
244
0
    if (code > 0) {
245
0
        if (!r_is_array(p1)) {
246
0
            goto bad;
247
0
        }
248
0
        else {
249
0
            for (i = 0; i < r_size(p1); i++){
250
0
                code = array_get(mem, p1, i, &p2);
251
0
                if (code < 0 || !r_is_array(&p2))
252
0
                    goto bad;
253
0
                else {
254
0
                    for (j = 0; j < r_size(&p2); j++) {
255
0
                        code = array_get(mem, &p2, j, &p3);
256
0
                        if (code < 0 || !r_is_number(&p3))
257
0
                            goto bad;
258
0
                    }
259
0
                }
260
0
            }
261
0
        }
262
0
    }
263
0
    code = dict_find_string(BPriv, "StemSnapH,", &p1);
264
0
    if (code > 0) {
265
0
        if (!r_is_array(p1)) {
266
0
            goto bad;
267
0
        }
268
0
        else {
269
0
            for (i = 0; i < r_size(p1); i++){
270
0
                code = array_get(mem, p1, i, &p2);
271
0
                if (code < 0 || !r_is_array(&p2))
272
0
                    goto bad;
273
0
                else {
274
0
                    for (j = 0; j < r_size(&p2); j++) {
275
0
                        code = array_get(mem, &p2, j, &p3);
276
0
                        if (code < 0 || !r_is_number(&p3))
277
0
                            goto bad;
278
0
                    }
279
0
                }
280
0
            }
281
0
        }
282
0
    }
283
0
    code = dict_find_string(BPriv, "StemSnapV", &p1);
284
0
    if (code > 0) {
285
0
        if (!r_is_array(p1)) {
286
0
            goto bad;
287
0
        }
288
0
        else {
289
0
            for (i = 0; i < r_size(p1); i++){
290
0
                code = array_get(mem, p1, i, &p2);
291
0
                if (code < 0 || !r_is_array(&p2))
292
0
                    goto bad;
293
0
                else {
294
0
                    for (j = 0; j < r_size(&p2); j++) {
295
0
                        code = array_get(mem, &p2, j, &p3);
296
0
                        if (code < 0 || !r_is_number(&p3))
297
0
                            goto bad;
298
0
                    }
299
0
                }
300
0
            }
301
0
        }
302
0
    }
303
0
    code = dict_find_string(BPriv, "BlueScale", &p1);
304
0
    if (code > 0) {
305
0
        if (!r_is_array(p1)) {
306
0
            goto bad;
307
0
        }
308
0
        else {
309
0
            for (i = 0; i < r_size(p1); i++) {
310
0
                code = array_get(mem, p1, i, &p3);
311
0
                if (code < 0 || !r_is_number(&p3))
312
0
                    goto bad;
313
0
            }
314
0
        }
315
0
    }
316
0
    code = dict_find_string(BPriv, "BlueShift", &p1);
317
0
    if (code > 0) {
318
0
        if (!r_is_array(p1)) {
319
0
            goto bad;
320
0
        }
321
0
        else {
322
0
            for (i = 0; i < r_size(p1); i++) {
323
0
                code = array_get(mem, p1, i, &p3);
324
0
                if (code < 0 || !r_has_type(&p3, t_integer))
325
0
                    goto bad;
326
0
            }
327
0
        }
328
0
    }
329
0
    code = dict_find_string(BPriv, "FamilyBlues", &p1);
330
0
    if (code > 0) {
331
0
        if (!r_is_array(p1) || r_size(p1) < 2) {
332
0
            goto bad;
333
0
        }
334
0
        else {
335
0
            for (i = 0; i < r_size(p1); i++){
336
0
                code = array_get(mem, p1, i, &p2);
337
0
                if (code < 0 || !r_is_array(&p2))
338
0
                    goto bad;
339
0
                else {
340
0
                    for (j = 0; j < r_size(&p2); j++) {
341
0
                        code = array_get(mem, &p2, j, &p3);
342
0
                        if (code < 0 || !r_has_type(&p3, t_integer))
343
0
                            goto bad;
344
0
                    }
345
0
                }
346
0
            }
347
0
        }
348
0
    }
349
0
    code = dict_find_string(BPriv, "FamilyOtherBlues", &p1);
350
0
    if (code > 0) {
351
0
        if (!r_is_array(p1) || r_size(p1) < 2) {
352
0
            goto bad;
353
0
        }
354
0
        else {
355
0
            for (i = 0; i < r_size(p1); i++){
356
0
                code = array_get(mem, p1, i, &p2);
357
0
                if (code < 0 || !r_is_array(&p2))
358
0
                    goto bad;
359
0
                else {
360
0
                    for (j = 0; j < r_size(&p2); j++) {
361
0
                        code = array_get(mem, &p2, j, &p3);
362
0
                        if (code < 0 || !r_has_type(&p3, t_integer))
363
0
                            goto bad;
364
0
                    }
365
0
                }
366
0
            }
367
0
        }
368
0
    }
369
0
    code = dict_find_string(BPriv, "ForceBold", &p1);
370
0
    if (code > 0) {
371
0
        if (!r_is_array(p1)) {
372
0
            goto bad;
373
0
        }
374
0
        else {
375
0
            for (i = 0; i < r_size(p1); i++) {
376
0
                code = array_get(mem, p1, i, &p3);
377
0
                if (code < 0 || !r_has_type(&p3, t_boolean))
378
0
                    goto bad;
379
0
            }
380
0
        }
381
0
    }
382
0
    code = dict_find_string(Blend, "FontInfo", &BFInfo);
383
0
    if (code > 0 && r_has_type(BFInfo, t_dictionary)) {
384
0
        code = dict_find_string(BFInfo, "UnderlinePosition", &p1);
385
0
        if (code > 0) {
386
0
            if (!r_is_array(p1)) {
387
0
                goto bad;
388
0
            }
389
0
            else {
390
0
                for (i = 0; i < r_size(p1); i++) {
391
0
                    code = array_get(mem, p1, i, &p3);
392
0
                    if (code < 0 || !r_is_number(&p3))
393
0
                        goto bad;
394
0
                }
395
0
            }
396
0
        }
397
0
        code = dict_find_string(BFInfo, "UnderlineThickness", &p1);
398
0
        if (code > 0) {
399
0
            if (!r_is_array(p1)) {
400
0
                goto bad;
401
0
            }
402
0
            else {
403
0
                for (i = 0; i < r_size(p1); i++) {
404
0
                    code = array_get(mem, p1, i, &p3);
405
0
                    if (code < 0 || !r_is_number(&p3))
406
0
                        goto bad;
407
0
                }
408
0
            }
409
0
        }
410
0
        code = dict_find_string(BFInfo, "ItalicAngle", &p1);
411
0
        if (code > 0) {
412
0
            if (!r_is_array(p1)) {
413
0
                goto bad;
414
0
            }
415
0
            else {
416
0
                for (i = 0; i < r_size(p1); i++) {
417
0
                    code = array_get(mem, p1, i, &p3);
418
0
                    if (code < 0 || !r_is_number(&p3))
419
0
                        goto bad;
420
0
                }
421
0
            }
422
0
        }
423
0
    }
424
0
    return 0;
425
0
bad:
426
0
    return_error(gs_error_invalidfont);
427
0
}
428
429
/* Get the parameters of a CharString-based font or a FDArray entry. */
430
int
431
charstring_font_params(const gs_memory_t *mem,
432
                       const_os_ptr op, charstring_font_refs_t *pfr,
433
                       gs_type1_data *pdata1)
434
1.22k
{
435
1.22k
    const ref *pprivate = pfr->Private;
436
1.22k
    int code;
437
438
    /* Get the rest of the information from the Private dictionary. */
439
1.22k
    if ((code = dict_int_param(pprivate, "lenIV", -1, 255, pdata1->lenIV, &pdata1->lenIV)) < 0)
440
0
        return code;
441
1.22k
    if ((code = dict_uint_param(pprivate, "subroutineNumberBias",
442
1.22k
         0, max_uint, pdata1->subroutineNumberBias, &pdata1->subroutineNumberBias)) < 0)
443
0
        return code;
444
1.22k
    if ((code = dict_int_param(pprivate, "BlueFuzz", 0, 1999, 1, &pdata1->BlueFuzz)) < 0)
445
0
        return code;
446
1.22k
    if ((code = dict_float_param(pprivate, "BlueScale", 0.039625, &pdata1->BlueScale)) < 0)
447
0
        return code;
448
1.22k
    if ((code = dict_float_param(pprivate, "BlueShift", 7.0, &pdata1->BlueShift)) < 0)
449
0
        return code;
450
1.22k
    if ((code = pdata1->BlueValues.count = dict_float_array_param(mem, pprivate, "BlueValues",
451
1.22k
                max_BlueValues * 2, &pdata1->BlueValues.values[0], NULL)) < 0)
452
0
        return code;
453
1.22k
    if (pdata1->BlueValues.count % 2 != 0)
454
0
        return_error(gs_error_rangecheck);
455
456
1.22k
    if ((code = dict_float_param(pprivate, "ExpansionFactor", 0.06, &pdata1->ExpansionFactor)) < 0)
457
0
        return code;
458
1.22k
    if ((code = pdata1->FamilyBlues.count = dict_float_array_param(mem, pprivate, "FamilyBlues",
459
1.22k
                max_FamilyBlues * 2, &pdata1->FamilyBlues.values[0], NULL)) < 0)
460
0
        return code;
461
1.22k
    if (pdata1->FamilyBlues.count % 2 != 0)
462
0
        return_error(gs_error_rangecheck);
463
464
1.22k
    if ((code = pdata1->FamilyOtherBlues.count = dict_float_array_param(mem, pprivate, "FamilyOtherBlues",
465
1.22k
                max_FamilyOtherBlues * 2, &pdata1->FamilyOtherBlues.values[0], NULL)) < 0)
466
0
        return code;
467
1.22k
    if (pdata1->FamilyOtherBlues.count % 2 != 0)
468
0
        return_error(gs_error_rangecheck);
469
470
1.22k
    if ((code = dict_bool_param(pprivate, "ForceBold", false, &pdata1->ForceBold)) < 0)
471
0
        return code;
472
    /*
473
     * We've seen a few fonts with out-of-range LanguageGroup values;
474
     * if it weren't for this, the only legal values should be 0 or 1.
475
     */
476
1.22k
    if ((code = dict_int_param(pprivate, "LanguageGroup", min_int, max_int, 0, &pdata1->LanguageGroup)) < 0)
477
0
        return code;
478
1.22k
    if ((code = pdata1->OtherBlues.count = dict_float_array_param(mem, pprivate, "OtherBlues",
479
1.22k
                max_OtherBlues * 2, &pdata1->OtherBlues.values[0], NULL)) < 0)
480
0
        return code;
481
1.22k
    if (pdata1->OtherBlues.count % 2 != 0)
482
0
        return_error(gs_error_rangecheck);
483
484
1.22k
    if ((code = dict_bool_param(pprivate, "RndStemUp", true, &pdata1->RndStemUp)) < 0)
485
0
        return code;
486
1.22k
    if ((code = pdata1->StdHW.count = dict_float_array_check_param(mem, pprivate, "StdHW",
487
1.22k
                1, &pdata1->StdHW.values[0], NULL, 0, gs_error_rangecheck)) < 0)
488
0
        return code;
489
1.22k
    if ((code = pdata1->StdVW.count = dict_float_array_check_param(mem, pprivate, "StdVW",
490
1.22k
                1, &pdata1->StdVW.values[0], NULL, 0, gs_error_rangecheck)) < 0)
491
0
        return code;
492
1.22k
    if ((code = pdata1->StemSnapH.count = dict_float_array_param(mem, pprivate, "StemSnapH",
493
1.22k
                max_StemSnap, &pdata1->StemSnapH.values[0], NULL)) < 0)
494
0
        return code;
495
1.22k
    if ((code = pdata1->StemSnapV.count = dict_float_array_param(mem, pprivate, "StemSnapV",
496
1.22k
                max_StemSnap, &pdata1->StemSnapV.values[0], NULL)) < 0)
497
0
        return code;
498
    /* The WeightVector is in the font dictionary, not Private. */
499
1.22k
    if ((code = pdata1->WeightVector.count = dict_float_array_param(mem, op, "WeightVector",
500
1.22k
                max_WeightVector, pdata1->WeightVector.values, NULL)) < 0)
501
0
        return code;
502
503
1.22k
    if (pdata1->WeightVector.count > 0) {
504
0
        code = charstring_check_mm_params((ref *)op, pdata1->WeightVector.count);
505
0
        if (code < 0)
506
0
            return code;
507
0
    }
508
    /*
509
     * According to section 5.6 of the "Adobe Type 1 Font Format",
510
     * there is a requirement that BlueScale times the maximum
511
     * alignment zone height must be less than 1.  Some fonts
512
     * produced by Fontographer have ridiculously large BlueScale
513
     * values, so we force BlueScale back into range here.
514
     */
515
1.22k
    {
516
1.22k
        float max_zone_height = 1.0;
517
518
1.22k
        find_zone_height(&max_zone_height, pdata1->BlueValues.count, pdata1->BlueValues.values);
519
1.22k
        find_zone_height(&max_zone_height, pdata1->OtherBlues.count, pdata1->OtherBlues.values);
520
1.22k
        find_zone_height(&max_zone_height, pdata1->FamilyBlues.count, pdata1->FamilyBlues.values);
521
1.22k
        find_zone_height(&max_zone_height, pdata1->FamilyOtherBlues.count, pdata1->FamilyOtherBlues.values);
522
1.22k
        if (pdata1->BlueScale * max_zone_height > 1.0)
523
0
            pdata1->BlueScale = 1.0 / max_zone_height;
524
1.22k
    }
525
    /*
526
     * According to the same Adobe book, section 5.11, only values
527
     * 0 and 1 are allowed for LanguageGroup and we have encountered
528
     * fonts with other values. If the value is anything else, map it to 0
529
     * so that the remainder of the graphics library won't see an
530
     * unexpected value.
531
     */
532
1.22k
    if (pdata1->LanguageGroup > 1 || pdata1->LanguageGroup < 0)
533
0
        pdata1->LanguageGroup = 0;
534
535
    /* This is used only when determining if its possible to copy glyphs
536
     * between fonts. Currenly only by pdfwrite and friends. Rather than
537
     * check all the subrs (which we used to do) we hash tehm, store it
538
     * and check the hashes. Zero except when in use by pdfwrite..
539
     */
540
1.22k
    memset(&pdata1->hash_subrs, 0x00, 16);
541
1.22k
    return 0;
542
1.22k
}
543
544
/* Fill in a newly built CharString-based font or FDArray entry. */
545
int
546
charstring_font_init(gs_font_type1 *pfont, const charstring_font_refs_t *pfr,
547
                     const gs_type1_data *pdata1)
548
1.22k
{
549
1.22k
    font_data *pdata;
550
551
1.22k
    pdata = pfont_data(pfont);
552
1.22k
    pfont->data = *pdata1;
553
1.22k
    pfont->data.parent = NULL;
554
1.22k
    ref_assign(&pdata->u.type1.OtherSubrs, pfr->OtherSubrs);
555
1.22k
    ref_assign(&pdata->u.type1.Subrs, pfr->Subrs);
556
1.22k
    ref_assign(&pdata->u.type1.GlobalSubrs, pfr->GlobalSubrs);
557
1.22k
    pfont->data.procs = z1_data_procs;
558
1.22k
    pfont->data.proc_data = (char *)pdata;
559
1.22k
    pfont->procs.same_font = z1_same_font;
560
1.22k
    pfont->procs.glyph_info = z1_glyph_info;
561
1.22k
    pfont->procs.enumerate_glyph = z1_enumerate_glyph;
562
1.22k
    pfont->procs.glyph_outline = zchar1_glyph_outline;
563
1.22k
    return 0;
564
1.22k
}
565
566
/* Build a Type 1, Type 2, or Type 4 font. */
567
int
568
build_charstring_font(i_ctx_t *i_ctx_p, os_ptr op, build_proc_refs *pbuild,
569
                      font_type ftype, charstring_font_refs_t *pfr,
570
                      gs_type1_data *pdata1, build_font_options_t options)
571
1.22k
{
572
1.22k
    int code = charstring_font_params(imemory, op, pfr, pdata1);
573
1.22k
    gs_font_type1 *pfont;
574
575
1.22k
    if (code < 0)
576
0
        return code;
577
1.22k
    code = build_gs_primitive_font(i_ctx_p, op, (gs_font_base **)&pfont, ftype,
578
1.22k
                                   &st_gs_font_type1, pbuild, options);
579
1.22k
    if (code != 0)
580
0
        return code;
581
    /* This is a new font, fill it in. */
582
1.22k
    charstring_font_init(pfont, pfr, pdata1);
583
1.22k
    return define_gs_font(i_ctx_p, (gs_font *)pfont);
584
1.22k
}
585
586
/* ------ Operators ------ */
587
588
/* Build a Type 1 or Type 4 font. */
589
static int
590
buildfont1or4(i_ctx_t *i_ctx_p, os_ptr op, build_proc_refs * pbuild,
591
              font_type ftype, build_font_options_t options)
592
1.22k
{
593
1.22k
    charstring_font_refs_t refs;
594
1.22k
    int code;
595
1.22k
    gs_type1_data data1;
596
597
1.22k
    check_op(2);
598
1.22k
    code = charstring_font_get_refs(op, &refs);
599
1.22k
    if (code < 0)
600
0
        return code;
601
1.22k
    data1.interpret = gs_type1_interpret;
602
1.22k
    data1.subroutineNumberBias = 0;
603
1.22k
    data1.gsubrNumberBias = 0;
604
605
1.22k
    data1.lenIV = DEFAULT_LENIV_1;
606
1.22k
    return build_charstring_font(i_ctx_p, op, pbuild, ftype, &refs, &data1,
607
1.22k
                                 options);
608
1.22k
}
609
610
/* <string|name> <font_dict> .buildfont1 <string|name> <font> */
611
/* Build a type 1 (Adobe encrypted) font. */
612
static int
613
zbuildfont1(i_ctx_t *i_ctx_p)
614
1.22k
{
615
1.22k
    os_ptr op = osp;
616
1.22k
    build_proc_refs build;
617
1.22k
    int code = build_proc_name_refs(imemory, &build,
618
1.22k
                                    "%Type1BuildChar", "%Type1BuildGlyph");
619
620
1.22k
    if (code < 0)
621
0
        return code;
622
1.22k
    return buildfont1or4(i_ctx_p, op, &build, ft_encrypted,
623
1.22k
                         bf_notdef_required);
624
1.22k
}
625
626
/* <string|name> <font_dict> .buildfont4 <string|name> <font> */
627
/* Build a type 4 (disk-based Adobe encrypted) font. */
628
static int
629
zbuildfont4(i_ctx_t *i_ctx_p)
630
0
{
631
0
    os_ptr op = osp;
632
0
    build_proc_refs build;
633
0
    int code = build_gs_font_procs(op, &build);
634
635
0
    if (code < 0)
636
0
        return code;
637
0
    return buildfont1or4(i_ctx_p, op, &build, ft_disk_based, bf_options_none);
638
0
}
639
640
/* ------ Initialization procedure ------ */
641
642
const op_def zfont1_op_defs[] =
643
{
644
    {"2.buildfont1", zbuildfont1},
645
    {"2.buildfont4", zbuildfont4},
646
    op_def_end(0)
647
};
648
649
/* ------ Font procedures for Type 1 fonts ------ */
650
651
/* same_font procedure */
652
static bool
653
same_font_dict(const font_data *pdata, const font_data *podata,
654
               const char *key)
655
0
{
656
0
    ref *pvalue;
657
0
    bool present = dict_find_string(&pdata->dict, key, &pvalue) > 0;
658
0
    ref *povalue;
659
0
    bool opresent = dict_find_string(&podata->dict, key, &povalue) > 0;
660
0
    dict *pdict = (&(podata->dict))->value.pdict;
661
662
0
    return (present == opresent &&
663
0
            (present <= 0 || obj_eq(dict_mem(pdict), pvalue, povalue)));
664
0
}
665
static bool z1_check_data_procs_equal(const gs_type1_data_procs_t *p1, const gs_type1_data_procs_t *p2)
666
0
{
667
0
    if (p1->glyph_data != p2->glyph_data)
668
0
        return false;
669
0
    if (p1->subr_data != p2->subr_data)
670
0
        return false;
671
0
    if (p1->seac_data != p2->seac_data)
672
0
        return false;
673
0
    if (p1->push_values != p2->push_values)
674
0
        return false;
675
0
    if (p1->pop_value != p2->pop_value)
676
0
        return false;
677
0
    return true;
678
0
}
679
680
static int
681
z1_same_font(const gs_font *font, const gs_font *ofont, int mask)
682
0
{
683
0
    if (ofont->FontType != font->FontType)
684
0
        return 0;
685
0
    while (font->base != font)
686
0
        font = font->base;
687
0
    while (ofont->base != ofont)
688
0
        ofont = ofont->base;
689
0
    if (ofont == font)
690
0
        return mask;
691
0
    {
692
0
        int same = gs_base_same_font(font, ofont, mask);
693
0
        int check = mask & ~same;
694
0
        const gs_font_type1 *const pfont1 = (const gs_font_type1 *)font;
695
0
        const font_data *const pdata = pfont_data(pfont1);
696
0
        const gs_font_type1 *pofont1 = (const gs_font_type1 *)ofont;
697
0
        const font_data *const podata = pfont_data(pofont1);
698
0
        bool same_data_procs = z1_check_data_procs_equal(&pofont1->data.procs, &z1_data_procs);
699
700
701
0
        if ((check & (FONT_SAME_OUTLINES | FONT_SAME_METRICS)) && same_data_procs &&
702
0
            obj_eq(font->memory, &pdata->CharStrings, &podata->CharStrings) &&
703
            /*
704
             * We use same_font_dict for convenience: we know that
705
             * both fonts do have Private dictionaries.
706
             */
707
0
            same_font_dict(pdata, podata, "Private")
708
0
            )
709
0
            same |= FONT_SAME_OUTLINES;
710
711
0
        if ((check & FONT_SAME_METRICS) && (same & FONT_SAME_OUTLINES) && same_data_procs  &&
712
            /* Metrics may be affected by CDevProc, Metrics, Metrics2. */
713
0
            same_font_dict(pdata, podata, "Metrics") &&
714
0
            same_font_dict(pdata, podata, "Metrics2") &&
715
0
            same_font_dict(pdata, podata, "CDevProc")
716
0
            )
717
0
            same |= FONT_SAME_METRICS;
718
719
0
        if ((check & FONT_SAME_ENCODING) &&
720
0
            pofont1->procs.same_font == z1_same_font &&
721
0
            obj_eq(font->memory, &pdata->Encoding, &podata->Encoding)
722
0
            )
723
0
            same |= FONT_SAME_ENCODING;
724
725
0
        return same & mask;
726
0
    }
727
0
}