Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/xps/xpscff.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
/* XPS interpreter - cff font support */
18
19
#include "ghostxps.h"
20
21
0
#define CFF_ARGS_SIZE 48
22
23
/*
24
 * Big-endian memory accessor functions
25
 */
26
27
static inline int s16(byte *p)
28
0
{
29
0
    return (signed short)( (p[0] << 8) | p[1] );
30
0
}
31
32
static inline int u16(byte *p)
33
0
{
34
0
    return (p[0] << 8) | p[1];
35
0
}
36
37
static inline int u24(byte *p)
38
0
{
39
0
    return (p[0] << 16) | (p[1] << 8) | p[2];
40
0
}
41
42
static inline int u32(byte *p)
43
0
{
44
0
    return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
45
0
}
46
47
/*
48
 * OpenType Tables
49
 *
50
 * Required: cmap, head, hhea, hmtx, maxp, name, OS/2, post
51
 * TrueType: cvt, fpgm, glyf, loca, prep
52
 * Postscript: CFF, VORG
53
 * Typographic: BASE, GDEF, GPOS, GSUB, JSTF
54
 * Other: DSIG, gasp, hdmx, kern, LTSH, PCLT, VDMX, vhea, vmtx
55
 */
56
57
static byte * xps_count_cff_index(byte *p, byte *e, int *countp);
58
static byte * xps_find_cff_index(byte *p, byte *e, int idx, byte **pp, byte **ep);
59
60
static int subrbias(int count)
61
0
{
62
0
    return count < 1240 ? 107 : count < 33900 ? 1131 : 32768;
63
0
}
64
65
static int uofs(byte *p, int offsize)
66
0
{
67
0
    if (offsize == 1) return p[0];
68
0
    if (offsize == 2) return u16(p);
69
0
    if (offsize == 3) return u24(p);
70
0
    if (offsize == 4) return u32(p);
71
0
    return 0;
72
0
}
73
74
static byte *
75
xps_read_cff_real(byte *p, byte *e, float *val)
76
0
{
77
0
    char buf[64];
78
0
    char *txt = buf;
79
80
    /* b0 was 30 */
81
82
0
    while (txt < buf + (sizeof buf) - 4 && p < e)
83
0
    {
84
0
        int b, n;
85
86
0
        b = *p++;
87
88
0
        n = (b >> 4) & 0xf;
89
0
        if (n < 0xA) { *txt++ = n + '0'; }
90
0
        else if (n == 0xA) { *txt++ = '.'; }
91
0
        else if (n == 0xB) { *txt++ = 'E'; }
92
0
        else if (n == 0xC) { *txt++ = 'E'; *txt++ = '-'; }
93
0
        else if (n == 0xE) { *txt++ = '-'; }
94
0
        else if (n == 0xF) { break; }
95
96
0
        n = b & 0xf;
97
0
        if (n < 0xA) { *txt++ = n + '0'; }
98
0
        else if (n == 0xA) { *txt++ = '.'; }
99
0
        else if (n == 0xB) { *txt++ = 'E'; }
100
0
        else if (n == 0xC) { *txt++ = 'E'; *txt++ = '-'; }
101
0
        else if (n == 0xE) { *txt++ = '-'; }
102
0
        else if (n == 0xF) { break; }
103
0
    }
104
105
0
    *txt = 0;
106
107
0
    *val = atof(buf);
108
109
0
    return p;
110
0
}
111
112
static byte *
113
xps_read_cff_integer(byte *p, byte *e, int b0, int *val)
114
0
{
115
0
    int b1, b2, b3, b4;
116
117
0
    if (b0 == 28)
118
0
    {
119
0
        if (p + 2 > e)
120
0
        {
121
0
            gs_throw(-1, "corrupt dictionary (integer)");
122
0
            return 0;
123
0
        }
124
0
        b1 = *p++;
125
0
        b2 = *p++;
126
0
        *val = (b1 << 8) | b2;
127
0
    }
128
129
0
    else if (b0 == 29)
130
0
    {
131
0
        if (p + 4 > e)
132
0
        {
133
0
            gs_throw(-1, "corrupt dictionary (integer)");
134
0
            return 0;
135
0
        }
136
0
        b1 = *p++;
137
0
        b2 = *p++;
138
0
        b3 = *p++;
139
0
        b4 = *p++;
140
0
        *val = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
141
0
    }
142
143
0
    else if (b0 < 247)
144
0
    {
145
0
        *val = b0 - 139;
146
0
    }
147
148
0
    else if (b0 < 251)
149
0
    {
150
0
        if (p + 1 > e)
151
0
        {
152
0
            gs_throw(-1, "corrupt dictionary (integer)");
153
0
            return 0;
154
0
        }
155
0
        b1 = *p++;
156
0
        *val = (b0 - 247) * 256 + b1 + 108;
157
0
    }
158
159
0
    else
160
0
    {
161
0
        if (p + 1 > e)
162
0
        {
163
0
            gs_throw(-1, "corrupt dictionary (integer)");
164
0
            return 0;
165
0
        }
166
0
        b1 = *p++;
167
0
        *val = -(b0 - 251) * 256 - b1 - 108;
168
0
    }
169
170
0
    return p;
171
0
}
172
173
static int
174
xps_read_cff_dict(byte *p, byte *e, xps_font_t *font, gs_font_type1 *pt1, int depth)
175
0
{
176
0
    struct { int ival; float fval; } args[CFF_ARGS_SIZE];
177
0
    int offset;
178
0
    int b0, n;
179
180
0
    int privatelen = 0;
181
0
    int privateofs = 0;
182
183
0
    if (depth > 16)
184
0
        return gs_throw(-1, "too many nested dicts");
185
186
0
    memset(args, 0x00, sizeof(args));
187
188
0
    offset = p - font->cffdata;
189
190
0
    n = 0;
191
0
    while (p < e)
192
0
    {
193
0
        b0 = *p++;
194
195
0
        if (b0 < 22)
196
0
        {
197
0
            if (b0 == 12)
198
0
            {
199
0
                if (p + 1 > e)
200
0
                {
201
0
                    return gs_throw(-1, "corrupt dictionary (operator)");
202
0
                }
203
0
                b0 = 0x100 | *p++;
204
0
            }
205
206
            /* some CFF file offsets */
207
208
0
            if (b0 == 17)
209
0
            {
210
0
                if (args[0].ival < 0)
211
0
                    return gs_throw(-1, "corrupt cff file offset");
212
0
                font->charstrings = font->cffdata + args[0].ival;
213
0
            }
214
215
0
            if (b0 == 18)
216
0
            {
217
0
                if (args[0].ival < 0 || args[1].ival < 0)
218
0
                    return gs_throw(-1, "corrupt cff file offset");
219
0
                privatelen = args[0].ival;
220
0
                privateofs = args[1].ival;
221
0
                if ((font->cffdata + privateofs + privatelen) > font->cffend)
222
0
                    return gs_throw(-1, "corrupt cff file offset");
223
0
            }
224
225
0
            if (b0 == 19)
226
0
            {
227
0
                if (args[0].ival < 0)
228
0
                    return gs_throw(-1, "corrupt cff file offset");
229
0
                font->subrs = font->cffdata + offset + args[0].ival;
230
0
            }
231
232
0
            if (b0 == (256 | 36))
233
0
                gs_warn("cid cff fonts not supported yet");
234
0
            if (b0 == (256 | 37))
235
0
                gs_warn("cid cff fonts not supported yet");
236
237
            /* Type1 stuff that need to be set for the pt1 struct */
238
239
0
            if (b0 == (256 | 6))
240
0
            {
241
0
                if (args[0].ival == 1)
242
0
                {
243
0
                    pt1->data.interpret = gs_type1_interpret;
244
0
                    pt1->data.lenIV = -1; /* FIXME */
245
0
                }
246
0
            }
247
248
0
            if (b0 == (256 | 7))
249
0
            {
250
0
                pt1->FontMatrix.xx = args[0].fval;
251
0
                pt1->FontMatrix.xy = args[1].fval;
252
0
                pt1->FontMatrix.yx = args[2].fval;
253
0
                pt1->FontMatrix.yy = args[3].fval;
254
0
                pt1->FontMatrix.tx = args[4].fval;
255
0
                pt1->FontMatrix.ty = args[5].fval;
256
0
            }
257
258
0
            if (b0 == 5)
259
0
            {
260
0
                pt1->FontBBox.p.x = args[0].fval;
261
0
                pt1->FontBBox.p.y = args[1].fval;
262
0
                pt1->FontBBox.q.x = args[2].fval;
263
0
                pt1->FontBBox.q.y = args[3].fval;
264
0
            }
265
266
0
            if (b0 == 20)
267
0
                pt1->data.defaultWidthX = float2fixed(args[0].fval);
268
269
0
            if (b0 == 21)
270
0
                pt1->data.nominalWidthX = float2fixed(args[0].fval);
271
272
0
            if (b0 == (256 | 19))
273
0
                pt1->data.initialRandomSeed = args[0].ival;
274
275
            /* Monday morning blues */
276
#if 0
277
            if (b0 == 6)
278
            {
279
                pt1->data.BlueValues.count = n / 2;
280
                for (f = 0, i = 0; i < n; f += args[i].fval, i++)
281
                    pt1->data.BlueValues.values[i] = f;
282
            }
283
284
            if (b0 == 7)
285
            {
286
                pt1->data.OtherBlues.count = n / 2;
287
                for (f = 0, i = 0; i < n; f += args[i].fval, i++)
288
                    pt1->data.OtherBlues.values[i] = f;
289
            }
290
291
            if (b0 == 8)
292
            {
293
                pt1->data.FamilyBlues.count = n / 2;
294
                for (f = 0, i = 0; i < n; f += args[i].fval, i++)
295
                    pt1->data.FamilyBlues.values[i] = f;
296
            }
297
298
            if (b0 == 9)
299
            {
300
                pt1->data.FamilyOtherBlues.count = n / 2;
301
                for (f = 0, i = 0; i < n; f += args[i].fval, i++)
302
                    pt1->data.FamilyOtherBlues.values[i] = f;
303
            }
304
305
            if (b0 == 10)
306
            {
307
                pt1->data.StdHW.count = 1;
308
                pt1->data.StdHW.values[0] = args[0].fval;
309
            }
310
311
            if (b0 == 11)
312
            {
313
                pt1->data.StdVW.count = 1;
314
                pt1->data.StdVW.values[0] = args[0].fval;
315
            }
316
317
            if (b0 == (256 | 9))
318
                pt1->data.BlueScale = args[0].fval;
319
320
            if (b0 == (256 | 10))
321
                pt1->data.BlueShift = args[0].fval;
322
323
            if (b0 == (256 | 11))
324
                pt1->data.BlueFuzz = args[0].fval;
325
326
            if (b0 == (256 | 12))
327
            {
328
                pt1->data.StemSnapH.count = n;
329
                for (f = 0, i = 0; i < n; f += args[i].fval, i++)
330
                    pt1->data.StemSnapH.values[i] = f;
331
            }
332
333
            if (b0 == (256 | 13))
334
            {
335
                pt1->data.StemSnapV.count = n;
336
                for (f = 0, i = 0; i < n; f += args[i].fval, i++)
337
                    pt1->data.StemSnapV.values[i] = f;
338
            }
339
340
            if (b0 == (256 | 14))
341
                pt1->data.ForceBold = args[0].ival;
342
343
            if (b0 == (256 | 17))
344
                pt1->data.LanguageGroup = args[0].ival;
345
346
            if (b0 == (256 | 18))
347
                pt1->data.ExpansionFactor = args[0].fval;
348
349
#endif
350
351
0
            n = 0;
352
0
        }
353
354
0
        else
355
0
        {
356
0
            if (b0 == 30)
357
0
            {
358
0
                if (n >= CFF_ARGS_SIZE)
359
0
                    return gs_throw(-1, "overflow in cff dict");
360
0
                p = xps_read_cff_real(p, e, &args[n].fval);
361
0
                if (!p)
362
0
                    return gs_throw(-1, "corrupt dictionary operand");
363
0
                args[n].ival = (int) args[n].fval;
364
0
                n++;
365
0
            }
366
0
            else if (b0 == 28 || b0 == 29 || (b0 >= 32 && b0 <= 254))
367
0
            {
368
0
                if (n >= CFF_ARGS_SIZE)
369
0
                    return gs_throw(-1, "overflow in cff dict");
370
0
                p = xps_read_cff_integer(p, e, b0, &args[n].ival);
371
0
                if (!p)
372
0
                    return gs_throw(-1, "corrupt dictionary operand");
373
0
                args[n].fval = (float) args[n].ival;
374
0
                n++;
375
0
            }
376
0
            else
377
0
            {
378
0
                return gs_throw1(-1, "corrupt dictionary operand (b0 = %d)", b0);
379
0
            }
380
0
        }
381
0
    }
382
383
    /* recurse for the private dictionary */
384
0
    if (privatelen)
385
0
    {
386
0
        int code = xps_read_cff_dict(
387
0
                font->cffdata + privateofs,
388
0
                font->cffdata + privateofs + privatelen,
389
0
                font, pt1, depth+1);
390
0
        if (code < 0)
391
0
            return gs_rethrow(code, "cannot read private dictionary");
392
0
    }
393
394
0
    return 0;
395
0
}
396
397
/*
398
 * Get the number of items in an INDEX, and return
399
 * a pointer to the end of the INDEX or NULL on
400
 * failure.
401
 */
402
static byte *
403
xps_count_cff_index(byte *p, byte *e, int *countp)
404
0
{
405
0
    int count, offsize, last;
406
407
0
    if (p + 3 > e)
408
0
    {
409
0
        gs_throw(-1, "not enough data for index header");
410
0
        return 0;
411
0
    }
412
413
0
    count = u16(p); p += 2;
414
0
    *countp = count;
415
416
0
    if (count == 0)
417
0
        return p;
418
419
0
    offsize = *p++;
420
421
0
    if (offsize < 1 || offsize > 4)
422
0
    {
423
0
        gs_throw(-1, "corrupt index header");
424
0
        return 0;
425
0
    }
426
427
0
    if (p + count * offsize > e)
428
0
    {
429
0
        gs_throw(-1, "not enough data for index offset table");
430
0
        return 0;
431
0
    }
432
433
0
    p += count * offsize;
434
0
    last = uofs(p, offsize);
435
0
    if (last < 0 || p + last > e)
436
0
    {
437
0
        gs_throw(-1, "corrupt index header");
438
0
        return 0;
439
0
    }
440
441
0
    p += offsize;
442
0
    p --; /* stupid offsets */
443
444
0
    if (p + last > e)
445
0
    {
446
0
        gs_throw(-1, "not enough data for index data");
447
0
        return 0;
448
0
    }
449
450
0
    p += last;
451
452
0
    return p;
453
0
}
454
455
/*
456
 * Locate and store pointers to the data of an
457
 * item in the index that starts at 'p'.
458
 * Return pointer to the end of the index,
459
 * or NULL on failure.
460
 */
461
static byte *
462
xps_find_cff_index(byte *p, byte *e, int idx, byte **pp, byte **ep)
463
0
{
464
0
    int count, offsize, sofs, eofs, last;
465
466
0
    if (p == NULL)
467
0
        return 0;
468
469
0
    if (p + 3 > e)
470
0
    {
471
0
        gs_throw(-1, "not enough data for index header");
472
0
        return 0;
473
0
    }
474
475
0
    count = u16(p); p += 2;
476
0
    if (count == 0)
477
0
        return 0;
478
479
0
    offsize = *p++;
480
481
0
    if (offsize < 1 || offsize > 4)
482
0
    {
483
0
        gs_throw(-1, "corrupt index header");
484
0
        return 0;
485
0
    }
486
487
0
    if (p + count * offsize > e)
488
0
    {
489
0
        gs_throw(-1, "not enough data for index offset table");
490
0
        return 0;
491
0
    }
492
493
0
    if (idx < 0 || idx >= count)
494
0
    {
495
0
        gs_throw(-1, "tried to access non-existing index item");
496
0
        return 0;
497
0
    }
498
499
0
    sofs = uofs(p + idx * offsize, offsize);
500
0
    eofs = uofs(p + (idx + 1) * offsize, offsize);
501
0
    last = uofs(p + count * offsize, offsize);
502
503
0
    p += count * offsize;
504
0
    p += offsize;
505
0
    p --; /* stupid offsets */
506
507
0
    if (p + last > e)
508
0
    {
509
0
        gs_throw(-1, "not enough data for index data");
510
0
        return 0;
511
0
    }
512
513
0
    if (sofs < 0 || eofs < 0 || sofs > eofs || eofs > last)
514
0
    {
515
0
        gs_throw(-1, "corrupt index offset table");
516
0
        return 0;
517
0
    }
518
519
0
    *pp = p + sofs;
520
0
    *ep = p + eofs;
521
522
0
    return p + last;
523
0
}
524
525
/*
526
 * Scan the CFF file structure and extract important data.
527
 */
528
529
static int
530
xps_read_cff_file(xps_font_t *font, gs_font_type1 *pt1)
531
0
{
532
0
    byte *p = font->cffdata;
533
0
    byte *e = font->cffend;
534
0
    byte *dictp, *dicte;
535
0
    int ngsubrs;
536
0
    int nsubrs;
537
0
    int count;
538
0
    int code;
539
540
    /* CFF header */
541
0
    {
542
0
        int major, minor, hdrsize;
543
544
0
        if (p + 4 > e)
545
0
            return gs_throw(-1, "not enough data for header");
546
547
0
        major = *p++;
548
0
        minor = *p++;
549
0
        hdrsize = *p++;
550
0
        /*offsize = **/p++;
551
552
0
        if (major != 1 || minor != 0)
553
0
            return gs_throw(-1, "not a CFF 1.0 file");
554
555
0
        if (p + hdrsize - 4 > e)
556
0
            return gs_throw(-1, "not enough data for extended header");
557
0
    }
558
559
    /* Name INDEX */
560
0
    p = xps_count_cff_index(p, e, &count);
561
0
    if (!p)
562
0
        return gs_throw(-1, "cannot read name index");
563
0
    if (count != 1)
564
0
        return gs_throw(-1, "file did not contain exactly one font");
565
566
    /* Top Dict INDEX */
567
0
    p = xps_find_cff_index(p, e, 0, &dictp, &dicte);
568
0
    if (!p)
569
0
        return gs_throw(-1, "cannot read top dict index");
570
571
    /* String index */
572
0
    p = xps_count_cff_index(p, e, &count);
573
0
    if (!p)
574
0
        return gs_throw(-1, "cannot read string index");
575
576
    /* Global Subr INDEX */
577
0
    font->gsubrs = p;
578
0
    p = xps_count_cff_index(p, e, &ngsubrs);
579
0
    if (!p)
580
0
        return gs_throw(-1, "cannot read gsubr index");
581
582
    /* Read the top and private dictionaries */
583
0
    code = xps_read_cff_dict(dictp, dicte, font, pt1, 0);
584
0
    if (code < 0)
585
0
        return gs_rethrow(code, "cannot read top dictionary");
586
587
    /* Check the subrs index */
588
0
    nsubrs = 0;
589
0
    if (font->subrs)
590
0
    {
591
0
        p = xps_count_cff_index(font->subrs, e, &nsubrs);
592
0
        if (!p)
593
0
            return gs_rethrow(-1, "cannot read subrs index");
594
0
    }
595
596
    /* Check the charstrings index */
597
0
    if (font->charstrings)
598
0
    {
599
0
        p = xps_count_cff_index(font->charstrings, e, &count);
600
0
        if (!p)
601
0
            return gs_rethrow(-1, "cannot read charstrings index");
602
0
    }
603
604
0
    pt1->data.subroutineNumberBias = subrbias(nsubrs);
605
0
    pt1->data.gsubrNumberBias = subrbias(ngsubrs);
606
    /* nominal and defaultWidthX */
607
608
0
    return 0;
609
0
}
610
611
/*
612
 * Ghostscript font machinery callbacks.
613
 */
614
615
static gs_glyph
616
xps_post_callback_encode_char(gs_font *pfont, gs_char chr, gs_glyph_space_t spc)
617
0
{
618
0
    xps_font_t *xf = pfont->client_data;
619
0
    int value;
620
0
    value = xps_encode_font_char(xf, chr);
621
0
    if (value == 0)
622
0
        return GS_NO_GLYPH;
623
0
    return value;
624
0
}
625
626
static int
627
xps_post_callback_decode_glyph(gs_font *p42, gs_glyph glyph, int ch, ushort *unicode_return, unsigned int length)
628
0
{
629
0
    return 0;
630
0
}
631
632
static int
633
xps_post_callback_glyph_name(gs_font *pf, gs_glyph glyph, gs_const_string *pstr)
634
0
{
635
0
    dmprintf1(pf->memory, "asking for CFF glyph name %lu\n", (ulong)glyph);
636
0
    return -1;
637
0
}
638
639
static int
640
xps_post_callback_glyph_info(gs_font *font, gs_glyph glyph,
641
        const gs_matrix *pmat, int members, gs_glyph_info_t *info)
642
0
{
643
0
    dmprintf1(font->memory, "asking for CFF glyph info %lu\n", (ulong)glyph);
644
0
    return -1;
645
0
}
646
647
static int
648
xps_post_callback_glyph_outline(gs_font *font, int wmode, gs_glyph glyph,
649
        const gs_matrix *pmat, gx_path *ppath, double sbw[4])
650
0
{
651
0
    dmprintf1(font->memory, "asking for CFF glyph outline %lu\n", (ulong)glyph);
652
0
    return -1;
653
0
}
654
655
typedef struct gs_type1exec_state_s
656
{
657
    gs_type1_state cis;         /* must be first */
658
    /* i_ctx_t *i_ctx_p; */     /* so push/pop can access o-stack */
659
    double sbw[4];
660
    gs_rect char_bbox;
661
    /*
662
     * The following elements are only used locally to make the stack clean
663
     * for OtherSubrs: they don't need to be declared for the garbage
664
     * collector.
665
     */
666
    void * save_args[6];
667
    int num_args;
668
    bool AlignToPixels;
669
} gs_type1exec_state;
670
671
static int
672
xps_post_callback_glyph_data(gs_font_type1 * pfont, gs_glyph glyph, gs_glyph_data_t *pgd)
673
0
{
674
0
    xps_font_t *font = pfont->client_data;
675
0
    byte *s, *e;
676
0
    byte *p;
677
678
0
    p = xps_find_cff_index(font->charstrings, font->cffend, glyph, &s, &e);
679
0
    if (!p)
680
0
        return gs_rethrow(gs_error_rangecheck, "cannot find charstring");
681
682
0
    gs_glyph_data_from_string(pgd, s, e - s, NULL);
683
684
0
    return 0;
685
0
}
686
687
static int
688
xps_post_callback_subr_data(gs_font_type1 * pfont,
689
        int subr_num, bool global, gs_glyph_data_t *pgd)
690
0
{
691
0
    xps_font_t *font = pfont->client_data;
692
0
    byte *s, *e;
693
0
    byte *p;
694
695
0
    if (global)
696
0
    {
697
0
        p = xps_find_cff_index(font->gsubrs, font->cffend, subr_num, &s, &e);
698
0
        if (!p)
699
0
            return gs_rethrow(gs_error_rangecheck, "cannot find gsubr");
700
0
    }
701
0
    else
702
0
    {
703
0
        p = xps_find_cff_index(font->subrs, font->cffend, subr_num, &s, &e);
704
0
        if (!p)
705
0
            return gs_rethrow(gs_error_rangecheck, "cannot find subr");
706
0
    }
707
708
0
    gs_glyph_data_from_string(pgd, s, e - s, NULL);
709
710
0
    return 0;
711
0
}
712
713
static int
714
xps_post_callback_seac_data(gs_font_type1 * pfont, int ccode, gs_glyph * pglyph,
715
        gs_const_string *gstr, gs_glyph_data_t *pgd)
716
0
{
717
0
    return gs_throw(-1, "seac is deprecated in CFF fonts");
718
0
}
719
720
static int
721
xps_post_callback_push(void *callback_data, const fixed *values, int count)
722
0
{
723
0
    return gs_throw(-1, "push not implemented");
724
0
}
725
726
static int
727
xps_post_callback_pop(void *callback_data, fixed *value)
728
0
{
729
0
    return gs_throw(-1, "pop not implemented");
730
0
}
731
732
static int
733
xps_cff_append(gs_gstate *pgs, gs_font_type1 *pt1, gs_glyph glyph, int donthint)
734
0
{
735
0
    int code, value;
736
0
    gs_type1exec_state cxs;
737
0
    gs_glyph_data_t gd;
738
0
    gs_type1_state *const pcis = &cxs.cis;
739
0
    gs_glyph_data_t *pgd = &gd;
740
0
    double sbw[4];
741
0
    gs_matrix mtx;
742
743
    /* get charstring data */
744
0
    code = xps_post_callback_glyph_data(pt1, glyph, pgd);
745
0
    if (code < 0)
746
0
        return gs_rethrow(code, "cannot get glyph data");
747
748
0
    mtx = ctm_only(pgs);
749
0
    gs_matrix_scale(&mtx, 0.001, 0.001, &mtx);
750
0
    mtx.tx = 0;
751
0
    mtx.ty = 0;
752
0
    gs_matrix_fixed_from_matrix(&pgs->ctm, &mtx);
753
0
    pgs->flatness = 0;
754
755
0
    code = gs_type1_interp_init(&cxs.cis, pgs, pgs->path, NULL, NULL, donthint, 0, pt1);
756
0
    if (code < 0)
757
0
        return gs_throw(code, "cannot init type1 interpreter");
758
759
0
    gs_type1_set_callback_data(pcis, &cxs);
760
761
    /* TODO: check if this is set in the font dict
762
       gs_type1_set_lsb(pcis, &mpt);
763
       gs_type1_set_width(pcis, &mpt);
764
765
     ...
766
     */
767
0
    while (1)
768
0
    {
769
0
        code = pt1->data.interpret(pcis, pgd, &value);
770
0
        switch (code)
771
0
        {
772
0
        case type1_result_callothersubr: /* unknown OtherSubr */
773
0
            return_error(-15); /* can't handle it */
774
0
        case type1_result_sbw: /* [h]sbw, just continue */
775
0
            type1_cis_get_metrics(pcis, cxs.sbw);
776
0
            type1_cis_get_metrics(pcis, sbw);
777
0
            pgd = 0;
778
0
            break;
779
0
        case 0: /* all done */
780
0
            return 0;
781
0
        default: /* code < 0, error */
782
0
            return gs_throw(code, "cannot interpret type1 data");
783
0
        }
784
0
    }
785
0
}
786
787
static int
788
xps_post_callback_build_char(gs_show_enum *penum, gs_gstate *pgs,
789
        gs_font *pfont, gs_char chr, gs_glyph glyph)
790
0
{
791
0
    gs_font_type1 *pt1 = (gs_font_type1*)pfont;
792
0
    const gs_rect *pbbox;
793
0
    float w2[6];
794
0
    int code;
795
796
    /* get the metrics */
797
0
    w2[0] = 0;
798
0
    w2[1] = 1;
799
800
0
    pbbox = &pt1->FontBBox;
801
0
    w2[2] = pbbox->p.x * 0.001;
802
0
    w2[3] = pbbox->p.y * 0.001;
803
0
    w2[4] = pbbox->q.x * 0.001;
804
0
    w2[5] = pbbox->q.y * 0.001;
805
806
    /* Expand the bbox when stroking */
807
0
    if ( pfont->PaintType )
808
0
    {
809
0
        float expand = max(1.415, gs_currentmiterlimit(pgs)) * gs_currentlinewidth(pgs) / 2;
810
0
        w2[2] -= expand, w2[3] -= expand;
811
0
        w2[4] += expand, w2[5] += expand;
812
0
    }
813
814
0
    if ( (code = gs_moveto(pgs, 0.0, 0.0)) < 0 )
815
0
        return code;
816
817
0
    if ( (code = gs_setcachedevice(penum, pgs, w2)) < 0 )
818
0
        return code;
819
820
0
    code = xps_cff_append(pgs, pt1, glyph,
821
0
            gs_show_in_charpath(penum) != cpm_show);
822
0
    if (code < 0)
823
0
        return code;
824
825
0
    code = (pfont->PaintType ? gs_stroke(pgs) : gs_fill(pgs));
826
0
    if (code < 0)
827
0
        return code;
828
829
0
    return 0;
830
0
}
831
832
int
833
xps_init_postscript_font(xps_context_t *ctx, xps_font_t *font)
834
0
{
835
0
    gs_font_type1 *pt1;
836
0
    int cffofs;
837
0
    int cfflen;
838
0
    int cffend;
839
0
    int code;
840
841
    /* Find the CFF table and parse it to create a charstring based font */
842
    /* We don't need to support CFF files with multiple fonts */
843
    /* Find the VORG table for easier vertical metrics */
844
845
0
    cffofs = xps_find_sfnt_table(font, "CFF ", &cfflen);
846
0
    if (cffofs < 0)
847
0
        return gs_throw(-1, "cannot find CFF table");
848
849
    /* check the table is within the buffer and no integer overflow occurs */
850
0
    cffend = cffofs + cfflen;
851
0
    if (cffend < cffofs || cfflen < 0 || cffend > font->length)
852
0
        return gs_throw(-1, "corrupt CFF table location");
853
854
0
    font->cffdata = font->data + cffofs;
855
0
    font->cffend = font->data + cffend;
856
857
0
    font->gsubrs = 0;
858
0
    font->subrs = 0;
859
0
    font->charstrings = 0;
860
861
0
    pt1 = (void*) gs_alloc_struct(ctx->memory, gs_font_type1, &st_gs_font_type1, "xps_font type1");
862
0
    if (!pt1)
863
0
        return gs_throw(-1, "out of memory");
864
865
0
    font->font = (void*) pt1;
866
867
    /* Common to all fonts */
868
869
0
    pt1->next = 0;
870
0
    pt1->prev = 0;
871
0
    pt1->memory = ctx->memory;
872
873
0
    pt1->dir = ctx->fontdir; /* NB also set by gs_definefont later */
874
0
    pt1->base = font->font; /* NB also set by gs_definefont later */
875
0
    pt1->is_resource = false;
876
0
    gs_notify_init(&pt1->notify_list, gs_memory_stable(ctx->memory));
877
0
    pt1->id = gs_next_ids(ctx->memory, 1);
878
879
0
    pt1->client_data = font; /* that's us */
880
881
0
    gs_make_identity(&pt1->FontMatrix);
882
0
    gs_make_identity(&pt1->orig_FontMatrix);
883
884
0
    pt1->FontType = ft_encrypted2;
885
0
    pt1->BitmapWidths = true;
886
0
    pt1->ExactSize = fbit_use_outlines;
887
0
    pt1->InBetweenSize = fbit_use_outlines;
888
0
    pt1->TransformedChar = fbit_use_outlines;
889
0
    pt1->WMode = 0;
890
0
    pt1->PaintType = 0;
891
0
    pt1->StrokeWidth = 0;
892
893
0
    pt1->procs.define_font = gs_no_define_font;
894
0
    pt1->procs.make_font = gs_no_make_font;
895
0
    pt1->procs.font_info = gs_default_font_info;
896
0
    pt1->procs.same_font = gs_default_same_font;
897
0
    pt1->procs.encode_char = xps_post_callback_encode_char;
898
0
    pt1->procs.decode_glyph = xps_post_callback_decode_glyph;
899
0
    pt1->procs.enumerate_glyph = gs_no_enumerate_glyph;
900
0
    pt1->procs.glyph_info = xps_post_callback_glyph_info;
901
0
    pt1->procs.glyph_outline = xps_post_callback_glyph_outline;
902
0
    pt1->procs.glyph_name = xps_post_callback_glyph_name;
903
0
    pt1->procs.init_fstack = gs_default_init_fstack;
904
0
    pt1->procs.next_char_glyph = gs_default_next_char_glyph;
905
0
    pt1->procs.build_char = xps_post_callback_build_char;
906
907
0
    strcpy((char*)pt1->font_name.chars, "PostScriptFont");
908
0
    pt1->font_name.size = strlen((char*)pt1->font_name.chars);
909
910
0
    pt1->key_name.size = 0;
911
912
    /* Base font specific */
913
914
0
    pt1->FontBBox.p.x = 0; /* -0.5; */
915
0
    pt1->FontBBox.p.y = 0; /* -0.5; */
916
0
    pt1->FontBBox.q.x = 0; /* 1.5; */
917
0
    pt1->FontBBox.q.y = 0; /* 1.5; */
918
919
0
    uid_set_UniqueID(&pt1->UID, pt1->id);
920
921
0
    pt1->encoding_index = ENCODING_INDEX_UNKNOWN;
922
0
    pt1->nearest_encoding_index = ENCODING_INDEX_UNKNOWN;
923
924
0
    pt1->FAPI = 0;
925
0
    pt1->FAPI_font_data = 0;
926
927
    /* Type 1/2 specific */
928
    /* defaults from the CFF spec */
929
930
0
    pt1->data.procs.glyph_data = xps_post_callback_glyph_data;
931
0
    pt1->data.procs.subr_data = xps_post_callback_subr_data;
932
0
    pt1->data.procs.seac_data = xps_post_callback_seac_data;
933
0
    pt1->data.procs.push_values = xps_post_callback_push;
934
0
    pt1->data.procs.pop_value = xps_post_callback_pop;
935
936
0
    pt1->data.interpret = gs_type2_interpret;
937
0
    pt1->data.proc_data = font;
938
0
    pt1->data.parent = NULL;
939
0
    pt1->data.lenIV = -1; /* DEFAULT_LENIV_2 */
940
941
0
    pt1->data.subroutineNumberBias = 0;
942
0
    pt1->data.gsubrNumberBias = 0;
943
0
    pt1->data.initialRandomSeed = 0;
944
0
    pt1->data.defaultWidthX = 0;
945
0
    pt1->data.nominalWidthX = 0;
946
947
0
    pt1->data.BlueFuzz = 1;
948
0
    pt1->data.BlueScale = 0.039625f;
949
0
    pt1->data.BlueShift = 7;
950
0
    pt1->data.BlueValues.count = 0;
951
0
    pt1->data.ExpansionFactor = 0.06f;
952
0
    pt1->data.ForceBold = 0;
953
0
    pt1->data.FamilyBlues.count = 0;
954
0
    pt1->data.FamilyOtherBlues.count = 0;
955
0
    pt1->data.LanguageGroup = 0;
956
0
    pt1->data.OtherBlues.count = 0;
957
958
0
    pt1->data.RndStemUp = 0;
959
0
    memset(&pt1->data.StdHW, 0, sizeof(pt1->data.StdHW));
960
0
    memset(&pt1->data.StdVW, 0, sizeof(pt1->data.StdVW));
961
0
    memset(&pt1->data.StemSnapH, 0, sizeof(pt1->data.StemSnapH));
962
0
    memset(&pt1->data.StemSnapV, 0, sizeof(pt1->data.StemSnapH));
963
0
    memset(&pt1->data.WeightVector, 0, sizeof(pt1->data.WeightVector));
964
965
0
    code = xps_read_cff_file(font, pt1);
966
0
    if (code < 0)
967
0
    {
968
        /* TODO free pt1 here? */
969
0
        return gs_rethrow(code, "cannot read cff file structure");
970
0
    }
971
972
0
    if ((code = gs_definefont(ctx->fontdir, font->font)) < 0) {
973
0
        return(code);
974
0
    }
975
976
0
    code = xps_fapi_passfont (font->font, NULL, NULL, font->data, font->length);
977
0
    return code;
978
0
}