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