Coverage Report

Created: 2025-06-10 07:27

/src/ghostpdl/devices/vector/gdevpdtc.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-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
17
/* Composite and CID-based text processing for pdfwrite. */
18
#include "memory_.h"
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "gxfcmap.h"
22
#include "gxfont.h"
23
#include "gxfont0.h"
24
#include "gxfont0c.h"
25
#include "gzpath.h"
26
#include "gxchar.h"
27
#include "gdevpsf.h"
28
#include "gdevpdfx.h"
29
#include "gdevpdtx.h"
30
#include "gdevpdtd.h"
31
#include "gdevpdtf.h"
32
#include "gdevpdts.h"
33
#include "gdevpdtt.h"
34
35
#include "gximage.h"
36
#include "gxcpath.h"
37
/* ---------------- Non-CMap-based composite font ---------------- */
38
39
/*
40
 * Process a text string in a composite font with FMapType != 9 (CMap).
41
 */
42
int
43
process_composite_text(gs_text_enum_t *pte, void *vbuf, uint bsize)
44
0
{
45
0
    byte *const buf = vbuf;
46
0
    pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
47
0
    int code = 0;
48
0
    gs_string str;
49
0
    pdf_text_process_state_t text_state;
50
0
    pdf_text_enum_t curr, prev, out;
51
0
    gs_point total_width;
52
0
    const gs_matrix *psmat = 0;
53
0
    gs_font *prev_font = 0;
54
0
    gs_char chr, char_code = 0x0badf00d, space_char = GS_NO_CHAR;
55
0
    int buf_index = 0;
56
0
    bool return_width = (penum->text.operation & TEXT_RETURN_WIDTH);
57
0
    gx_path *path = gs_text_enum_path(penum);
58
59
0
    str.data = buf;
60
0
    if (return_width) {
61
0
        code = gx_path_current_point(path, &penum->origin);
62
0
        if (code < 0)
63
0
            return code;
64
0
    }
65
0
    if (pte->text.operation &
66
0
        (TEXT_FROM_ANY - (TEXT_FROM_STRING | TEXT_FROM_BYTES))
67
0
        )
68
0
        return_error(gs_error_rangecheck);
69
0
    if (pte->text.operation & TEXT_INTERVENE) {
70
        /* Not implemented. (PostScript doesn't even allow this case.) */
71
0
        return_error(gs_error_rangecheck);
72
0
    }
73
0
    total_width.x = total_width.y = 0;
74
0
    curr = *penum;
75
0
    prev = curr;
76
0
    out = curr;
77
0
    out.current_font = 0;
78
    /* Scan runs of characters in the same leaf font. */
79
0
    for ( ; ; ) {
80
0
        int font_code;
81
0
        gs_font *new_font = 0;
82
83
0
        gs_text_enum_copy_dynamic((gs_text_enum_t *)&out,
84
0
                                  (gs_text_enum_t *)&curr, false);
85
0
        for (;;) {
86
0
            gs_glyph glyph;
87
88
0
            gs_text_enum_copy_dynamic((gs_text_enum_t *)&prev,
89
0
                                      (gs_text_enum_t *)&curr, false);
90
0
            font_code = pte->orig_font->procs.next_char_glyph
91
0
                ((gs_text_enum_t *)&curr, &chr, &glyph);
92
            /*
93
             * We check for a font change by comparing the current
94
             * font, rather than testing the return code, because
95
             * it makes the control structure a little simpler.
96
             */
97
0
            switch (font_code) {
98
0
            case 0:   /* no font change */
99
0
            case 1:   /* font change */
100
0
                curr.returned.current_char = chr;
101
0
                char_code = gx_current_char((gs_text_enum_t *)&curr);
102
0
                new_font = curr.fstack.items[curr.fstack.depth].font;
103
0
                if (new_font != prev_font)
104
0
                    break;
105
0
                if (chr != (byte)chr) /* probably can't happen */
106
0
                    return_error(gs_error_rangecheck);
107
0
                if (buf_index >= bsize)
108
0
                    return_error(gs_error_unregistered); /* Must not happen. */
109
0
                buf[buf_index] = (byte)chr;
110
0
                buf_index++;
111
0
                prev_font = new_font;
112
0
                psmat = &curr.fstack.items[curr.fstack.depth - 1].font->FontMatrix;
113
0
                if ((pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) &&
114
0
                        pte->text.space.s_char == char_code)
115
0
                    space_char = chr;
116
0
                continue;
117
0
            case 2:   /* end of string */
118
0
                break;
119
0
            default:  /* error */
120
0
                return font_code;
121
0
            }
122
0
            break;
123
0
        }
124
0
        str.size = buf_index;
125
0
        if (buf_index) {
126
            /* buf_index == 0 is only possible the very first time. */
127
            /*
128
             * The FontMatrix of leaf descendant fonts is not updated
129
             * by scalefont.  Compute the effective FontMatrix now.
130
             */
131
0
            gs_matrix fmat;
132
133
            /* set up the base font : */
134
0
            out.fstack.depth = 0;
135
0
            out.fstack.items[out.fstack.depth].font = out.current_font = prev_font;
136
0
            pte->current_font = prev_font;
137
138
            /* Provide the decoded space character : */
139
0
            out.text.space.s_char = space_char;
140
141
0
            gs_matrix_multiply(&prev_font->FontMatrix, psmat, &fmat);
142
0
            out.index = 0; /* Note : we don't reset out.xy_index here. */
143
0
            code = pdf_process_string_aux(&out, &str, NULL, &fmat, &text_state);
144
0
            if (code < 0) {
145
0
                if (code == gs_error_undefined && new_font && new_font->FontType == ft_encrypted2)
146
                /* Caused by trying to make a CFF font resource for ps2write, which doesn't support CFF, abort now! */
147
0
      return_error(gs_error_invalidfont);
148
0
                return code;
149
0
            }
150
0
            curr.xy_index = out.xy_index; /* pdf_encode_process_string advanced it. */
151
0
            if (out.index < str.size) {
152
0
                gs_glyph glyph;
153
154
                /* Advance *pte exactly for out.index chars,
155
                   because above we stored bytes into buf. */
156
0
                while (out.index--)
157
0
                    pte->orig_font->procs.next_char_glyph(pte, &chr, &glyph);
158
0
                font_code = 2; /* force exiting the loop */
159
0
            } else {
160
                /* advance *pte past the current substring */
161
0
                gs_text_enum_copy_dynamic(pte, (gs_text_enum_t *)&prev, true);
162
0
            }
163
0
            pte->xy_index = out.xy_index;
164
0
            if (return_width) {
165
                /* This is silly, but its a consequence of the way pdf_process_string
166
                 * works. When we have TEXT_DO_NONE (stringwidth) we add the width of the
167
                 * glyph(s) to the enumerator 'returned.total_width' so we keep track
168
                 * of the total width as we go. However when we are returning the width
169
                 * but its NOT for a stringwidth, we set the enumerator 'retuerned'
170
                 * value to just the width of the glyph(s) processed. So when we are *not*
171
                 * handling a stringwidth we need to keep track of the total width
172
                 * ourselves. I'd have preferred to alter pdf_process_string, but that
173
                 * is used in many other places, and those places rely on this behaviour.
174
                 */
175
0
                if (pte->text.operation & TEXT_DO_NONE) {
176
0
                    pte->returned.total_width.x = total_width.x = out.returned.total_width.x;
177
0
                    pte->returned.total_width.y = total_width.y = out.returned.total_width.y;
178
0
                } else {
179
0
                    pte->returned.total_width.x = total_width.x +=
180
0
                        out.returned.total_width.x;
181
0
                    pte->returned.total_width.y = total_width.y +=
182
0
                        out.returned.total_width.y;
183
0
                }
184
0
            }
185
0
            pdf_text_release_cgp(penum);
186
0
        }
187
0
        if (font_code == 2)
188
0
            break;
189
0
        buf[0] = (byte)chr;
190
0
        buf_index = 1;
191
0
        space_char = ((pte->text.operation & TEXT_ADD_TO_SPACE_WIDTH) &&
192
0
                      pte->text.space.s_char == char_code ? chr : ~0);
193
0
        psmat = &curr.fstack.items[curr.fstack.depth - 1].font->FontMatrix;
194
0
        prev_font = new_font;
195
0
    }
196
0
    if (!return_width)
197
0
        return 0;
198
0
    return pdf_shift_text_currentpoint(penum, &total_width);
199
0
}
200
201
/* ---------------- CMap-based composite font ---------------- */
202
203
/*
204
 * Process a text string in a composite font with FMapType == 9 (CMap).
205
 */
206
static const char *const standard_cmap_names[] = {
207
    /* The following were added in PDF 1.5. */
208
209
    "UniGB-UTF16-H", "UniGB-UTF16-V",
210
211
    "GBKp-EUC-H", "GBKp-EUC-V",
212
    "HKscs-B5-H", "HKscs-B5-V",
213
    "UniCNS-UTF16-H", "UniCNS-UTF16-V",
214
    "UniJIS-UTF16-H", "UniJIS-UTF16-V",
215
    "UniKS-UTF16-H", "UniKS-UTF16-V",
216
0
#define END_PDF15_CMAP_NAMES_INDEX 12
217
    /* The following were added in PDF 1.4. */
218
    "GBKp-EUC-H", "GBKp-EUC-V",
219
    "GBK2K-H", "GBK2K-V",
220
    "HKscs-B5-H", "HKscs-B5-V",
221
0
#define END_PDF14_CMAP_NAMES_INDEX 18
222
    /* The following were added in PDF 1.3. */
223
224
    "GBpc-EUC-V",
225
    "GBK-EUC-H", "GBK-EUC-V",
226
    "UniGB-UCS2-H", "UniGB-UCS2-V",
227
228
    "ETenms-B5-H", "ETenms-B5-V",
229
230
    "UniCNS-UCS2-H", "UniCNS-UCS2-V",
231
232
    "90msp-RKSJ-H", "90msp-RKSJ-V",
233
    "EUC-H", "EUC-V",
234
    "UniJIS-UCS2-H", "UniJIS-UCS2-V",
235
    "UniJIS-UCS2-HW-H", "UniJIS-UCS2-HW-V",
236
237
    "KSCms-UHC-HW-H", "KSCms-UHC-HW-V",
238
    "UniKS-UCS2-H", "UniKS-UCS2-V",
239
240
0
#define END_PDF13_CMAP_NAMES_INDEX 39
241
    /* The following were added in PDF 1.2. */
242
243
    "GB-EUC-H", "GB-EUC-V",
244
    "GBpc-EUC-H",
245
246
    "B5pc-H", "B5pc-V",
247
    "ETen-B5-H", "ETen-B5-V",
248
    "CNS-EUC-H", "CNS-EUC-V",
249
250
    "83pv-RKSJ-H",
251
    "90ms-RKSJ-H", "90ms-RKSJ-V",
252
    "90pv-RKSJ-H",
253
    "Add-RKSJ-H", "Add-RKSJ-V",
254
    "Ext-RKSJ-H", "Ext-RKSJ-V",
255
    "H", "V",
256
257
    "KSC-EUC-H", "KSC-EUC-V",
258
    "KSCms-UHC-H", "KSCms-UHC-V",
259
    "KSCpc-EUC-H",
260
261
    "Identity-H", "Identity-V",
262
263
    0
264
};
265
266
static int
267
attach_cmap_resource(gx_device_pdf *pdev, pdf_font_resource_t *pdfont,
268
                const gs_cmap_t *pcmap, int font_index_only)
269
1.32k
{
270
1.32k
    const char *const *pcmn =
271
1.32k
        standard_cmap_names +
272
1.32k
        (pdev->CompatibilityLevel < 1.3 ? END_PDF13_CMAP_NAMES_INDEX :
273
1.32k
         pdev->CompatibilityLevel < 1.4 ? END_PDF14_CMAP_NAMES_INDEX :
274
1.32k
         pdev->CompatibilityLevel < 1.5 ? END_PDF15_CMAP_NAMES_INDEX : 0);
275
1.32k
    bool is_identity = false;
276
1.32k
    pdf_resource_t *pcmres = 0; /* CMap */
277
1.32k
    int code;
278
279
    /* Make sure cmap names is properly initialised. Silences Coverity warning */
280
1.32k
    if (!pcmn)
281
0
        return_error(gs_error_unknownerror);
282
283
    /*
284
     * If the CMap isn't standard, write it out if necessary.
285
     */
286
84.2k
    for (; *pcmn != 0; ++pcmn)
287
84.1k
        if (pcmap->CMapName.size == strlen(*pcmn) &&
288
84.1k
            !memcmp(*pcmn, pcmap->CMapName.data, pcmap->CMapName.size))
289
1.26k
            break;
290
291
    /* For PDF/A we need to write out all non-identity CMaps
292
     * first force the identity check.
293
     */
294
1.32k
    if (*pcmn == 0 || pdev->PDFA != 0) {
295
        /*
296
         * PScript5.dll Version 5.2 creates identity CMaps with
297
         * instandard name. Check this specially here
298
         * and later replace with a standard name.
299
         * This is a temporary fix for SF bug #615994 "CMAP is corrupt".
300
         */
301
69
        is_identity = gs_cmap_is_identity(pcmap, font_index_only);
302
69
    }
303
    /* If the CMap is non-standard, or we are producing PDF/A, and its not
304
     * an Identity CMap, then we need to emit it.
305
     */
306
1.32k
    if ((*pcmn == 0  || pdev->PDFA != 0) && !is_identity) {   /* not standard */
307
60
        pcmres = pdf_find_resource_by_gs_id(pdev, resourceCMap, pcmap->id + font_index_only);
308
60
        if (pcmres == 0) {
309
            /* Create and write the CMap object. */
310
60
            code = pdf_cmap_alloc(pdev, pcmap, &pcmres, font_index_only);
311
60
            if (code < 0)
312
0
                return code;
313
60
        }
314
60
    }
315
1.32k
    if (pcmap->from_Unicode) {
316
0
        gs_cmap_ranges_enum_t renum;
317
318
0
        gs_cmap_ranges_enum_init(pcmap, &renum);
319
0
        if (gs_cmap_enum_next_range(&renum) == 0 && renum.range.size == 2 &&
320
0
            gs_cmap_enum_next_range(&renum) == 1) {
321
            /*
322
             * Exactly one code space range, of size 2.  Add an identity
323
             * ToUnicode CMap.
324
             */
325
0
            if (!pdev->Identity_ToUnicode_CMaps[pcmap->WMode]) {
326
                /* Create and write an identity ToUnicode CMap now. */
327
0
                gs_cmap_t *pidcmap;
328
329
0
                code = gs_cmap_create_char_identity(&pidcmap, 2, pcmap->WMode,
330
0
                                                    pdev->memory);
331
0
                if (code < 0)
332
0
                    return code;
333
0
                pidcmap->CMapType = 2;  /* per PDF Reference */
334
0
                pidcmap->ToUnicode = true;
335
0
                code = pdf_cmap_alloc(pdev, pidcmap,
336
0
                                &pdev->Identity_ToUnicode_CMaps[pcmap->WMode], -1);
337
0
                if (code < 0)
338
0
                    return code;
339
0
            }
340
0
            pdfont->res_ToUnicode = pdev->Identity_ToUnicode_CMaps[pcmap->WMode];
341
0
        }
342
0
    }
343
1.32k
    if (pcmres || is_identity) {
344
69
        if (pdfont->u.type0.CMapName_data == NULL || pcmap->CMapName.size != pdfont->u.type0.CMapName_size ||
345
69
            memcmp(pdfont->u.type0.CMapName_data, pcmap->CMapName.data, pcmap->CMapName.size))
346
0
        {
347
0
            byte *chars = gs_alloc_bytes(pdev->pdf_memory->non_gc_memory, pcmap->CMapName.size,
348
0
                                          "pdf_font_resource_t(CMapName)");
349
350
0
            if (chars == 0)
351
0
                return_error(gs_error_VMerror);
352
0
            memcpy(chars, pcmap->CMapName.data, pcmap->CMapName.size);
353
0
            if (pdfont->u.type0.CMapName_data != NULL)
354
0
                gs_free_object(pdev->pdf_memory->non_gc_memory, pdfont->u.type0.CMapName_data, "rewriting CMapName");
355
0
            pdfont->u.type0.CMapName_data = chars;
356
0
            pdfont->u.type0.CMapName_size = pcmap->CMapName.size;
357
0
        }
358
69
        if (is_identity)
359
9
            strcpy(pdfont->u.type0.Encoding_name,
360
9
                    (pcmap->WMode ? "/Identity-V" : "/Identity-H"));
361
60
        else
362
60
            gs_snprintf(pdfont->u.type0.Encoding_name, sizeof(pdfont->u.type0.Encoding_name),
363
60
                        "%"PRId64" 0 R", pdf_resource_id(pcmres));
364
1.26k
    } else {
365
1.26k
        uint size = 0;
366
367
1.26k
        if (!*pcmn)
368
            /* Should not be possible, if *pcmn is NULL then either
369
             * is_identity is true or we create pcmres.
370
             */
371
0
            return_error(gs_error_invalidfont);
372
373
1.26k
        size = strlen(*pcmn);
374
1.26k
        if (pdfont->u.type0.CMapName_data == NULL || size != pdfont->u.type0.CMapName_size ||
375
1.26k
            memcmp(pdfont->u.type0.CMapName_data, *pcmn, size) != 0)
376
0
        {
377
0
            byte *chars = gs_alloc_bytes(pdev->pdf_memory->non_gc_memory, size, "pdf_font_resource_t(CMapName)");
378
0
            if (chars == 0)
379
0
                return_error(gs_error_VMerror);
380
381
0
            memcpy(chars, *pcmn, size);
382
383
0
            if (pdfont->u.type0.CMapName_data != NULL)
384
0
                gs_free_object(pdev->pdf_memory->non_gc_memory, pdfont->u.type0.CMapName_data, "rewriting CMapName");
385
0
            pdfont->u.type0.CMapName_data = chars;
386
0
            pdfont->u.type0.CMapName_size = size;
387
0
        }
388
389
1.26k
        gs_snprintf(pdfont->u.type0.Encoding_name, sizeof(pdfont->u.type0.Encoding_name), "/%s", *pcmn);
390
1.26k
        pdfont->u.type0.cmap_is_standard = true;
391
1.26k
    }
392
1.32k
    pdfont->u.type0.WMode = pcmap->WMode;
393
1.32k
    return 0;
394
1.32k
}
395
396
static int estimate_fontbbox(pdf_text_enum_t *pte, gs_font_base *font,
397
                          const gs_matrix *pfmat,
398
                          gs_rect *text_bbox)
399
0
{
400
0
    gs_matrix m;
401
0
    gs_point p0, p1, p2, p3;
402
403
0
    if (font->FontBBox.p.x == font->FontBBox.q.x ||
404
0
        font->FontBBox.p.y == font->FontBBox.q.y)
405
0
        return_error(gs_error_undefined);
406
0
    if (pfmat == 0)
407
0
        pfmat = &font->FontMatrix;
408
0
    m = ctm_only(pte->pgs);
409
0
    m.tx = fixed2float(pte->origin.x);
410
0
    m.ty = fixed2float(pte->origin.y);
411
0
    gs_matrix_multiply(pfmat, &m, &m);
412
413
0
    gs_point_transform(font->FontBBox.p.x, font->FontBBox.p.y, &m, &p0);
414
0
    gs_point_transform(font->FontBBox.p.x, font->FontBBox.q.y, &m, &p1);
415
0
    gs_point_transform(font->FontBBox.q.x, font->FontBBox.p.y, &m, &p2);
416
0
    gs_point_transform(font->FontBBox.q.x, font->FontBBox.q.y, &m, &p3);
417
0
    text_bbox->p.x = min(min(p0.x, p1.x), min(p1.x, p2.x));
418
0
    text_bbox->p.y = min(min(p0.y, p1.y), min(p1.y, p2.y));
419
0
    text_bbox->q.x = max(max(p0.x, p1.x), max(p1.x, p2.x));
420
0
    text_bbox->q.y = max(max(p0.y, p1.y), max(p1.y, p2.y));
421
422
0
    return 0;
423
0
}
424
425
/* Record widths and CID => GID mappings. */
426
static int
427
scan_cmap_text(pdf_text_enum_t *pte, void *vbuf)
428
364k
{
429
364k
    gx_device_pdf *pdev = (gx_device_pdf *)pte->dev;
430
    /* gs_font_type0 *const font = (gs_font_type0 *)pte->current_font;*/ /* Type 0, fmap_CMap */
431
364k
    gs_font_type0 *const font = (gs_font_type0 *)pte->orig_font; /* Type 0, fmap_CMap */
432
    /* Not sure. Changed for CDevProc callout. Was pte->current_font */
433
364k
    gs_text_enum_t scan = *(gs_text_enum_t *)pte;
434
364k
    int wmode = font->WMode == 0 ? 0 : 1, code, rcode = 0;
435
364k
    pdf_font_resource_t *pdsubf0 = NULL;
436
364k
    gs_font *subfont0 = NULL, *saved_subfont = NULL;
437
364k
    uint index = scan.index, xy_index = scan.xy_index, start_index = index;
438
364k
    uint font_index0 = 0x7badf00d;
439
364k
    bool done = false;
440
364k
    pdf_char_glyph_pairs_t p;
441
364k
    gs_glyph *type1_glyphs = (gs_glyph *)vbuf;
442
364k
    int num_type1_glyphs = 0;
443
444
364k
    p.num_all_chars = 1;
445
364k
    p.num_unused_chars = 1;
446
364k
    p.unused_offset = 0;
447
364k
    pte->returned.total_width.x = pte->returned.total_width.y = 0;;
448
364k
    for (;;) {
449
364k
        uint break_index, break_xy_index;
450
364k
        uint font_index = 0x7badf00d;
451
364k
        gs_const_string str;
452
364k
        pdf_text_process_state_t text_state;
453
364k
        pdf_font_resource_t *pdsubf = NULL;
454
364k
        gs_font *subfont = NULL;
455
364k
        gs_point wxy;
456
364k
        bool font_change = 0;
457
364k
        gx_path *path = gs_text_enum_path(pte);
458
459
364k
        code = gx_path_current_point(path, &pte->origin);
460
364k
        if (code < 0)
461
0
            return code;
462
642k
        do {
463
642k
            gs_char chr;
464
642k
            gs_glyph glyph;
465
642k
            pdf_font_descriptor_t *pfd;
466
642k
            byte *glyph_usage;
467
642k
            double *real_widths, *w, *v, *w0;
468
642k
            int char_cache_size, width_cache_size;
469
642k
            gs_char cid;
470
471
642k
            break_index = scan.index;
472
642k
            break_xy_index = scan.xy_index;
473
642k
            code = font->procs.next_char_glyph(&scan, &chr, &glyph);
474
642k
            if (code == 2) {   /* end of string */
475
114k
                if (subfont == NULL)
476
153
                    subfont = scan.fstack.items[scan.fstack.depth].font;
477
114k
                done = true;
478
114k
                break;
479
114k
            }
480
528k
            if (code < 0)
481
3
                return code;
482
528k
            subfont = scan.fstack.items[scan.fstack.depth].font;
483
528k
            font_index = scan.fstack.items[scan.fstack.depth - 1].index;
484
528k
            scan.xy_index++;
485
528k
            if (glyph == GS_NO_GLYPH)
486
0
                glyph = GS_MIN_CID_GLYPH;
487
528k
            cid = glyph - GS_MIN_CID_GLYPH;
488
528k
            switch (subfont->FontType) {
489
0
                case ft_encrypted:
490
0
                case ft_encrypted2:{
491
0
                    if (glyph == GS_MIN_CID_GLYPH) {
492
0
                        glyph = subfont->procs.encode_char(subfont, chr, GLYPH_SPACE_NAME);
493
0
                    }
494
0
                    type1_glyphs[num_type1_glyphs] = glyph;
495
0
                    num_type1_glyphs++;
496
0
                    break;
497
0
                }
498
11.4k
                case ft_CID_encrypted:
499
528k
                case ft_CID_TrueType: {
500
528k
                    p.s[0].glyph = glyph;
501
528k
                    p.s[0].chr = cid;
502
528k
                    code = pdf_obtain_cidfont_resource(pdev, subfont, &pdsubf, &p);
503
528k
                    if (code < 0)
504
248k
                        return code;
505
279k
                    break;
506
528k
                }
507
279k
                case ft_user_defined:
508
0
                case ft_PDF_user_defined:
509
0
                {
510
0
                    gs_string str1;
511
512
0
                    str1.data = NULL;
513
0
                    str1.size = 0;
514
0
                    pte->current_font = subfont;
515
0
                    code = pdf_obtain_font_resource(pte, &str1, &pdsubf);
516
0
                    if (code < 0)
517
0
                        return code;
518
0
                    cid = pdf_find_glyph(pdsubf, glyph);
519
0
                    if (cid == GS_NO_CHAR) {
520
0
                        code = pdf_make_font3_resource(pdev, subfont, &pdsubf);
521
0
                        if (code < 0)
522
0
                            return code;
523
0
                        code = pdf_attach_font_resource(pdev, subfont, pdsubf);
524
0
                        if (code < 0)
525
0
                            return code;
526
0
                        cid = 0;
527
0
                    }
528
0
                    break;
529
0
                }
530
0
                default:
531
                    /* An unsupported case, fall back to default implementation. */
532
0
                    return_error(gs_error_rangecheck);
533
528k
            }
534
279k
            code = pdf_attached_font_resource(pdev, (gs_font *)subfont, &pdsubf,
535
279k
                                       &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
536
279k
            if (code < 0)
537
0
                return code;
538
279k
            if (break_index > start_index && pdev->charproc_just_accumulated)
539
0
                break;
540
279k
            if ((subfont->FontType == ft_user_defined || subfont->FontType == ft_PDF_user_defined )&&
541
279k
                (break_index > start_index || !pdev->charproc_just_accumulated) &&
542
279k
                !(pdsubf->u.simple.s.type3.cached[cid >> 3] & (0x80 >> (cid & 7)))) {
543
0
                if (subfont0 && subfont0->FontType != ft_user_defined && subfont0->FontType != ft_PDF_user_defined)
544
                    /* This is hacky. By pretending to be in a type 3 font doing a charpath we force
545
                     * text handling to fall right back to bitmap glyphs. This is because we can't handle
546
                     * CIDFonts with mixed type 1/3 descendants. Ugly but it produces correct output for
547
                     * what is after all a dumb setup.
548
                     */
549
0
                    pdev->type3charpath = 1;
550
0
                pte->current_font = subfont;
551
0
                return_error(gs_error_undefined);
552
0
            }
553
279k
            if (subfont->FontType == ft_encrypted || subfont->FontType == ft_encrypted2) {
554
0
                font_change = (subfont != subfont0 && subfont0 != NULL);
555
0
                if (font_change) {
556
0
                    saved_subfont = subfont;
557
0
                    subfont = subfont0;
558
0
                    num_type1_glyphs--;
559
0
                }
560
0
            } else
561
279k
                font_change = (pdsubf != pdsubf0 && pdsubf0 != NULL);
562
279k
            if (!font_change) {
563
279k
                pdsubf0 = pdsubf;
564
279k
                font_index0 = font_index;
565
279k
                subfont0 = subfont;
566
279k
            }
567
279k
            if (subfont->FontType != ft_encrypted && subfont->FontType != ft_encrypted2) {
568
279k
                pfd = pdsubf->FontDescriptor;
569
279k
                code = pdf_resize_resource_arrays(pdev, pdsubf, cid + 1);
570
279k
                if (code < 0)
571
2
                    return code;
572
279k
                if (subfont->FontType == ft_CID_encrypted || subfont->FontType == ft_CID_TrueType) {
573
279k
                    if (cid >=width_cache_size) {
574
                        /* fixme: we add the CID=0 glyph as CID=cid glyph to the output font.
575
                           Really it must not add and leave the CID undefined. */
576
3.68k
                        cid = 0; /* notdef. */
577
3.68k
                    }
578
279k
                }
579
279k
                if (cid >= char_cache_size || cid >= width_cache_size)
580
0
                    return_error(gs_error_unregistered); /* Must not happen */
581
279k
                if (pdsubf->FontType == ft_user_defined  || pdsubf->FontType == ft_PDF_user_defined  || pdsubf->FontType == ft_encrypted ||
582
279k
                                pdsubf->FontType == ft_encrypted2) {
583
279k
                } else {
584
279k
                    pdf_font_resource_t *pdfont;
585
279k
                    bool notdef_subst = false;
586
587
279k
                    code = pdf_obtain_cidfont_widths_arrays(pdev, pdsubf, wmode, &w, &w0, &v);
588
279k
                    if (code < 0)
589
0
                        return code;
590
279k
                    code = pdf_obtain_parent_type0_font_resource(pdev, pdsubf, font_index,
591
279k
                        &font->data.CMap->CMapName, &pdfont);
592
279k
                    if (code < 0)
593
0
                        return code;
594
279k
                    if (pdf_is_CID_font(subfont)) {
595
                        /* Some Pscript5 output has non-identity mappings between character code and CID
596
                         * and the GlyphNames2Unicode dictionary uses character codes, not glyph names. So
597
                         * if we detect ths condition we cheat and claim not to be a CIDFont, so that the
598
                         * decode_glyph procedure can use the character code to look up the GlyphNames2Unicode
599
                         * dictionary. See bugs #696021, #688768 and #687954 for examples of the various ways
600
                         * this code can be exercised.
601
                         */
602
279k
                        if (chr == glyph - GS_MIN_CID_GLYPH)
603
273k
                            code = subfont->procs.decode_glyph((gs_font *)subfont, glyph, -1, NULL, 0);
604
6.07k
                        else
605
6.07k
                            code = subfont->procs.decode_glyph((gs_font *)subfont, glyph, chr, NULL, 0);
606
279k
                        if (code != 0)
607
                            /* Since PScript5.dll creates GlyphNames2Unicode with character codes
608
                               instead CIDs, and with the WinCharSetFFFF-H2 CMap
609
                               character codes appears different than CIDs (Bug 687954),
610
                               pass the character code intead the CID. */
611
896
                            code = pdf_add_ToUnicode(pdev, subfont, pdfont,
612
896
                                chr + GS_MIN_CID_GLYPH, chr, NULL);
613
278k
                        else {
614
                            /* If we interpret a PDF document, ToUnicode
615
                               CMap may be attached to the Type 0 font. */
616
278k
                            code = pdf_add_ToUnicode(pdev, pte->orig_font, pdfont,
617
278k
                                chr + GS_MIN_CID_GLYPH, chr, NULL);
618
278k
                        }
619
279k
                    }
620
0
                    else
621
0
                        code = pdf_add_ToUnicode(pdev, subfont, pdfont, glyph, cid, NULL);
622
279k
                    if (code < 0)
623
0
                        return code;
624
                    /*  We can't check pdsubf->used[cid >> 3] here,
625
                        because it mixed data for different values of WMode.
626
                        Perhaps pdf_font_used_glyph returns fast with reused glyphs.
627
                     */
628
279k
                    code = pdf_font_used_glyph(pfd, glyph, (gs_font_base *)subfont);
629
279k
                    if (code == gs_error_rangecheck) {
630
4.07k
                        if (!(pdsubf->used[cid >> 3] & (0x80 >> (cid & 7)))) {
631
403
                            char buf[gs_font_name_max + 1];
632
403
                            int l = min(sizeof(buf) - 1, subfont->font_name.size);
633
634
403
                            memcpy(buf, subfont->font_name.chars, l);
635
403
                            buf[l] = 0;
636
403
                            emprintf3(pdev->memory,
637
403
                                      "Missing glyph CID=%d, glyph=%04x in the font %s . The output PDF may fail with some viewers.\n",
638
403
                                      (int)cid,
639
403
                                      (unsigned int)(glyph - GS_MIN_CID_GLYPH),
640
403
                                      buf);
641
403
                            pdsubf->used[cid >> 3] |= 0x80 >> (cid & 7);
642
403
                            if (pdev->PDFA != 0) {
643
0
                                switch (pdev->PDFACompatibilityPolicy) {
644
                                    /* Default behaviour matches Adobe Acrobat, warn and continue,
645
                                     * output file will not be PDF/A compliant
646
                                     */
647
0
                                    case 0:
648
0
                                    case 1:
649
0
                                    case 3:
650
0
                                        emprintf(pdev->memory,
651
0
                                             "All used glyphs mst be present in fonts for PDF/A, reverting to normal PDF output.\n");
652
0
                                        pdev->AbortPDFAX = true;
653
0
                                        pdev->PDFA = 0;
654
0
                                        break;
655
0
                                    case 2:
656
0
                                        emprintf(pdev->memory,
657
0
                                             "All used glyphs mst be present in fonts for PDF/A, aborting conversion.\n");
658
0
                                        return_error(gs_error_invalidfont);
659
0
                                        break;
660
0
                                    default:
661
0
                                        emprintf(pdev->memory,
662
0
                                             "All used glyphs mst be present in fonts for PDF/A, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
663
0
                                        pdev->AbortPDFAX = true;
664
0
                                        pdev->PDFA = 0;
665
0
                                        break;
666
0
                                }
667
0
                            }
668
403
                        }
669
4.07k
                        cid = 0, code = 1;  /* undefined glyph. */
670
4.07k
                        notdef_subst = true;
671
                        /* If this is the first use of CID=0, get its width */
672
4.07k
                        if (pdsubf->Widths[cid] == 0) {
673
3.98k
                            pdf_glyph_widths_t widths;
674
675
3.98k
                            code = pdf_glyph_widths(pdsubf, wmode, glyph, (gs_font *)subfont, &widths,
676
3.98k
                                pte->cdevproc_callout ? pte->cdevproc_result : NULL);
677
3.98k
                        }
678
275k
                    } else if (code < 0)
679
702
                        return code;
680
278k
                    if (glyph == GS_MIN_CID_GLYPH && pdev->PDFA != 0) {
681
0
                        switch (pdev->PDFACompatibilityPolicy) {
682
0
                            case 0:
683
0
                            case 1:
684
0
                            case 3:
685
0
                                emprintf(pdev->memory,
686
0
                                     "A CIDFont uses CID 0, which is not legal for PDF/A, reverting to normal PDF output.\n");
687
0
                                pdev->AbortPDFAX = true;
688
0
                                pdev->PDFA = 0;
689
0
                                break;
690
0
                            case 2:
691
0
                                emprintf(pdev->memory,
692
0
                                     "A CIDFont uses CID 0, which is not legal for PDF/A, aborting conversion.\n");
693
0
                                return_error(gs_error_invalidfont);
694
0
                                break;
695
0
                            default:
696
0
                                emprintf(pdev->memory,
697
0
                                     "A CIDFont uses CID 0, which is not legal for PDF/A, unrecognised PDFACompatibilityLevel,\nreverting to normal PDF output\n");
698
0
                                pdev->AbortPDFAX = true;
699
0
                                pdev->PDFA = 0;
700
0
                                break;
701
0
                        }
702
0
                    }
703
278k
                    if ((code == 0 /* just copied */ || pdsubf->Widths[cid] == 0) && !notdef_subst) {
704
274k
                        pdf_glyph_widths_t widths;
705
706
274k
                    code = pdf_glyph_widths(pdsubf, wmode, glyph, (gs_font *)subfont, &widths,
707
274k
                        pte->cdevproc_callout ? pte->cdevproc_result : NULL);
708
274k
                    if (code < 0)
709
0
                        return code;
710
274k
                    if (code == TEXT_PROCESS_CDEVPROC) {
711
0
                        pte->returned.current_glyph = glyph;
712
0
                        pte->current_font = subfont;
713
0
                        rcode = TEXT_PROCESS_CDEVPROC;
714
0
                        break;
715
0
                    }
716
274k
                    if (code >= 0) {
717
274k
                        if (cid > pdsubf->count)
718
0
                            return_error(gs_error_unregistered); /* Must not happen. */
719
274k
                        w[cid] = widths.Width.w;
720
274k
                        if (v != NULL) {
721
750
                            v[cid * 2 + 0] = widths.Width.v.x;
722
750
                            v[cid * 2 + 1] = widths.Width.v.y;
723
750
                        }
724
274k
                        real_widths[cid] = widths.real_width.w;
725
274k
                    }
726
274k
                    if (wmode) {
727
                        /* Since AR5 use W or DW to compute the x-coordinate of
728
                           v-vector, comupte and store the glyph width for WMode 0. */
729
                        /* fixme : skip computing real_width here. */
730
750
                        code = pdf_glyph_widths(pdsubf, 0, glyph, (gs_font *)subfont, &widths,
731
750
                            pte->cdevproc_callout ? pte->cdevproc_result : NULL);
732
750
                        if (code < 0)
733
0
                            return code;
734
750
                        w0[cid] = widths.Width.w;
735
750
                    }
736
274k
                    if (pdsubf->u.cidfont.CIDToGIDMap != 0) {
737
268k
                        uint gid = 0;
738
268k
                        gs_font_cid2 *subfont2 = (gs_font_cid2 *)subfont;
739
740
268k
                        gid = subfont2->cidata.CIDMap_proc(subfont2, glyph);
741
742
                        /* If this is a TrueType CIDFont, check the GSUB table to see if there's
743
                         * a suitable substitute glyph.
744
                         */
745
268k
                        if (subfont2->FontType == ft_CID_TrueType)
746
268k
                            gid = subfont2->data.substitute_glyph_index_vertical((gs_font_type42 *)subfont, gid, subfont2->WMode, glyph);
747
268k
                        pdsubf->u.cidfont.CIDToGIDMap[cid] = gid;
748
268k
                    }
749
274k
                }
750
278k
                if (wmode)
751
1.38k
                    pdsubf->u.cidfont.used2[cid >> 3] |= 0x80 >> (cid & 7);
752
278k
                }
753
278k
                pdsubf->used[cid >> 3] |= 0x80 >> (cid & 7);
754
278k
            }
755
278k
            if (pte->cdevproc_callout) {
756
                /* Only handle a single character because its width is stored
757
                  into pte->cdevproc_result, and process_text_modify_width neds it.
758
                  fixme: next time take from w, v, real_widths. */
759
0
                break_index = scan.index;
760
0
                break_xy_index = scan.xy_index;
761
0
                break;
762
0
            }
763
278k
        } while (!font_change);
764
114k
        if (break_index > index) {
765
114k
            pdf_font_resource_t *pdfont;
766
114k
            gs_matrix m3;
767
114k
            int xy_index_step = (!(pte->text.operation & TEXT_REPLACE_WIDTHS) ? 0 :
768
114k
                                 pte->text.x_widths == pte->text.y_widths ? 2 : 1);
769
114k
            gs_text_params_t save_text;
770
771
114k
            if (!subfont && num_type1_glyphs != 0)
772
0
                subfont = subfont0;
773
114k
            if (subfont && (subfont->FontType == ft_encrypted || subfont->FontType == ft_encrypted2)) {
774
0
                int save_op = pte->text.operation;
775
0
                gs_font *save_font = pte->current_font;
776
0
                const gs_glyph *save_data = pte->text.data.glyphs;
777
778
0
                pte->current_font = subfont;
779
0
                pte->text.operation |= TEXT_FROM_GLYPHS;
780
0
                pte->text.data.glyphs = type1_glyphs;
781
0
                str.data = ((const byte *)vbuf) + ((pte->text.size - pte->index) * sizeof(gs_glyph));
782
0
                str.size = num_type1_glyphs;
783
0
                code = pdf_obtain_font_resource_unencoded(pte, (const gs_string *)&str, &pdsubf0,
784
0
                    type1_glyphs);
785
0
                if (code < 0) {
786
                    /* Replace the modified values, fall back to default implementation
787
                     * (type 3 bitmap image font)
788
                     */
789
0
                    pte->current_font = save_font;
790
0
                    pte->text.operation |= save_op;
791
0
                    pte->text.data.glyphs = save_data;
792
0
                    return(code);
793
0
                }
794
0
                memcpy((void *)scan.text.data.bytes, (void *)str.data, str.size);
795
0
                str.data = scan.text.data.bytes;
796
0
                pdsubf = pdsubf0;
797
0
                pte->text.operation = save_op;
798
0
                pte->text.data.glyphs = save_data;
799
0
            }
800
114k
            if (!subfont0 || !pdsubf0)
801
                /* This should be impossible */
802
0
                return_error(gs_error_invalidfont);
803
804
114k
            pte->current_font = subfont0;
805
114k
            code = gs_matrix_multiply(&subfont0->FontMatrix, &font->FontMatrix, &m3);
806
            /* We thought that it should be gs_matrix_multiply(&font->FontMatrix, &subfont0->FontMatrix, &m3); */
807
114k
            if (code < 0)
808
0
                return code;
809
114k
            if (pdsubf0->FontType == ft_user_defined  || pdsubf0->FontType == ft_PDF_user_defined  || pdsubf0->FontType == ft_encrypted ||
810
114k
                pdsubf0->FontType == ft_encrypted2)
811
0
                    pdfont = pdsubf0;
812
114k
            else {
813
114k
                code = pdf_obtain_parent_type0_font_resource(pdev, pdsubf0, font_index0,
814
114k
                            &font->data.CMap->CMapName, &pdfont);
815
114k
                if (code < 0)
816
0
                    return code;
817
114k
                if (!pdfont->u.type0.Encoding_name[0]) {
818
                    /*
819
                    * If pdfont->u.type0.Encoding_name is set,
820
                    * a CMap resource is already attached.
821
                    * See attach_cmap_resource.
822
                    */
823
1.32k
                    code = attach_cmap_resource(pdev, pdfont, font->data.CMap, font_index0);
824
1.32k
                    if (code < 0)
825
0
                        return code;
826
1.32k
                }
827
114k
            }
828
114k
            pdf_set_text_wmode(pdev, font->WMode);
829
114k
            code = pdf_update_text_state(&text_state, (pdf_text_enum_t *)pte, pdfont, &m3);
830
114k
            if (code < 0)
831
0
                return code;
832
            /* process_text_modify_width breaks text parameters.
833
               We would like to improve it someday.
834
               Now save them locally and restore after the call. */
835
114k
            save_text = pte->text;
836
114k
            if (subfont && (subfont->FontType != ft_encrypted &&
837
114k
                subfont->FontType != ft_encrypted2)) {
838
                /* If we are a type 1 descendant, we already sorted this out above */
839
114k
                str.data = scan.text.data.bytes + index;
840
114k
                str.size = break_index - index;
841
114k
            }
842
114k
            if (pte->text.operation & TEXT_REPLACE_WIDTHS) {
843
0
                if (pte->text.x_widths != NULL)
844
0
                    pte->text.x_widths += xy_index * xy_index_step;
845
0
                if (pte->text.y_widths != NULL)
846
0
                    pte->text.y_widths += xy_index * xy_index_step;
847
0
            }
848
114k
            pte->xy_index = 0;
849
114k
            if (subfont && (subfont->FontType == ft_encrypted ||
850
114k
                subfont->FontType == ft_encrypted2)) {
851
0
                gs_font *f = pte->orig_font;
852
853
0
                adjust_first_last_char(pdfont, (byte *)str.data, str.size);
854
855
                /* Make sure we use the descendant font, not the original type 0 ! */
856
0
                pte->orig_font = subfont;
857
0
                code = process_text_modify_width((pdf_text_enum_t *)pte,
858
0
                    (gs_font *)subfont, &text_state, &str, &wxy, type1_glyphs, false, scan.index - index);
859
0
                if (code < 0)
860
0
                    return(code);
861
0
                if(font_change) {
862
0
                    type1_glyphs[0] = type1_glyphs[num_type1_glyphs];
863
0
                    num_type1_glyphs = 1;
864
0
                    subfont = saved_subfont;
865
0
                } else {
866
0
                    num_type1_glyphs = 0;
867
0
                }
868
0
                pte->orig_font = f;
869
114k
            } else {
870
114k
                code = process_text_modify_width((pdf_text_enum_t *)pte, (gs_font *)font,
871
114k
                    &text_state, &str, &wxy, NULL, true, scan.index - index);
872
114k
            }
873
114k
            if (pte->text.operation & TEXT_REPLACE_WIDTHS) {
874
0
                if (pte->text.x_widths != NULL)
875
0
                    pte->text.x_widths -= xy_index * xy_index_step;
876
0
                if (pte->text.y_widths != NULL)
877
0
                    pte->text.y_widths -= xy_index * xy_index_step;
878
0
            }
879
114k
            pte->text = save_text;
880
114k
            pte->cdevproc_callout = false;
881
114k
            if (code < 0) {
882
0
                pte->index = index;
883
0
                pte->xy_index = xy_index;
884
0
                return code;
885
0
            }
886
114k
            pte->index = break_index;
887
114k
            pte->xy_index = break_xy_index;
888
114k
            if (pdev->Eps2Write) {
889
0
                gs_rect text_bbox;
890
0
                gx_device_clip cdev;
891
0
                gx_drawing_color devc;
892
0
                fixed x0, y0, bx2, by2;
893
894
0
                text_bbox.q.x = text_bbox.p.y = text_bbox.q.y = 0;
895
0
                estimate_fontbbox(pte, (gs_font_base *)font, NULL, &text_bbox);
896
0
                text_bbox.p.x = fixed2float(pte->origin.x);
897
0
                text_bbox.q.x = text_bbox.p.x + wxy.x;
898
899
0
                x0 = float2fixed(text_bbox.p.x);
900
0
                y0 = float2fixed(text_bbox.p.y);
901
0
                bx2 = float2fixed(text_bbox.q.x) - x0;
902
0
                by2 = float2fixed(text_bbox.q.y) - y0;
903
904
0
                pdev->AccumulatingBBox++;
905
0
                gx_make_clip_device_on_stack(&cdev, pte->pcpath, (gx_device *)pdev);
906
0
                set_nonclient_dev_color(&devc, gx_device_black((gx_device *)pdev));  /* any non-white color will do */
907
0
                gx_default_fill_triangle((gx_device *) pdev, x0, y0,
908
0
                                         float2fixed(text_bbox.p.x) - x0,
909
0
                                         float2fixed(text_bbox.q.y) - y0,
910
0
                                         bx2, by2, &devc, lop_default);
911
0
                gx_default_fill_triangle((gx_device *) & cdev, x0, y0,
912
0
                                         float2fixed(text_bbox.q.x) - x0,
913
0
                                         float2fixed(text_bbox.p.y) - y0,
914
0
                                         bx2, by2, &devc, lop_default);
915
0
                gx_destroy_clip_device_on_stack(&cdev);
916
0
                pdev->AccumulatingBBox--;
917
0
            }
918
114k
            code = pdf_shift_text_currentpoint(pte, &wxy);
919
114k
            if (code < 0)
920
0
                return code;
921
114k
        }
922
114k
        pdf_text_release_cgp(pte);
923
114k
        index = break_index;
924
114k
        xy_index = break_xy_index;
925
114k
        if (done || rcode != 0)
926
114k
            break;
927
89
        pdsubf0 = pdsubf;
928
89
        font_index0 = font_index;
929
89
        subfont0 = subfont;
930
89
    }
931
114k
    pte->index = index;
932
114k
    pte->xy_index = xy_index;
933
114k
    return rcode;
934
364k
}
935
936
int
937
process_cmap_text(gs_text_enum_t *penum, void *vbuf, uint bsize)
938
364k
{
939
364k
    int code;
940
364k
    pdf_text_enum_t *pte = (pdf_text_enum_t *)penum;
941
364k
    byte *save;
942
364k
    uint start = pte->index;
943
944
364k
    if (pte->text.operation &
945
364k
        (TEXT_FROM_ANY - (TEXT_FROM_STRING | TEXT_FROM_BYTES))
946
364k
        )
947
0
        return_error(gs_error_rangecheck);
948
364k
    if (pte->text.operation & TEXT_INTERVENE) {
949
        /* Not implemented.  (PostScript doesn't allow TEXT_INTERVENE.) */
950
0
        return_error(gs_error_rangecheck);
951
0
    }
952
    /* scan_cmap_text has the unfortunate side effect of meddling with the
953
     * text data in the enumerator. In general that's OK but in the case where
954
     * the string is (eg) in a bound procedure, and we run that procedure more
955
     * than once, the string is corrupted on the first use and then produces
956
     * incorrect output for the subsequent use(s).
957
     * The routine is, sadly, extremely convoluted so instead of trying to fix
958
     * it so that it doesn't corrupt the string (which looks likely to be impossible
959
     * without copying the string at some point) I've chosen to take a copy of the
960
     * string here, and restore it after the call to scan_cmap_text.
961
     * See bug #695322 and test file Bug691680.ps
962
     */
963
364k
    save = (byte *)pte->text.data.bytes;
964
364k
    pte->text.data.bytes = gs_alloc_string(pte->memory, pte->text.size, "pdf_text_process");
965
364k
    if (pte->text.data.bytes == NULL)
966
0
        return_error(gs_error_VMerror);
967
364k
    memcpy((byte *)pte->text.data.bytes, save, pte->text.size);
968
364k
    code = scan_cmap_text(pte, vbuf);
969
364k
    gs_free_string(pte->memory, (byte *)pte->text.data.bytes,  pte->text.size, "pdf_text_process");
970
364k
    pte->text.data.bytes = save;
971
364k
    pte->bytes_decoded = pte->index - start;
972
973
364k
    if (code == TEXT_PROCESS_CDEVPROC)
974
0
        pte->cdevproc_callout = true;
975
364k
    else
976
364k
        pte->cdevproc_callout = false;
977
364k
    return code;
978
364k
}
979
980
/* ---------------- CIDFont ---------------- */
981
982
/*
983
 * Process a text string in a CIDFont.  (Only glyphshow is supported.)
984
 */
985
int
986
process_cid_text(gs_text_enum_t *pte, void *vbuf, uint bsize)
987
0
{
988
0
    pdf_text_enum_t *penum = (pdf_text_enum_t *)pte;
989
0
    uint operation = pte->text.operation;
990
0
    gs_text_enum_t save;
991
0
    gs_font *scaled_font = pte->current_font; /* CIDFont */
992
0
    gs_font *font;    /* unscaled font (CIDFont) */
993
0
    const gs_glyph *glyphs;
994
0
    gs_matrix scale_matrix;
995
0
    pdf_font_resource_t *pdsubf; /* CIDFont */
996
0
    gs_font_type0 *font0 = NULL;
997
0
    uint size;
998
0
    int code;
999
1000
0
    if (operation & TEXT_FROM_GLYPHS) {
1001
0
        glyphs = pte->text.data.glyphs;
1002
0
        size = pte->text.size - pte->index;
1003
0
    } else if (operation & TEXT_FROM_SINGLE_GLYPH) {
1004
0
        glyphs = &pte->text.data.d_glyph;
1005
0
        size = 1;
1006
0
    } else if (operation & TEXT_FROM_STRING) {
1007
0
        glyphs = &pte->outer_CID;
1008
0
        size = 1;
1009
0
    } else
1010
0
        return_error(gs_error_rangecheck);
1011
1012
    /*
1013
     * PDF doesn't support glyphshow directly: we need to create a Type 0
1014
     * font with an Identity CMap.  Make sure all the glyph numbers fit
1015
     * into 16 bits.  (Eventually we should support wider glyphs too,
1016
     * but this would require a different CMap.)
1017
     */
1018
0
    if (bsize < size * 2)
1019
0
        return_error(gs_error_unregistered); /* Must not happen. */
1020
0
    {
1021
0
        int i;
1022
0
        byte *pchars = vbuf;
1023
1024
0
        for (i = 0; i < size; ++i) {
1025
0
            ulong gnum = glyphs[i] - GS_MIN_CID_GLYPH;
1026
1027
0
            if (gnum & ~0xffffL)
1028
0
                return_error(gs_error_rangecheck);
1029
0
            *pchars++ = (byte)(gnum >> 8);
1030
0
            *pchars++ = (byte)gnum;
1031
0
        }
1032
0
    }
1033
1034
    /* Find the original (unscaled) version of this font. */
1035
1036
0
    for (font = scaled_font; font->base != font; )
1037
0
        font = font->base;
1038
    /* Compute the scaling matrix. */
1039
0
    code = gs_matrix_invert(&font->FontMatrix, &scale_matrix);
1040
0
    if (code < 0)
1041
0
        return code;
1042
0
    gs_matrix_multiply(&scale_matrix, &scaled_font->FontMatrix, &scale_matrix);
1043
1044
    /* Find or create the CIDFont resource. */
1045
1046
0
    code = pdf_obtain_font_resource(penum, NULL, &pdsubf);
1047
0
    if (code < 0)
1048
0
        return code;
1049
1050
    /* Create the CMap and Type 0 font if they don't exist already. */
1051
1052
0
    if (pdsubf->u.cidfont.glyphshow_font_id != 0)
1053
0
        font0 = (gs_font_type0 *)gs_find_font_by_id(font->dir,
1054
0
                    pdsubf->u.cidfont.glyphshow_font_id, &scaled_font->FontMatrix);
1055
0
    if (font0 == NULL) {
1056
0
        code = gs_font_type0_from_cidfont(&font0, font, font->WMode,
1057
0
                                          &scale_matrix, font->memory);
1058
0
        if (code < 0)
1059
0
            return code;
1060
0
        pdsubf->u.cidfont.glyphshow_font_id = font0->id;
1061
0
    }
1062
1063
    /* Now handle the glyphshow as a show in the Type 0 font. */
1064
1065
0
    save = *pte;
1066
0
    pte->current_font = pte->orig_font = (gs_font *)font0;
1067
    /* Patch the operation temporarily for init_fstack. */
1068
0
    pte->text.operation = (operation & ~TEXT_FROM_ANY) | TEXT_FROM_BYTES;
1069
    /* Patch the data for process_cmap_text. */
1070
0
    pte->text.data.bytes = vbuf;
1071
0
    pte->text.size = size * 2;
1072
0
    pte->index = 0;
1073
0
    gs_type0_init_fstack(pte, pte->current_font);
1074
0
    code = process_cmap_text(pte, vbuf, bsize);
1075
0
    pte->current_font = scaled_font;
1076
0
    pte->orig_font = save.orig_font;
1077
0
    pte->text = save.text;
1078
0
    pte->index = save.index + pte->index / 2;
1079
0
    pte->fstack = save.fstack;
1080
0
    return code;
1081
0
}