Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 2002 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: gdevpdtc.c,v 1.42 2005/04/27 16:40:44 igor Exp $ */
18
/* Composite and CID-based text processing for pdfwrite. */
19
#include "memory_.h"
20
#include "string_.h"
21
#include "gx.h"
22
#include "gserrors.h"
23
#include "gxfcmap.h"
24
#include "gxfont.h"
25
#include "gxfont0.h"
26
#include "gxfont0c.h"
27
#include "gzpath.h"
28
#include "gxchar.h"
29
#include "gdevpsf.h"
30
#include "gdevpdfx.h"
31
#include "gdevpdtx.h"
32
#include "gdevpdtd.h"
33
#include "gdevpdtf.h"
34
#include "gdevpdts.h"
35
#include "gdevpdtt.h"
36
 
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
{
45
    byte *const buf = vbuf;
46
    pdf_text_enum_t *const penum = (pdf_text_enum_t *)pte;
47
    int code = 0;
48
    gs_string str;
49
    pdf_text_process_state_t text_state;
50
    pdf_text_enum_t curr, prev, out;
51
    gs_point total_width;
52
    const gs_matrix *psmat = 0;
53
    gs_font *prev_font = 0;
54
    gs_char chr, char_code = 0x0badf00d, space_char = GS_NO_CHAR;
55
    int buf_index = 0;
56
    bool return_width = (penum->text.operation & TEXT_RETURN_WIDTH);
57
 
58
    str.data = buf;
59
    if (return_width) {
60
	code = gx_path_current_point(penum->path, &penum->origin);
61
	if (code < 0)
62
	    return code;
63
    }
64
    if (pte->text.operation &
65
	(TEXT_FROM_ANY - (TEXT_FROM_STRING | TEXT_FROM_BYTES))
66
	)
67
	return_error(gs_error_rangecheck);
68
    if (pte->text.operation & TEXT_INTERVENE) {
69
	/* Not implemented. (PostScript doesn't even allow this case.) */
70
	return_error(gs_error_rangecheck);
71
    }
72
    total_width.x = total_width.y = 0;
73
    curr = *penum;
74
    prev = curr;
75
    out = curr;
76
    out.current_font = 0;
77
    /* Scan runs of characters in the same leaf font. */
78
    for ( ; ; ) {
79
	int font_code;
80
	gs_font *new_font = 0;
81
 
82
	gs_text_enum_copy_dynamic((gs_text_enum_t *)&out,
83
				  (gs_text_enum_t *)&curr, false);
84
	for (;;) {
85
	    gs_glyph glyph;
86
 
87
	    gs_text_enum_copy_dynamic((gs_text_enum_t *)&prev,
88
				      (gs_text_enum_t *)&curr, false);
89
	    font_code = pte->orig_font->procs.next_char_glyph
90
		((gs_text_enum_t *)&curr, &chr, &glyph);
91
	    /*
92
	     * We check for a font change by comparing the current
93
	     * font, rather than testing the return code, because
94
	     * it makes the control structure a little simpler.
95
	     */
96
	    switch (font_code) {
97
	    case 0:		/* no font change */
98
	    case 1:		/* font change */
99
		curr.returned.current_char = chr;
100
		char_code = gx_current_char((gs_text_enum_t *)&curr);
101
		new_font = curr.fstack.items[curr.fstack.depth].font;
102
		if (new_font != prev_font)
103
		    break;
104
		if (chr != (byte)chr)	/* probably can't happen */
105
		    return_error(gs_error_rangecheck);
106
		if (buf_index >= bsize)
107
		    return_error(gs_error_unregistered); /* Must not happen. */
108
		buf[buf_index] = (byte)chr;
109
		buf_index++;
110
		prev_font = new_font;
111
		psmat = &curr.fstack.items[curr.fstack.depth - 1].font->FontMatrix;
112
		if (pte->text.space.s_char == char_code)
113
		    space_char = chr;
114
		continue;
115
	    case 2:		/* end of string */
116
		break;
117
	    default:	/* error */
118
		return font_code;
119
	    }
120
	    break;
121
	}
122
	str.size = buf_index;
123
	if (buf_index) {
124
	    /* buf_index == 0 is only possible the very first time. */
125
	    /*
126
	     * The FontMatrix of leaf descendant fonts is not updated
127
	     * by scalefont.  Compute the effective FontMatrix now.
128
	     */
129
	    gs_matrix fmat;
130
 
131
	    /* set up the base font : */
132
	    out.fstack.depth = 0;
133
	    out.fstack.items[out.fstack.depth].font = out.current_font = prev_font;
134
 
135
	    /* Provide the decoded space character : */
136
	    out.text.space.s_char = space_char;
137
 
138
	    gs_matrix_multiply(&prev_font->FontMatrix, psmat, &fmat);
139
	    code = pdf_encode_process_string(&out, &str, NULL, &fmat, &text_state);
140
	    if (code < 0)
141
		return code;
142
	    curr.xy_index = out.xy_index; /* pdf_encode_process_string advanced it. */
143
	    gs_text_enum_copy_dynamic(pte, (gs_text_enum_t *)&prev, true);
144
	    if (return_width) {
145
		pte->returned.total_width.x = total_width.x +=
146
		    out.returned.total_width.x;
147
		pte->returned.total_width.y = total_width.y +=
148
		    out.returned.total_width.y;
149
	    }
150
	    pdf_text_release_cgp(penum);
151
	}
152
	if (font_code == 2)
153
	    break;
154
	buf[0] = (byte)chr;
155
	buf_index = 1;
156
	space_char = (pte->text.space.s_char == char_code ? chr : ~0);
157
	psmat = &curr.fstack.items[curr.fstack.depth - 1].font->FontMatrix;
158
	prev_font = new_font;
159
    }
160
    if (!return_width)
161
	return 0;
162
    return pdf_shift_text_currentpoint(penum, &total_width);
163
}
164
 
165
/* ---------------- CMap-based composite font ---------------- */
166
 
167
/*
168
 * Process a text string in a composite font with FMapType == 9 (CMap).
169
 */
170
private const char *const standard_cmap_names[] = {
171
    /* The following were added in PDF 1.4. */
172
    "GBKp-EUC-H", "GBKp-EUC-V",
173
    "GBK2K-H", "GBK2K-V",
174
    "HKscs-B5-H", "HKscs-B5-V",
175
#define END_PDF14_CMAP_NAMES_INDEX 6
176
 
177
    "Identity-H", "Identity-V",
178
 
179
    "GB-EUC-H", "GB-EUC-V",
180
    "GBpc-EUC-H", "GBpc-EUC-V",
181
    "GBK-EUC-H", "GBK-EUC-V",
182
    "UniGB-UCS2-H", "UniGB-UCS2-V",
183
 
184
    "B5pc-H", "B5pc-V",
185
    "ETen-B5-H", "ETen-B5-V",
186
    "ETenms-B5-H", "ETenms-B5-V",
187
    "CNS-EUC-H", "CNS-EUC-V",
188
    "UniCNS-UCS2-H", "UniCNS-UCS2-V",
189
 
190
    "83pv-RKSJ-H",
191
    "90ms-RKSJ-H", "90ms-RKSJ-V",
192
    "90msp-RKSJ-H", "90msp-RKSJ-V",
193
    "90pv-RKSJ-H",
194
    "Add-RKSJ-H", "Add-RKSJ-V",
195
    "EUC-H", "EUC-V",
196
    "Ext-RKSJ-H", "Ext-RKSJ-V",
197
    "H", "V",
198
    "UniJIS-UCS2-H", "UniJIS-UCS2-V",
199
    "UniJIS-UCS2-HW-H", "UniJIS-UCS2-HW-V",
200
 
201
    "KSC-EUC-H", "KSC-EUC-V",
202
    "KSCms-UHC-H", "KSCms-UHC-V",
203
    "KSCms-UHC-HW-H", "KSCms-UHC-HW-V",
204
    "KSCpc-EUC-H",
205
    "UniKS-UCS2-H", "UniKS-UCS2-V",
206
 
207
 
208
};
209
 
210
private int
211
attach_cmap_resource(gx_device_pdf *pdev, pdf_font_resource_t *pdfont, 
212
		const gs_cmap_t *pcmap, int font_index_only)
213
{
214
    const char *const *pcmn =
215
	standard_cmap_names +
216
	(pdev->CompatibilityLevel < 1.4 ? END_PDF14_CMAP_NAMES_INDEX : 0);
217
    bool is_identity = false;
218
    pdf_resource_t *pcmres = 0;	/* CMap */
219
    int code;
220
 
221
    /*
222
     * If the CMap isn't standard, write it out if necessary.
223
     */
224
    for (; *pcmn != 0; ++pcmn)
225
	if (pcmap->CMapName.size == strlen(*pcmn) &&
226
	    !memcmp(*pcmn, pcmap->CMapName.data, pcmap->CMapName.size))
227
	    break;
228
    if (*pcmn == 0) {
229
	/* 
230
	 * PScript5.dll Version 5.2 creates identity CMaps with
231
	 * instandard name. Check this specially here
232
	 * and later replace with a standard name.
233
	 * This is a temporary fix for SF bug #615994 "CMAP is corrupt".
234
	 */
235
	is_identity = gs_cmap_is_identity(pcmap, font_index_only);
236
    }
237
    if (*pcmn == 0 && !is_identity) {		/* not standard */
238
	pcmres = pdf_find_resource_by_gs_id(pdev, resourceCMap, pcmap->id + font_index_only);
239
	if (pcmres == 0) {
240
	    /* Create and write the CMap object. */
241
	    code = pdf_cmap_alloc(pdev, pcmap, &pcmres, font_index_only);
242
	    if (code < 0)
243
		return code;
244
	}
245
    }
246
    if (pcmap->from_Unicode) {
247
	gs_cmap_ranges_enum_t renum;
248
 
249
	gs_cmap_ranges_enum_init(pcmap, &renum);
250
	if (gs_cmap_enum_next_range(&renum) == 0 && renum.range.size == 2 &&
251
	    gs_cmap_enum_next_range(&renum) == 1) {
252
	    /*
253
	     * Exactly one code space range, of size 2.  Add an identity
254
	     * ToUnicode CMap.
255
	     */
256
	    if (!pdev->Identity_ToUnicode_CMaps[pcmap->WMode]) {
257
		/* Create and write an identity ToUnicode CMap now. */
258
		gs_cmap_t *pidcmap;
259
 
260
		code = gs_cmap_create_char_identity(&pidcmap, 2, pcmap->WMode,
261
						    pdev->memory);
262
		if (code < 0)
263
		    return code;
264
		pidcmap->CMapType = 2;	/* per PDF Reference */
265
		code = pdf_cmap_alloc(pdev, pidcmap,
266
				&pdev->Identity_ToUnicode_CMaps[pcmap->WMode], -1);
267
		if (code < 0)
268
		    return code;
269
	    }
270
	    pdfont->res_ToUnicode = pdev->Identity_ToUnicode_CMaps[pcmap->WMode];
271
	}
272
    }
273
    if (pcmres || is_identity) {
274
	uint size = pcmap->CMapName.size;
275
	byte *chars = gs_alloc_string(pdev->pdf_memory, size,
276
				      "pdf_font_resource_t(CMapName)");
277
 
278
	if (chars == 0)
279
	    return_error(gs_error_VMerror);
280
	memcpy(chars, pcmap->CMapName.data, size);
281
	if (is_identity)
282
	    strcpy(pdfont->u.type0.Encoding_name, 
283
		    (pcmap->WMode ? "/Identity-V" : "/Identity-H"));
284
	else
285
	    sprintf(pdfont->u.type0.Encoding_name, "%ld 0 R",
286
		    pdf_resource_id(pcmres));
287
	pdfont->u.type0.CMapName.data = chars;
288
	pdfont->u.type0.CMapName.size = size;
289
    } else {
290
	sprintf(pdfont->u.type0.Encoding_name, "/%s", *pcmn);
291
	pdfont->u.type0.CMapName.data = (const byte *)*pcmn;
292
	pdfont->u.type0.CMapName.size = strlen(*pcmn);
293
	pdfont->u.type0.cmap_is_standard = true;
294
    }
295
    pdfont->u.type0.WMode = pcmap->WMode;
296
    return 0;
297
}
298
 
299
/* Record widths and CID => GID mappings. */
300
private int
301
scan_cmap_text(pdf_text_enum_t *pte)
302
{
303
    gx_device_pdf *pdev = (gx_device_pdf *)pte->dev;
304
    /* gs_font_type0 *const font = (gs_font_type0 *)pte->current_font;*/ /* Type 0, fmap_CMap */
305
    gs_font_type0 *const font = (gs_font_type0 *)pte->orig_font; /* Type 0, fmap_CMap */
306
    /* Not sure. Changed for CDevProc callout. Was pte->current_font */
307
    gs_text_enum_t scan = *(gs_text_enum_t *)pte;
308
    int wmode = font->WMode, code, rcode = 0;
309
    pdf_font_resource_t *pdsubf0 = NULL;
310
    gs_font *subfont0 = NULL;
311
    uint index = scan.index, xy_index = scan.xy_index;
312
    uint font_index0 = 0x7badf00d;
313
    bool done = false;
314
    pdf_char_glyph_pairs_t p;
315
 
316
    p.num_all_chars = 1;
317
    p.num_unused_chars = 1;
318
    p.unused_offset = 0;
319
    pte->returned.total_width.x = pte->returned.total_width.y = 0;;
320
    for (;;) {
321
	uint break_index, break_xy_index;
322
	uint font_index = 0x7badf00d;
323
	gs_const_string str;
324
	pdf_text_process_state_t text_state;
325
	pdf_font_resource_t *pdsubf;
326
	gs_font *subfont = NULL;
327
	gs_point wxy;
328
	bool font_change;
329
 
330
	code = gx_path_current_point(pte->path, &pte->origin);
331
	if (code < 0)
332
	    return code;
333
        do {
334
	    gs_char chr;
335
	    gs_glyph glyph;
336
	    pdf_font_descriptor_t *pfd;
337
	    byte *glyph_usage;
338
	    double *real_widths, *w, *v, *w0;
339
	    int char_cache_size, width_cache_size;
340
	    uint cid;
341
 
342
	    break_index = scan.index;
343
	    break_xy_index = scan.xy_index;
344
	    code = font->procs.next_char_glyph(&scan, &chr, &glyph);
345
	    if (code == 2) {		/* end of string */
346
		done = true;
347
		break;
348
	    }
349
	    if (code < 0)
350
		return code;
351
	    subfont = scan.fstack.items[scan.fstack.depth].font;
352
	    font_index = scan.fstack.items[scan.fstack.depth].index;
353
	    scan.xy_index++;
354
	    switch (subfont->FontType) {
355
	    case ft_CID_encrypted:
356
	    case ft_CID_TrueType:
357
		break;
358
	    default:
359
		/* An unsupported case, fall back to default implementation. */
360
		return_error(gs_error_rangecheck);
361
	    }
362
	    if (glyph == GS_NO_GLYPH)
363
		glyph = GS_MIN_CID_GLYPH;
364
	    cid = glyph - GS_MIN_CID_GLYPH;
365
	    p.s[0].glyph = glyph;
366
	    p.s[0].chr = cid;
367
	    code = pdf_obtain_cidfont_resource(pdev, subfont, &pdsubf, &p);
368
	    if (code < 0)
369
		return code;
370
	    font_change = (pdsubf != pdsubf0 && pdsubf0 != NULL);
371
	    if (!font_change) {
372
		pdsubf0 = pdsubf;
373
		font_index0 = font_index;
374
		subfont0 = subfont;
375
	    }
376
	    code = pdf_attached_font_resource(pdev, (gs_font *)subfont, &pdsubf, 
377
				       &glyph_usage, &real_widths, &char_cache_size, &width_cache_size);
378
	    if (code < 0)
379
		return code;
380
	    pfd = pdsubf->FontDescriptor;
381
	    code = pdf_resize_resource_arrays(pdev, pdsubf, cid + 1);
382
	    if (code < 0)
383
		return code;
384
	    code = pdf_obtain_cidfont_widths_arrays(pdev, pdsubf, wmode, &w, &w0, &v);
385
	    if (code < 0)
386
		return code;
387
	    {
388
		pdf_font_resource_t *pdfont;
389
 
390
		code = pdf_obtain_parent_type0_font_resource(pdev, pdsubf, 
391
				&font->data.CMap->CMapName, &pdfont);
392
		if (code < 0)
393
		    return code;
394
		if (pdf_is_CID_font(subfont)) {
395
		    /* Since PScript5.dll creates GlyphNames2Unicode with character codes
396
		    instead CIDs, and with the WinCharSetFFFF-H2 CMap
397
		    character codes appears different than CIDs (Bug 687954),
398
		    pass the character code intead the CID. */
399
		    code = pdf_add_ToUnicode(pdev, subfont, pdfont, chr + GS_MIN_CID_GLYPH, chr);
400
		} else
401
		    code = pdf_add_ToUnicode(pdev, subfont, pdfont, glyph, cid);
402
		if (code < 0)
403
		    return code;
404
	    }
405
	    /* We can't check pdsubf->used[cid >> 3] here,
406
	       because it mixed data for different values of WMode. 
407
	       Perhaps pdf_font_used_glyph returns fast with reused glyphs.
408
	     */
409
	    code = pdf_font_used_glyph(pfd, glyph, (gs_font_base *)subfont);
410
	    if (code == gs_error_rangecheck) {
411
		if (!(pdsubf->used[cid >> 3] & (0x80 >> (cid & 7)))) {
412
		    char buf[gs_font_name_max + 1];
413
		    int l = min(sizeof(buf) - 1, subfont->font_name.size);
414
 
415
		    memcpy(buf, subfont->font_name.chars, l);
416
		    buf[l] = 0;
417
		    eprintf2("Missing glyph CID=%d in the font %s . The output PDF may fail with some viewers.\n", cid, buf);
418
		    pdsubf->used[cid >> 3] |= 0x80 >> (cid & 7);
419
		}
420
		cid = 0, code = 1;  /* undefined glyph. */
421
	    } else if (code < 0)
422
		return code;
423
	    if (cid >= char_cache_size || cid >= width_cache_size)
424
		return_error(gs_error_unregistered); /* Must not happen */
425
	    if (code == 0 /* just copied */ || pdsubf->Widths[cid] == 0) {
426
		pdf_glyph_widths_t widths;
427
 
428
		code = pdf_glyph_widths(pdsubf, wmode, glyph, (gs_font *)subfont, &widths,
429
				pte->cdevproc_callout ? pte->cdevproc_result : NULL);
430
		if (code < 0)
431
		    return code;
432
		if (code == TEXT_PROCESS_CDEVPROC) {
433
		    pte->returned.current_glyph = glyph;
434
		    pte->current_font = subfont;
435
		    rcode = TEXT_PROCESS_CDEVPROC;
436
		    break;
437
		}
438
		if (code == 0) { /* OK to cache */
439
		    if (cid > pdsubf->count)
440
			return_error(gs_error_unregistered); /* Must not happen. */
441
		    w[cid] = widths.Width.w;
442
		    if (v != NULL) {
443
			v[cid * 2 + 0] = widths.Width.v.x;
444
			v[cid * 2 + 1] = widths.Width.v.y;
445
		    }
446
		    real_widths[cid] = widths.real_width.w;
447
		}
448
		if (wmode) {
449
		    /* Since AR5 use W or DW to compute the x-coordinate of
450
		       v-vector, comupte and store the glyph width for WMode 0. */
451
		    /* fixme : skip computing real_width here. */
452
		    code = pdf_glyph_widths(pdsubf, 0, glyph, (gs_font *)subfont, &widths,
453
				    pte->cdevproc_callout ? pte->cdevproc_result : NULL);
454
		    if (code < 0)
455
			return code;
456
		    w0[cid] = widths.Width.w;
457
		}
458
		if (pdsubf->u.cidfont.CIDToGIDMap != 0) {
459
		    gs_font_cid2 *subfont2 = (gs_font_cid2 *)subfont;
460
 
461
		    pdsubf->u.cidfont.CIDToGIDMap[cid] =
462
			subfont2->cidata.CIDMap_proc(subfont2, glyph);
463
		}
464
	    }
465
	    pdsubf->used[cid >> 3] |= 0x80 >> (cid & 7);
466
	    if (wmode)
467
		pdsubf->u.cidfont.used2[cid >> 3] |= 0x80 >> (cid & 7);
468
	    if (pte->cdevproc_callout) {
469
		 /* Only handle a single character because its width is stored 
470
		    into pte->cdevproc_result, and process_text_modify_width neds it. 
471
		    fixme: next time take from w, v, real_widths. */
472
		break_index = scan.index;
473
		break_xy_index = scan.xy_index;
474
		break;
475
	    }
476
	} while (!font_change);
477
	if (break_index > index) {
478
	    pdf_font_resource_t *pdfont;
479
	    gs_matrix m0, m1, m2, m3;
480
	    int xy_index_step = (pte->text.x_widths != NULL && /* see gs_text_replaced_width */
481
				 pte->text.x_widths == pte->text.y_widths ? 2 : 1);
482
	    gs_text_params_t save_text;
483
 
484
	    code = pdf_font_orig_matrix(subfont0, &m0);
485
	    if (code < 0)
486
		return code;
487
	    code = gs_matrix_invert(&m0, &m1);
488
	    if (code < 0)
489
		return code;
490
	    code = gs_matrix_multiply(&subfont0->FontMatrix, &m1, &m2);
491
	    if (code < 0)
492
		return code;
493
	    code = gs_matrix_multiply(&m2, &font->FontMatrix, &m3); 
494
	    /* We thought that it should be gs_matrix_multiply(&font->FontMatrix, &m2, &m3); */
495
	    if (code < 0)
496
		return code;
497
	    code = pdf_obtain_parent_type0_font_resource(pdev, pdsubf0, 
498
			    &font->data.CMap->CMapName, &pdfont);
499
	    if (code < 0)
500
		return code;
501
	    if (!pdfont->u.type0.Encoding_name[0]) {
502
		/*
503
		 * If pdfont->u.type0.Encoding_name is set, 
504
		 * a CMap resource is already attached.
505
		 * See attach_cmap_resource.
506
		 */
507
		code = attach_cmap_resource(pdev, pdfont, font->data.CMap, font_index0);
508
		if (code < 0)
509
		    return code;
510
	    }
511
	    pdf_set_text_wmode(pdev, font->WMode);
512
	    code = pdf_update_text_state(&text_state, (pdf_text_enum_t *)pte, pdfont, &m3);
513
	    if (code < 0)
514
		return code;
515
	    /* process_text_modify_width breaks text parameters. 
516
	       We would like to improve it someday. 
517
	       Now save them locally and restore after the call. */
518
	    save_text = pte->text;
519
	    str.data = scan.text.data.bytes + index;
520
	    str.size = break_index - index;
521
	    if (pte->text.x_widths != NULL)
522
		pte->text.x_widths += xy_index * xy_index_step;
523
	    if (pte->text.y_widths != NULL)
524
		pte->text.y_widths += xy_index * xy_index_step;
525
	    pte->xy_index = 0;
526
	    code = process_text_modify_width((pdf_text_enum_t *)pte, (gs_font *)font,
527
				  &text_state, &str, &wxy);
528
	    if (pte->text.x_widths != NULL)
529
		pte->text.x_widths -= xy_index * xy_index_step;
530
	    if (pte->text.y_widths != NULL)
531
		pte->text.y_widths -= xy_index * xy_index_step;
532
	    pte->text = save_text;
533
	    pte->cdevproc_callout = false;
534
	    if (code < 0) {
535
		pte->index = index;
536
		pte->xy_index = xy_index;
537
		return code;
538
	    }
539
	    pte->index = break_index;
540
	    pte->xy_index = break_xy_index;
541
	    code = pdf_shift_text_currentpoint(pte, &wxy);
542
	    if (code < 0)
543
		return code;
544
	} 
545
	pdf_text_release_cgp(pte);
546
	index = break_index;
547
	xy_index = break_xy_index;
548
	if (done || rcode != 0)
549
	    break;
550
	pdsubf0 = pdsubf;
551
	font_index0 = font_index;
552
	subfont0 = subfont;
553
    }
554
    pte->index = index;
555
    pte->xy_index = xy_index;
556
    return rcode;
557
}
558
 
559
int
560
process_cmap_text(gs_text_enum_t *penum, void *vbuf, uint bsize)
561
{
562
    int code;
563
    pdf_text_enum_t *pte = (pdf_text_enum_t *)penum;
564
 
565
    if (pte->text.operation &
566
	(TEXT_FROM_ANY - (TEXT_FROM_STRING | TEXT_FROM_BYTES))
567
	)
568
	return_error(gs_error_rangecheck);
569
    if (pte->text.operation & TEXT_INTERVENE) {
570
	/* Not implemented.  (PostScript doesn't allow TEXT_INTERVENE.) */
571
	return_error(gs_error_rangecheck);
572
    }
573
    code = scan_cmap_text((pdf_text_enum_t *)pte);
574
    if (code == TEXT_PROCESS_CDEVPROC)
575
	pte->cdevproc_callout = true;
576
    else
577
	pte->cdevproc_callout = false;
578
    return code;
579
}
580
 
581
/* ---------------- CIDFont ---------------- */
582
 
583
/*
584
 * Process a text string in a CIDFont.  (Only glyphshow is supported.)
585
 */
586
int
587
process_cid_text(gs_text_enum_t *pte, void *vbuf, uint bsize)
588
{
589
    pdf_text_enum_t *penum = (pdf_text_enum_t *)pte;
590
    uint operation = pte->text.operation;
591
    gs_text_enum_t save;
592
    gs_font *scaled_font = pte->current_font; /* CIDFont */
593
    gs_font *font;		/* unscaled font (CIDFont) */
594
    const gs_glyph *glyphs;
595
    gs_matrix scale_matrix;
596
    pdf_font_resource_t *pdsubf; /* CIDFont */
597
    gs_font_type0 *font0 = NULL;
598
    uint size;
599
    int code;
600
 
601
    if (operation & TEXT_FROM_GLYPHS) {
602
	glyphs = pte->text.data.glyphs;
603
	size = pte->text.size - pte->index;
604
    } else if (operation & TEXT_FROM_SINGLE_GLYPH) {
605
	glyphs = &pte->text.data.d_glyph;
606
	size = 1;
607
    } else
608
	return_error(gs_error_rangecheck);
609
 
610
    /*
611
     * PDF doesn't support glyphshow directly: we need to create a Type 0
612
     * font with an Identity CMap.  Make sure all the glyph numbers fit
613
     * into 16 bits.  (Eventually we should support wider glyphs too,
614
     * but this would require a different CMap.)
615
     */
616
    if (bsize < size * 2)
617
	return_error(gs_error_unregistered); /* Must not happen. */
618
    {
619
	int i;
620
	byte *pchars = vbuf;
621
 
622
	for (i = 0; i < size; ++i) {
623
	    ulong gnum = glyphs[i] - GS_MIN_CID_GLYPH;
624
 
625
	    if (gnum & ~0xffffL)
626
		return_error(gs_error_rangecheck);
627
	    *pchars++ = (byte)(gnum >> 8);  
628
	    *pchars++ = (byte)gnum;
629
	}
630
    }
631
 
632
    /* Find the original (unscaled) version of this font. */
633
 
634
    for (font = scaled_font; font->base != font; )
635
	font = font->base;
636
    /* Compute the scaling matrix. */
637
    gs_matrix_invert(&font->FontMatrix, &scale_matrix);
638
    gs_matrix_multiply(&scale_matrix, &scaled_font->FontMatrix, &scale_matrix);
639
 
640
    /* Find or create the CIDFont resource. */
641
 
642
    code = pdf_obtain_font_resource(penum, NULL, &pdsubf);
643
    if (code < 0)
644
	return code;
645
 
646
    /* Create the CMap and Type 0 font if they don't exist already. */
647
 
648
    if (pdsubf->u.cidfont.glyphshow_font_id != 0)
649
 	font0 = (gs_font_type0 *)gs_find_font_by_id(font->dir, 
650
 		    pdsubf->u.cidfont.glyphshow_font_id, &scaled_font->FontMatrix);
651
    if (font0 == NULL) {
652
  	code = gs_font_type0_from_cidfont(&font0, font, font->WMode,
653
 					  &scale_matrix, font->memory);
654
	if (code < 0)
655
	    return code;
656
 	pdsubf->u.cidfont.glyphshow_font_id = font0->id;
657
    }
658
 
659
    /* Now handle the glyphshow as a show in the Type 0 font. */
660
 
661
    save = *pte;
662
    pte->current_font = pte->orig_font = (gs_font *)font0;
663
    /* Patch the operation temporarily for init_fstack. */
664
    pte->text.operation = (operation & ~TEXT_FROM_ANY) | TEXT_FROM_BYTES;
665
    /* Patch the data for process_cmap_text. */
666
    pte->text.data.bytes = vbuf;
667
    pte->text.size = size * 2;
668
    pte->index = 0;
669
    gs_type0_init_fstack(pte, pte->current_font);
670
    code = process_cmap_text(pte, vbuf, bsize);
671
    pte->current_font = scaled_font;
672
    pte->orig_font = save.orig_font;
673
    pte->text = save.text;
674
    pte->index = save.index + pte->index / 2;
675
    pte->fstack = save.fstack;
676
    return code;
677
}