xref: /plan9/sys/src/cmd/gs/src/gdevpdtw.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: gdevpdtw.c,v 1.44 2005/06/06 15:32:22 igor Exp $ */
18*593dc095SDavid du Colombier /* Font resource writing for pdfwrite text */
19*593dc095SDavid du Colombier #include "memory_.h"
20*593dc095SDavid du Colombier #include "gx.h"
21*593dc095SDavid du Colombier #include "gserrors.h"
22*593dc095SDavid du Colombier #include "gxfcmap.h"
23*593dc095SDavid du Colombier #include "gxfont.h"
24*593dc095SDavid du Colombier #include "gscencs.h"
25*593dc095SDavid du Colombier #include "gdevpsf.h"
26*593dc095SDavid du Colombier #include "gdevpdfx.h"
27*593dc095SDavid du Colombier #include "gdevpdfo.h"		/* for object->written */
28*593dc095SDavid du Colombier #include "gdevpdtd.h"		/* for writing FontDescriptor */
29*593dc095SDavid du Colombier #include "gdevpdtf.h"
30*593dc095SDavid du Colombier #include "gdevpdti.h"		/* for writing bitmap fonts Encoding */
31*593dc095SDavid du Colombier #include "gdevpdtw.h"
32*593dc095SDavid du Colombier #include "gdevpdtv.h"
33*593dc095SDavid du Colombier #include "sarc4.h"
34*593dc095SDavid du Colombier 
35*593dc095SDavid du Colombier private const char *const encoding_names[] = {
36*593dc095SDavid du Colombier     KNOWN_REAL_ENCODING_NAMES
37*593dc095SDavid du Colombier };
38*593dc095SDavid du Colombier 
39*593dc095SDavid du Colombier /* ================ Font resource writing ================ */
40*593dc095SDavid du Colombier 
41*593dc095SDavid du Colombier /* ---------------- Private ---------------- */
42*593dc095SDavid du Colombier 
43*593dc095SDavid du Colombier /* Write the Widths for a font. */
44*593dc095SDavid du Colombier private int
pdf_write_Widths(gx_device_pdf * pdev,int first,int last,const double * widths)45*593dc095SDavid du Colombier pdf_write_Widths(gx_device_pdf *pdev, int first, int last, const double *widths)
46*593dc095SDavid du Colombier {
47*593dc095SDavid du Colombier     stream *s = pdev->strm;
48*593dc095SDavid du Colombier     int i;
49*593dc095SDavid du Colombier 
50*593dc095SDavid du Colombier     if (first > last)
51*593dc095SDavid du Colombier 	first = last = 0;
52*593dc095SDavid du Colombier     pprintd2(s, "/FirstChar %d/LastChar %d/Widths[", first, last);
53*593dc095SDavid du Colombier     for (i = first; i <= last; ++i)
54*593dc095SDavid du Colombier     	pprintg1(s, (i & 15 ? " %g" : "\n%g"), psdf_round(widths[i], 100, 10));
55*593dc095SDavid du Colombier     stream_puts(s, "]\n");
56*593dc095SDavid du Colombier     return 0;
57*593dc095SDavid du Colombier }
58*593dc095SDavid du Colombier 
59*593dc095SDavid du Colombier /* Check strings equality. */
60*593dc095SDavid du Colombier private bool
strings_equal(const gs_const_string * str0,const gs_const_string * str1)61*593dc095SDavid du Colombier strings_equal(const gs_const_string *str0, const gs_const_string *str1)
62*593dc095SDavid du Colombier {
63*593dc095SDavid du Colombier     return str0->size == str1->size &&
64*593dc095SDavid du Colombier 	   !memcmp(str0->data, str1->data, str0->size);
65*593dc095SDavid du Colombier }
66*593dc095SDavid du Colombier 
67*593dc095SDavid du Colombier /* Check if an encoding element differs from a standard one. */
68*593dc095SDavid du Colombier private int
pdf_different_encoding_element(const pdf_font_resource_t * pdfont,int ch,int encoding_index)69*593dc095SDavid du Colombier pdf_different_encoding_element(const pdf_font_resource_t *pdfont, int ch, int encoding_index)
70*593dc095SDavid du Colombier {
71*593dc095SDavid du Colombier     if (pdfont->u.simple.Encoding[ch].is_difference)
72*593dc095SDavid du Colombier 	return 1;
73*593dc095SDavid du Colombier     else if (encoding_index != ENCODING_INDEX_UNKNOWN) {
74*593dc095SDavid du Colombier 	gs_glyph glyph0 = gs_c_known_encode(ch, encoding_index);
75*593dc095SDavid du Colombier 	gs_glyph glyph1 = pdfont->u.simple.Encoding[ch].glyph;
76*593dc095SDavid du Colombier 	gs_const_string str;
77*593dc095SDavid du Colombier 	int code = gs_c_glyph_name(glyph0, &str);
78*593dc095SDavid du Colombier 
79*593dc095SDavid du Colombier 	if (code < 0)
80*593dc095SDavid du Colombier 	    return code; /* Must not happen */
81*593dc095SDavid du Colombier 	if (glyph1 != GS_NO_GLYPH)
82*593dc095SDavid du Colombier 	    if (!strings_equal(&str, &pdfont->u.simple.Encoding[ch].str))
83*593dc095SDavid du Colombier 		return 1;
84*593dc095SDavid du Colombier     }
85*593dc095SDavid du Colombier     return 0;
86*593dc095SDavid du Colombier }
87*593dc095SDavid du Colombier 
88*593dc095SDavid du Colombier /* Find an index of a different encoding element. */
89*593dc095SDavid du Colombier int
pdf_different_encoding_index(const pdf_font_resource_t * pdfont,int ch0)90*593dc095SDavid du Colombier pdf_different_encoding_index(const pdf_font_resource_t *pdfont, int ch0)
91*593dc095SDavid du Colombier {
92*593dc095SDavid du Colombier     gs_encoding_index_t base_encoding = pdfont->u.simple.BaseEncoding;
93*593dc095SDavid du Colombier     int ch, code;
94*593dc095SDavid du Colombier 
95*593dc095SDavid du Colombier     for (ch = ch0; ch < 256; ++ch) {
96*593dc095SDavid du Colombier 	code = pdf_different_encoding_element(pdfont, ch, base_encoding);
97*593dc095SDavid du Colombier 	if (code < 0)
98*593dc095SDavid du Colombier 	    return code; /* Must not happen */
99*593dc095SDavid du Colombier 	if (code)
100*593dc095SDavid du Colombier 	    break;
101*593dc095SDavid du Colombier     }
102*593dc095SDavid du Colombier     return ch;
103*593dc095SDavid du Colombier }
104*593dc095SDavid du Colombier 
105*593dc095SDavid du Colombier /* Check for unknown encode (simple fonts only). */
106*593dc095SDavid du Colombier private bool
pdf_simple_font_needs_ToUnicode(const pdf_font_resource_t * pdfont)107*593dc095SDavid du Colombier pdf_simple_font_needs_ToUnicode(const pdf_font_resource_t *pdfont)
108*593dc095SDavid du Colombier {
109*593dc095SDavid du Colombier     int ch;
110*593dc095SDavid du Colombier     unsigned char mask = (pdfont->FontType == ft_encrypted || pdfont->FontType == ft_encrypted2
111*593dc095SDavid du Colombier 		? GS_C_PDF_GOOD_GLYPH_MASK : GS_C_PDF_GOOD_NON_SYMBOL_MASK);
112*593dc095SDavid du Colombier 
113*593dc095SDavid du Colombier     if (pdfont->u.simple.Encoding == NULL)
114*593dc095SDavid du Colombier 	return true; /* Bitmap Type 3 fonts have no pdfont->u.simple.Encoding . */
115*593dc095SDavid du Colombier     for (ch = 0; ch < 256; ++ch) {
116*593dc095SDavid du Colombier 	pdf_encoding_element_t *pet = &pdfont->u.simple.Encoding[ch];
117*593dc095SDavid du Colombier 	gs_glyph glyph = pet->glyph;
118*593dc095SDavid du Colombier 
119*593dc095SDavid du Colombier 	if (glyph == GS_NO_GLYPH)
120*593dc095SDavid du Colombier 	    continue;
121*593dc095SDavid du Colombier 	if (glyph < gs_c_min_std_encoding_glyph || glyph >= GS_MIN_CID_GLYPH) {
122*593dc095SDavid du Colombier 	    if (pet->str.size == 0)
123*593dc095SDavid du Colombier 		return true;
124*593dc095SDavid du Colombier 	    glyph = gs_c_name_glyph(pet->str.data, pet->str.size);
125*593dc095SDavid du Colombier 	    if (glyph == GS_NO_GLYPH)
126*593dc095SDavid du Colombier 		return true;
127*593dc095SDavid du Colombier 	}
128*593dc095SDavid du Colombier         glyph -= gs_c_min_std_encoding_glyph;
129*593dc095SDavid du Colombier         if( glyph > GS_C_PDF_MAX_GOOD_GLYPH ||
130*593dc095SDavid du Colombier            !(gs_c_pdf_glyph_type[glyph >> 2] & (mask << (( glyph & 3 )<<1) )))
131*593dc095SDavid du Colombier           return true;
132*593dc095SDavid du Colombier     }
133*593dc095SDavid du Colombier     return false;
134*593dc095SDavid du Colombier }
135*593dc095SDavid du Colombier 
136*593dc095SDavid du Colombier /* Write Encoding differencrs. */
137*593dc095SDavid du Colombier int
pdf_write_encoding(gx_device_pdf * pdev,const pdf_font_resource_t * pdfont,long id,int ch)138*593dc095SDavid du Colombier pdf_write_encoding(gx_device_pdf *pdev, const pdf_font_resource_t *pdfont, long id, int ch)
139*593dc095SDavid du Colombier {
140*593dc095SDavid du Colombier     /* Note : this truncates extended glyph names to original names. */
141*593dc095SDavid du Colombier     stream *s;
142*593dc095SDavid du Colombier     gs_encoding_index_t base_encoding = pdfont->u.simple.BaseEncoding;
143*593dc095SDavid du Colombier     const int sl = strlen(gx_extendeg_glyph_name_separator);
144*593dc095SDavid du Colombier     int prev = 256, code;
145*593dc095SDavid du Colombier 
146*593dc095SDavid du Colombier     pdf_open_separate(pdev, id);
147*593dc095SDavid du Colombier     s = pdev->strm;
148*593dc095SDavid du Colombier     stream_puts(s, "<</Type/Encoding");
149*593dc095SDavid du Colombier     if (base_encoding < 0 && pdev->ForOPDFRead)
150*593dc095SDavid du Colombier 	base_encoding = ENCODING_INDEX_STANDARD;
151*593dc095SDavid du Colombier     if (base_encoding > 0)
152*593dc095SDavid du Colombier 	pprints1(s, "/BaseEncoding/%s", encoding_names[base_encoding]);
153*593dc095SDavid du Colombier     stream_puts(s, "/Differences[");
154*593dc095SDavid du Colombier     for (; ch < 256; ++ch) {
155*593dc095SDavid du Colombier 	code = pdf_different_encoding_element(pdfont, ch, base_encoding);
156*593dc095SDavid du Colombier 	if (code < 0)
157*593dc095SDavid du Colombier 	    return code; /* Must not happen */
158*593dc095SDavid du Colombier 	if (code == 0 && pdfont->FontType == ft_user_defined) {
159*593dc095SDavid du Colombier 	    /* PDF 1.4 spec Appendix H Note 42 says that
160*593dc095SDavid du Colombier 	     * Acrobat 4 can't properly handle Base Encoding.
161*593dc095SDavid du Colombier 	     * Enforce writing differences against that.
162*593dc095SDavid du Colombier 	     */
163*593dc095SDavid du Colombier 	    if (pdfont->used[ch >> 3] & 0x80 >> (ch & 7))
164*593dc095SDavid du Colombier 		if (pdfont->u.simple.Encoding[ch].str.size)
165*593dc095SDavid du Colombier 		    code = 1;
166*593dc095SDavid du Colombier 	}
167*593dc095SDavid du Colombier 	if (code) {
168*593dc095SDavid du Colombier 	    const byte *d = pdfont->u.simple.Encoding[ch].str.data;
169*593dc095SDavid du Colombier 	    int i, l = pdfont->u.simple.Encoding[ch].str.size;
170*593dc095SDavid du Colombier 
171*593dc095SDavid du Colombier     	    if (pdev->HavePDFWidths) {
172*593dc095SDavid du Colombier 		for (i = 0; i + sl < l; i++)
173*593dc095SDavid du Colombier 		    if (!memcmp(d + i, gx_extendeg_glyph_name_separator, sl)) {
174*593dc095SDavid du Colombier 			l = i;
175*593dc095SDavid du Colombier 			break;
176*593dc095SDavid du Colombier 		    }
177*593dc095SDavid du Colombier 	    }
178*593dc095SDavid du Colombier 	    if (ch != prev + 1)
179*593dc095SDavid du Colombier 		pprintd1(s, "\n%d", ch);
180*593dc095SDavid du Colombier 	    pdf_put_name(pdev, d, l);
181*593dc095SDavid du Colombier 	    prev = ch;
182*593dc095SDavid du Colombier 	}
183*593dc095SDavid du Colombier     }
184*593dc095SDavid du Colombier     stream_puts(s, "]>>\n");
185*593dc095SDavid du Colombier     pdf_end_separate(pdev);
186*593dc095SDavid du Colombier     return 0;
187*593dc095SDavid du Colombier }
188*593dc095SDavid du Colombier 
189*593dc095SDavid du Colombier /* Write Encoding reference. */
190*593dc095SDavid du Colombier int
pdf_write_encoding_ref(gx_device_pdf * pdev,const pdf_font_resource_t * pdfont,long id)191*593dc095SDavid du Colombier pdf_write_encoding_ref(gx_device_pdf *pdev,
192*593dc095SDavid du Colombier 	  const pdf_font_resource_t *pdfont, long id)
193*593dc095SDavid du Colombier {
194*593dc095SDavid du Colombier     stream *s = pdev->strm;
195*593dc095SDavid du Colombier 
196*593dc095SDavid du Colombier     if (id != 0)
197*593dc095SDavid du Colombier 	pprintld1(s, "/Encoding %ld 0 R", id);
198*593dc095SDavid du Colombier     else if (pdfont->u.simple.BaseEncoding > 0) {
199*593dc095SDavid du Colombier 	gs_encoding_index_t base_encoding = pdfont->u.simple.BaseEncoding;
200*593dc095SDavid du Colombier 	pprints1(s, "/Encoding/%s", encoding_names[base_encoding]);
201*593dc095SDavid du Colombier     }
202*593dc095SDavid du Colombier     return 0;
203*593dc095SDavid du Colombier }
204*593dc095SDavid du Colombier 
205*593dc095SDavid du Colombier /* Write the Subtype and Encoding for a simple font. */
206*593dc095SDavid du Colombier private int
pdf_write_simple_contents(gx_device_pdf * pdev,const pdf_font_resource_t * pdfont)207*593dc095SDavid du Colombier pdf_write_simple_contents(gx_device_pdf *pdev,
208*593dc095SDavid du Colombier 			  const pdf_font_resource_t *pdfont)
209*593dc095SDavid du Colombier {
210*593dc095SDavid du Colombier     stream *s = pdev->strm;
211*593dc095SDavid du Colombier     long diff_id = 0;
212*593dc095SDavid du Colombier     int ch = (pdfont->u.simple.Encoding ? 0 : 256);
213*593dc095SDavid du Colombier     int code = 0;
214*593dc095SDavid du Colombier 
215*593dc095SDavid du Colombier     ch = pdf_different_encoding_index(pdfont, ch);
216*593dc095SDavid du Colombier     if (ch < 256)
217*593dc095SDavid du Colombier 	diff_id = pdf_obj_ref(pdev);
218*593dc095SDavid du Colombier     code = pdf_write_encoding_ref(pdev, pdfont, diff_id);
219*593dc095SDavid du Colombier     if (code < 0)
220*593dc095SDavid du Colombier 	return code;
221*593dc095SDavid du Colombier     pprints1(s, "/Subtype/%s>>\n",
222*593dc095SDavid du Colombier 	     (pdfont->FontType == ft_TrueType ? "TrueType" :
223*593dc095SDavid du Colombier 	      pdfont->u.simple.s.type1.is_MM_instance ? "MMType1" : "Type1"));
224*593dc095SDavid du Colombier     pdf_end_separate(pdev);
225*593dc095SDavid du Colombier     if (diff_id) {
226*593dc095SDavid du Colombier 	code = pdf_write_encoding(pdev, pdfont, diff_id, ch);
227*593dc095SDavid du Colombier 	if (code < 0)
228*593dc095SDavid du Colombier 	    return code;
229*593dc095SDavid du Colombier     }
230*593dc095SDavid du Colombier     return 0;
231*593dc095SDavid du Colombier }
232*593dc095SDavid du Colombier 
233*593dc095SDavid du Colombier /*
234*593dc095SDavid du Colombier  * Write the W[2] entries for a CIDFont.  *pdfont is known to be a
235*593dc095SDavid du Colombier  * CIDFont (type 0 or 2).
236*593dc095SDavid du Colombier  */
237*593dc095SDavid du Colombier private bool
pdf_compute_CIDFont_default_widths(const pdf_font_resource_t * pdfont,int wmode,int * pdw,int * pdv)238*593dc095SDavid du Colombier pdf_compute_CIDFont_default_widths(const pdf_font_resource_t *pdfont, int wmode, int *pdw, int *pdv)
239*593dc095SDavid du Colombier {
240*593dc095SDavid du Colombier     psf_glyph_enum_t genum;
241*593dc095SDavid du Colombier     gs_glyph glyph;
242*593dc095SDavid du Colombier     ushort counts[1500]; /* Some CID fonts use vertical widths 1026 .*/
243*593dc095SDavid du Colombier     int dw_count = 0, i, dwi = 0, neg_count = 0, pos_count = 0;
244*593dc095SDavid du Colombier     double *w = (wmode ? pdfont->u.cidfont.Widths2 : pdfont->Widths);
245*593dc095SDavid du Colombier 
246*593dc095SDavid du Colombier     /* We don't wont to scan for both negative and positive widths,
247*593dc095SDavid du Colombier      * to save the C stack space.
248*593dc095SDavid du Colombier      * Doubtly they both are used in same font.
249*593dc095SDavid du Colombier      * So just count positive and negative widths separately
250*593dc095SDavid du Colombier      * and use the corresponding sign.
251*593dc095SDavid du Colombier      * fixme : implement 2 hystograms.
252*593dc095SDavid du Colombier      */
253*593dc095SDavid du Colombier     psf_enumerate_bits_begin(&genum, NULL,
254*593dc095SDavid du Colombier 			     wmode ? pdfont->u.cidfont.used2 : pdfont->used,
255*593dc095SDavid du Colombier 			     pdfont->count, GLYPH_SPACE_INDEX);
256*593dc095SDavid du Colombier     memset(counts, 0, sizeof(counts));
257*593dc095SDavid du Colombier     while (!psf_enumerate_glyphs_next(&genum, &glyph)) {
258*593dc095SDavid du Colombier         int i = glyph - GS_MIN_CID_GLYPH;
259*593dc095SDavid du Colombier 
260*593dc095SDavid du Colombier 	if ( i < pdfont->count) { /* safety */
261*593dc095SDavid du Colombier 	    int width = (int)(w[i] + 0.5);
262*593dc095SDavid du Colombier 
263*593dc095SDavid du Colombier 	    counts[min(any_abs(width), countof(counts) - 1)]++;
264*593dc095SDavid du Colombier 	    if (width > 0)
265*593dc095SDavid du Colombier 		pos_count++;
266*593dc095SDavid du Colombier 	    else if (width < 0)
267*593dc095SDavid du Colombier 		neg_count++;
268*593dc095SDavid du Colombier 	}
269*593dc095SDavid du Colombier     }
270*593dc095SDavid du Colombier     for (i = 1; i < countof(counts); ++i)
271*593dc095SDavid du Colombier 	if (counts[i] > dw_count)
272*593dc095SDavid du Colombier 	    dwi = i, dw_count = counts[i];
273*593dc095SDavid du Colombier     *pdw = (neg_count > pos_count ? -dwi : dwi);
274*593dc095SDavid du Colombier     *pdv = 0;
275*593dc095SDavid du Colombier     if (wmode) {
276*593dc095SDavid du Colombier 	psf_enumerate_glyphs_reset(&genum);
277*593dc095SDavid du Colombier 	while (!psf_enumerate_glyphs_next(&genum, &glyph)) {
278*593dc095SDavid du Colombier 	    int i = glyph - GS_MIN_CID_GLYPH;
279*593dc095SDavid du Colombier 
280*593dc095SDavid du Colombier 	    if ( i < pdfont->count) { /* safety */
281*593dc095SDavid du Colombier 		int width = (int)(w[i] + 0.5);
282*593dc095SDavid du Colombier 
283*593dc095SDavid du Colombier 		if (min(any_abs(width), countof(counts) - 1) == any_abs(dwi)) {
284*593dc095SDavid du Colombier 		    *pdv = (int)(pdfont->u.cidfont.v[i * 2 + 1] + 0.5);
285*593dc095SDavid du Colombier 		    break;
286*593dc095SDavid du Colombier 		}
287*593dc095SDavid du Colombier 	    }
288*593dc095SDavid du Colombier 	}
289*593dc095SDavid du Colombier     }
290*593dc095SDavid du Colombier     return (dw_count + counts[0] > 0);
291*593dc095SDavid du Colombier }
292*593dc095SDavid du Colombier 
293*593dc095SDavid du Colombier /*
294*593dc095SDavid du Colombier  * Write the [D]W[2] entries for a CIDFont.  *pdfont is known to be a
295*593dc095SDavid du Colombier  * CIDFont (type 0 or 2).
296*593dc095SDavid du Colombier  */
297*593dc095SDavid du Colombier private int
pdf_write_CIDFont_widths(gx_device_pdf * pdev,const pdf_font_resource_t * pdfont,int wmode)298*593dc095SDavid du Colombier pdf_write_CIDFont_widths(gx_device_pdf *pdev,
299*593dc095SDavid du Colombier 			 const pdf_font_resource_t *pdfont, int wmode)
300*593dc095SDavid du Colombier {
301*593dc095SDavid du Colombier     /*
302*593dc095SDavid du Colombier      * The values of the CIDFont width keys are as follows:
303*593dc095SDavid du Colombier      *   DW = w (default 0)
304*593dc095SDavid du Colombier      *   W = [{c [w ...] | cfirst clast w}*]
305*593dc095SDavid du Colombier      *   DW2 = [vy w1y] (default [880 -1000])
306*593dc095SDavid du Colombier      *   W2 = [{c [w1y vx vy ...] | cfirst clast w1y vx vy}*]
307*593dc095SDavid du Colombier      */
308*593dc095SDavid du Colombier     stream *s = pdev->strm;
309*593dc095SDavid du Colombier     psf_glyph_enum_t genum;
310*593dc095SDavid du Colombier     gs_glyph glyph;
311*593dc095SDavid du Colombier     int dw = 0, dv = 0, prev = -2;
312*593dc095SDavid du Colombier     const char *Widths_key = (wmode ? "/W2" : "/W");
313*593dc095SDavid du Colombier     double *w = (wmode ? pdfont->u.cidfont.Widths2 : pdfont->Widths);
314*593dc095SDavid du Colombier 
315*593dc095SDavid du Colombier     /* Compute and write default width : */
316*593dc095SDavid du Colombier     if (pdf_compute_CIDFont_default_widths(pdfont, wmode, &dw, &dv)) {
317*593dc095SDavid du Colombier 	if (wmode) {
318*593dc095SDavid du Colombier 	    pprintd2(s, "/DW2 [%d %d]\n", dv, dw);
319*593dc095SDavid du Colombier 	} else
320*593dc095SDavid du Colombier 	    pprintd1(s, "/DW %d\n", dw);
321*593dc095SDavid du Colombier     }
322*593dc095SDavid du Colombier 
323*593dc095SDavid du Colombier     /*
324*593dc095SDavid du Colombier      * Now write all widths different from the default one.  Currently we make no
325*593dc095SDavid du Colombier      * attempt to optimize this: we write every width individually.
326*593dc095SDavid du Colombier      */
327*593dc095SDavid du Colombier     psf_enumerate_bits_begin(&genum, NULL,
328*593dc095SDavid du Colombier 			     wmode ? pdfont->u.cidfont.used2 : pdfont->used,
329*593dc095SDavid du Colombier 			     pdfont->count, GLYPH_SPACE_INDEX);
330*593dc095SDavid du Colombier     {
331*593dc095SDavid du Colombier 	while (!psf_enumerate_glyphs_next(&genum, &glyph)) {
332*593dc095SDavid du Colombier 	    int cid = glyph - GS_MIN_CID_GLYPH;
333*593dc095SDavid du Colombier 	    int width = (int)(w[cid] + 0.5);
334*593dc095SDavid du Colombier 
335*593dc095SDavid du Colombier #if 0 /* Must write zero widths - see test file of the bug Bug 687681.
336*593dc095SDavid du Colombier 	 We don't enumerate unused glyphs here due to pdfont->used. */
337*593dc095SDavid du Colombier 	    if (width == 0)
338*593dc095SDavid du Colombier 		continue; /* Don't write for unused glyphs. */
339*593dc095SDavid du Colombier #else
340*593dc095SDavid du Colombier 	    {	/* Check whether copied font really have this glyph.
341*593dc095SDavid du Colombier 	           debugged with 401-01.ps, which uses undefined CIDs. */
342*593dc095SDavid du Colombier 		gs_font_base *pfont = pdf_font_resource_font(pdfont, false);
343*593dc095SDavid du Colombier 		gs_glyph_info_t info;
344*593dc095SDavid du Colombier 
345*593dc095SDavid du Colombier 		if (pdfont != NULL) {
346*593dc095SDavid du Colombier 		    if (pfont->procs.glyph_info((gs_font *)pfont, glyph, NULL, 0, &info) < 0)
347*593dc095SDavid du Colombier 			continue;
348*593dc095SDavid du Colombier 		}
349*593dc095SDavid du Colombier 	    }
350*593dc095SDavid du Colombier #endif
351*593dc095SDavid du Colombier 	    if (cid == prev + 1) {
352*593dc095SDavid du Colombier 		if (wmode) {
353*593dc095SDavid du Colombier 		    int vx = (int)(pdfont->u.cidfont.v[cid * 2 + 0] + 0.5);
354*593dc095SDavid du Colombier 		    int vy = (int)(pdfont->u.cidfont.v[cid * 2 + 1] + 0.5);
355*593dc095SDavid du Colombier 
356*593dc095SDavid du Colombier 		    pprintd3(s, "\n%d %d %d", width, vx, vy);
357*593dc095SDavid du Colombier 		} else
358*593dc095SDavid du Colombier 		    pprintd1(s, "\n%d", width);
359*593dc095SDavid du Colombier 	    } else if (width == dw &&
360*593dc095SDavid du Colombier 		    (!wmode || (int)(pdfont->u.cidfont.v[cid * 2 + 0] + 0.5) ==
361*593dc095SDavid du Colombier 				(int)(pdfont->Widths[cid] / 2 + 0.5)) &&
362*593dc095SDavid du Colombier 		    (!wmode || (int)(pdfont->u.cidfont.v[cid * 2 + 1] + 0.5) == dv))
363*593dc095SDavid du Colombier 		continue;
364*593dc095SDavid du Colombier 	    else {
365*593dc095SDavid du Colombier 		if (prev >= 0)
366*593dc095SDavid du Colombier 		    stream_puts(s, "]\n");
367*593dc095SDavid du Colombier 		else {
368*593dc095SDavid du Colombier 		    stream_puts(s, Widths_key);
369*593dc095SDavid du Colombier 		    stream_puts(s, "[");
370*593dc095SDavid du Colombier 		}
371*593dc095SDavid du Colombier 		if (wmode) {
372*593dc095SDavid du Colombier 		    int vx = (int)(pdfont->u.cidfont.v[cid * 2 + 0] + 0.5);
373*593dc095SDavid du Colombier 		    int vy = (int)(pdfont->u.cidfont.v[cid * 2 + 1] + 0.5);
374*593dc095SDavid du Colombier 
375*593dc095SDavid du Colombier 		    pprintd4(s, "%d[%d %d %d", cid, width, vx, vy);
376*593dc095SDavid du Colombier 		} else
377*593dc095SDavid du Colombier 		    pprintd2(s, "%d[%d", cid, width);
378*593dc095SDavid du Colombier 	    }
379*593dc095SDavid du Colombier 	    prev = cid;
380*593dc095SDavid du Colombier 	}
381*593dc095SDavid du Colombier 	if (prev >= 0)
382*593dc095SDavid du Colombier 	    stream_puts(s, "]]\n");
383*593dc095SDavid du Colombier     }
384*593dc095SDavid du Colombier 
385*593dc095SDavid du Colombier     return 0;
386*593dc095SDavid du Colombier }
387*593dc095SDavid du Colombier 
388*593dc095SDavid du Colombier /* ---------------- Specific FontTypes ---------------- */
389*593dc095SDavid du Colombier 
390*593dc095SDavid du Colombier /* Write the contents of a Type 0 font resource. */
391*593dc095SDavid du Colombier int
pdf_write_contents_type0(gx_device_pdf * pdev,pdf_font_resource_t * pdfont)392*593dc095SDavid du Colombier pdf_write_contents_type0(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
393*593dc095SDavid du Colombier {
394*593dc095SDavid du Colombier     stream *s = pdev->strm;
395*593dc095SDavid du Colombier 
396*593dc095SDavid du Colombier     /*
397*593dc095SDavid du Colombier      * The Encoding name might be missing if an error occurred when
398*593dc095SDavid du Colombier      * creating the font resource.
399*593dc095SDavid du Colombier      */
400*593dc095SDavid du Colombier     if (pdfont->u.type0.Encoding_name[0])
401*593dc095SDavid du Colombier 	pprints1(s, "/Encoding %s", pdfont->u.type0.Encoding_name);
402*593dc095SDavid du Colombier     pprintld1(s, "/DescendantFonts[%ld 0 R]",
403*593dc095SDavid du Colombier 	      pdf_font_id(pdfont->u.type0.DescendantFont));
404*593dc095SDavid du Colombier     stream_puts(s, "/Subtype/Type0>>\n");
405*593dc095SDavid du Colombier     pdf_end_separate(pdev);
406*593dc095SDavid du Colombier     return 0;
407*593dc095SDavid du Colombier }
408*593dc095SDavid du Colombier 
409*593dc095SDavid du Colombier /*
410*593dc095SDavid du Colombier  * Finish writing the contents of a Type 3 font resource (FontBBox, Widths,
411*593dc095SDavid du Colombier  * Subtype).
412*593dc095SDavid du Colombier  */
413*593dc095SDavid du Colombier int
pdf_finish_write_contents_type3(gx_device_pdf * pdev,pdf_font_resource_t * pdfont)414*593dc095SDavid du Colombier pdf_finish_write_contents_type3(gx_device_pdf *pdev,
415*593dc095SDavid du Colombier 				pdf_font_resource_t *pdfont)
416*593dc095SDavid du Colombier {
417*593dc095SDavid du Colombier     stream *s = pdev->strm;
418*593dc095SDavid du Colombier 
419*593dc095SDavid du Colombier     pdf_write_font_bbox(pdev, &pdfont->u.simple.s.type3.FontBBox);
420*593dc095SDavid du Colombier     pdf_write_Widths(pdev, pdfont->u.simple.FirstChar,
421*593dc095SDavid du Colombier 		    pdfont->u.simple.LastChar, pdfont->Widths);
422*593dc095SDavid du Colombier     stream_puts(s, "/Subtype/Type3>>\n");
423*593dc095SDavid du Colombier     pdf_end_separate(pdev);
424*593dc095SDavid du Colombier     return 0;
425*593dc095SDavid du Colombier }
426*593dc095SDavid du Colombier 
427*593dc095SDavid du Colombier /* Write the contents of a standard (base 14) font resource. */
428*593dc095SDavid du Colombier int
pdf_write_contents_std(gx_device_pdf * pdev,pdf_font_resource_t * pdfont)429*593dc095SDavid du Colombier pdf_write_contents_std(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
430*593dc095SDavid du Colombier {
431*593dc095SDavid du Colombier     return pdf_write_simple_contents(pdev, pdfont);
432*593dc095SDavid du Colombier }
433*593dc095SDavid du Colombier 
434*593dc095SDavid du Colombier /* Write the contents of a simple (Type 1 or Type 42) font resource. */
435*593dc095SDavid du Colombier int
pdf_write_contents_simple(gx_device_pdf * pdev,pdf_font_resource_t * pdfont)436*593dc095SDavid du Colombier pdf_write_contents_simple(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
437*593dc095SDavid du Colombier {
438*593dc095SDavid du Colombier     pdf_write_Widths(pdev, pdfont->u.simple.FirstChar,
439*593dc095SDavid du Colombier 		     pdfont->u.simple.LastChar, pdfont->Widths);
440*593dc095SDavid du Colombier     return pdf_write_simple_contents(pdev, pdfont);
441*593dc095SDavid du Colombier }
442*593dc095SDavid du Colombier 
443*593dc095SDavid du Colombier /* Write the contents of a CIDFont resource. */
444*593dc095SDavid du Colombier private int
write_contents_cid_common(gx_device_pdf * pdev,pdf_font_resource_t * pdfont,int subtype)445*593dc095SDavid du Colombier write_contents_cid_common(gx_device_pdf *pdev, pdf_font_resource_t *pdfont,
446*593dc095SDavid du Colombier 			  int subtype)
447*593dc095SDavid du Colombier {
448*593dc095SDavid du Colombier     /* Write [D]W[2], CIDSystemInfo, and Subtype, and close the object. */
449*593dc095SDavid du Colombier     stream *s = pdev->strm;
450*593dc095SDavid du Colombier     int code;
451*593dc095SDavid du Colombier 
452*593dc095SDavid du Colombier     if (pdfont->Widths != 0) {
453*593dc095SDavid du Colombier 	code = pdf_write_CIDFont_widths(pdev, pdfont, 0);
454*593dc095SDavid du Colombier 	if (code < 0)
455*593dc095SDavid du Colombier 	    return code;
456*593dc095SDavid du Colombier     } else {
457*593dc095SDavid du Colombier 	/* With a vertical font, the viewer uses /DW
458*593dc095SDavid du Colombier 	   to determine glyph width to compute its v-vector. */
459*593dc095SDavid du Colombier 	stream_puts(s, "/DW 0\n");
460*593dc095SDavid du Colombier     }
461*593dc095SDavid du Colombier     if (pdfont->u.cidfont.Widths2 != 0) {
462*593dc095SDavid du Colombier 	code = pdf_write_CIDFont_widths(pdev, pdfont, 1);
463*593dc095SDavid du Colombier 	if (code < 0)
464*593dc095SDavid du Colombier 	    return code;
465*593dc095SDavid du Colombier     }
466*593dc095SDavid du Colombier     if (pdfont->u.cidfont.CIDSystemInfo_id)
467*593dc095SDavid du Colombier 	pprintld1(s, "/CIDSystemInfo %ld 0 R",
468*593dc095SDavid du Colombier 		  pdfont->u.cidfont.CIDSystemInfo_id);
469*593dc095SDavid du Colombier     pprintd1(s, "/Subtype/CIDFontType%d>>\n", subtype);
470*593dc095SDavid du Colombier     pdf_end_separate(pdev);
471*593dc095SDavid du Colombier     return 0;
472*593dc095SDavid du Colombier }
473*593dc095SDavid du Colombier int
pdf_write_contents_cid0(gx_device_pdf * pdev,pdf_font_resource_t * pdfont)474*593dc095SDavid du Colombier pdf_write_contents_cid0(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
475*593dc095SDavid du Colombier {
476*593dc095SDavid du Colombier     return write_contents_cid_common(pdev, pdfont, 0);
477*593dc095SDavid du Colombier }
478*593dc095SDavid du Colombier int
pdf_write_contents_cid2(gx_device_pdf * pdev,pdf_font_resource_t * pdfont)479*593dc095SDavid du Colombier pdf_write_contents_cid2(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
480*593dc095SDavid du Colombier {
481*593dc095SDavid du Colombier     int count = pdfont->count;
482*593dc095SDavid du Colombier     long map_id = 0;
483*593dc095SDavid du Colombier     psf_glyph_enum_t genum;
484*593dc095SDavid du Colombier     gs_glyph glyph;
485*593dc095SDavid du Colombier     int code;
486*593dc095SDavid du Colombier 
487*593dc095SDavid du Colombier     /* Check for the identity CIDMap. */
488*593dc095SDavid du Colombier     psf_enumerate_bits_begin(&genum, NULL, pdfont->used, count,
489*593dc095SDavid du Colombier 			     GLYPH_SPACE_INDEX);
490*593dc095SDavid du Colombier     while (!psf_enumerate_glyphs_next(&genum, &glyph)) {
491*593dc095SDavid du Colombier 	int cid = glyph - GS_MIN_CID_GLYPH;
492*593dc095SDavid du Colombier 	int gid = pdfont->u.cidfont.CIDToGIDMap[cid];
493*593dc095SDavid du Colombier 
494*593dc095SDavid du Colombier 	if (gid != cid) {	/* non-identity map */
495*593dc095SDavid du Colombier 	    map_id = pdf_obj_ref(pdev);
496*593dc095SDavid du Colombier 	    pprintld1(pdev->strm, "/CIDToGIDMap %ld 0 R\n", map_id);
497*593dc095SDavid du Colombier 	    break;
498*593dc095SDavid du Colombier 	}
499*593dc095SDavid du Colombier     }
500*593dc095SDavid du Colombier 
501*593dc095SDavid du Colombier     code = write_contents_cid_common(pdev, pdfont, 2);
502*593dc095SDavid du Colombier     if (code < 0)
503*593dc095SDavid du Colombier 	return code;
504*593dc095SDavid du Colombier 
505*593dc095SDavid du Colombier     if (map_id) {
506*593dc095SDavid du Colombier 	pdf_data_writer_t writer;
507*593dc095SDavid du Colombier 	int i;
508*593dc095SDavid du Colombier 
509*593dc095SDavid du Colombier 	pdf_begin_data_stream(pdev, &writer,
510*593dc095SDavid du Colombier 	    DATA_STREAM_BINARY | DATA_STREAM_COMPRESS,
511*593dc095SDavid du Colombier 		    /* Don't set DATA_STREAM_ENCRYPT since we write to a temporary file.
512*593dc095SDavid du Colombier 		       See comment in pdf_begin_encrypt. */
513*593dc095SDavid du Colombier 		    map_id);
514*593dc095SDavid du Colombier 	for (i = 0; i < count; ++i) {
515*593dc095SDavid du Colombier 	    uint gid = pdfont->u.cidfont.CIDToGIDMap[i];
516*593dc095SDavid du Colombier 
517*593dc095SDavid du Colombier 	    stream_putc(writer.binary.strm, (byte)(gid >> 8));
518*593dc095SDavid du Colombier 	    stream_putc(writer.binary.strm, (byte)(gid));
519*593dc095SDavid du Colombier 	}
520*593dc095SDavid du Colombier 	code = pdf_end_data(&writer);
521*593dc095SDavid du Colombier     }
522*593dc095SDavid du Colombier     return code;
523*593dc095SDavid du Colombier }
524*593dc095SDavid du Colombier 
525*593dc095SDavid du Colombier /* ---------------- External entries ---------------- */
526*593dc095SDavid du Colombier 
527*593dc095SDavid du Colombier /* Write a font resource. */
528*593dc095SDavid du Colombier private int
pdf_write_font_resource(gx_device_pdf * pdev,pdf_font_resource_t * pdfont)529*593dc095SDavid du Colombier pdf_write_font_resource(gx_device_pdf *pdev, pdf_font_resource_t *pdfont)
530*593dc095SDavid du Colombier {
531*593dc095SDavid du Colombier     stream *s;
532*593dc095SDavid du Colombier 
533*593dc095SDavid du Colombier     if (pdfont->cmap_ToUnicode != NULL && pdfont->res_ToUnicode == NULL)
534*593dc095SDavid du Colombier 	if (((pdfont->FontType == ft_composite) &&
535*593dc095SDavid du Colombier 		!gs_cmap_is_identity(pdfont->cmap_ToUnicode, -1)) ||
536*593dc095SDavid du Colombier 	    ((pdfont->FontType == ft_encrypted || pdfont->FontType == ft_encrypted2 ||
537*593dc095SDavid du Colombier 		pdfont->FontType == ft_TrueType || pdfont->FontType == ft_user_defined) &&
538*593dc095SDavid du Colombier 		pdf_simple_font_needs_ToUnicode(pdfont))
539*593dc095SDavid du Colombier 	   ) {
540*593dc095SDavid du Colombier 	    pdf_resource_t *prcmap;
541*593dc095SDavid du Colombier 	    int code = pdf_cmap_alloc(pdev, pdfont->cmap_ToUnicode, &prcmap, -1);
542*593dc095SDavid du Colombier 
543*593dc095SDavid du Colombier 	    if (code < 0)
544*593dc095SDavid du Colombier 		return code;
545*593dc095SDavid du Colombier 	    pdfont->res_ToUnicode = prcmap;
546*593dc095SDavid du Colombier 	}
547*593dc095SDavid du Colombier     pdf_open_separate(pdev, pdf_font_id(pdfont));
548*593dc095SDavid du Colombier     s = pdev->strm;
549*593dc095SDavid du Colombier     stream_puts(s, "<<");
550*593dc095SDavid du Colombier     if (pdfont->BaseFont.size > 0) {
551*593dc095SDavid du Colombier 	stream_puts(s, "/BaseFont");
552*593dc095SDavid du Colombier 	pdf_put_name(pdev, pdfont->BaseFont.data, pdfont->BaseFont.size);
553*593dc095SDavid du Colombier     }
554*593dc095SDavid du Colombier     if (pdfont->FontDescriptor)
555*593dc095SDavid du Colombier 	pprintld1(s, "/FontDescriptor %ld 0 R",
556*593dc095SDavid du Colombier 		  pdf_font_descriptor_id(pdfont->FontDescriptor));
557*593dc095SDavid du Colombier     if (pdfont->res_ToUnicode)
558*593dc095SDavid du Colombier 	pprintld1(s, "/ToUnicode %ld 0 R",
559*593dc095SDavid du Colombier 		  pdf_resource_id((const pdf_resource_t *)pdfont->res_ToUnicode));
560*593dc095SDavid du Colombier     if (pdev->CompatibilityLevel > 1.0)
561*593dc095SDavid du Colombier 	stream_puts(s, "/Type/Font\n");
562*593dc095SDavid du Colombier     else
563*593dc095SDavid du Colombier 	pprintld1(s, "/Type/Font/Name/R%ld\n", pdf_font_id(pdfont));
564*593dc095SDavid du Colombier     if (pdev->ForOPDFRead && pdfont->global)
565*593dc095SDavid du Colombier 	stream_puts(s, "/.Global true\n");
566*593dc095SDavid du Colombier     return pdfont->write_contents(pdev, pdfont);
567*593dc095SDavid du Colombier }
568*593dc095SDavid du Colombier 
569*593dc095SDavid du Colombier /*
570*593dc095SDavid du Colombier  * Close the text-related parts of a document, including writing out font
571*593dc095SDavid du Colombier  * and related resources.
572*593dc095SDavid du Colombier  */
573*593dc095SDavid du Colombier private int
write_font_resources(gx_device_pdf * pdev,pdf_resource_list_t * prlist)574*593dc095SDavid du Colombier write_font_resources(gx_device_pdf *pdev, pdf_resource_list_t *prlist)
575*593dc095SDavid du Colombier {
576*593dc095SDavid du Colombier     int j;
577*593dc095SDavid du Colombier     pdf_resource_t *pres;
578*593dc095SDavid du Colombier 
579*593dc095SDavid du Colombier     for (j = 0; j < NUM_RESOURCE_CHAINS; ++j)
580*593dc095SDavid du Colombier 	for (pres = prlist->chains[j]; pres != 0; pres = pres->next) {
581*593dc095SDavid du Colombier 	    pdf_font_resource_t *const pdfont = (pdf_font_resource_t *)pres;
582*593dc095SDavid du Colombier 	    int code = pdf_compute_BaseFont(pdev, pdfont, true);
583*593dc095SDavid du Colombier 
584*593dc095SDavid du Colombier 	    if (code < 0)
585*593dc095SDavid du Colombier 		return code;
586*593dc095SDavid du Colombier 	    code = pdf_write_font_resource(pdev, pdfont);
587*593dc095SDavid du Colombier 	    if (code < 0)
588*593dc095SDavid du Colombier 		return code;
589*593dc095SDavid du Colombier 	    pdfont->object->written = true;
590*593dc095SDavid du Colombier 	}
591*593dc095SDavid du Colombier     return 0;
592*593dc095SDavid du Colombier }
593*593dc095SDavid du Colombier int
pdf_finish_font_descriptors(gx_device_pdf * pdev,int (* finish_proc)(gx_device_pdf *,pdf_font_descriptor_t *))594*593dc095SDavid du Colombier pdf_finish_font_descriptors(gx_device_pdf *pdev,
595*593dc095SDavid du Colombier 			int (*finish_proc)(gx_device_pdf *,
596*593dc095SDavid du Colombier 					   pdf_font_descriptor_t *))
597*593dc095SDavid du Colombier {
598*593dc095SDavid du Colombier     int j;
599*593dc095SDavid du Colombier     pdf_resource_t *pres;
600*593dc095SDavid du Colombier 
601*593dc095SDavid du Colombier     for (j = 0; j < NUM_RESOURCE_CHAINS; ++j)
602*593dc095SDavid du Colombier 	for (pres = pdev->resources[resourceFontDescriptor].chains[j];
603*593dc095SDavid du Colombier 	     pres != 0; pres = pres->next
604*593dc095SDavid du Colombier 	     ) {
605*593dc095SDavid du Colombier 	    int code = finish_proc(pdev, (pdf_font_descriptor_t *)pres);
606*593dc095SDavid du Colombier 
607*593dc095SDavid du Colombier 	    if (code < 0)
608*593dc095SDavid du Colombier 		return code;
609*593dc095SDavid du Colombier 	}
610*593dc095SDavid du Colombier     return 0;
611*593dc095SDavid du Colombier }
612*593dc095SDavid du Colombier int
pdf_close_text_document(gx_device_pdf * pdev)613*593dc095SDavid du Colombier pdf_close_text_document(gx_device_pdf *pdev)
614*593dc095SDavid du Colombier {
615*593dc095SDavid du Colombier     int code;
616*593dc095SDavid du Colombier 
617*593dc095SDavid du Colombier     /*
618*593dc095SDavid du Colombier      * Finish the descriptors and write any embedded fonts, but don't
619*593dc095SDavid du Colombier      * write the descriptors yet; then write the fonts; finally write
620*593dc095SDavid du Colombier      * the descriptors.
621*593dc095SDavid du Colombier      */
622*593dc095SDavid du Colombier 
623*593dc095SDavid du Colombier     pdf_clean_standard_fonts(pdev);
624*593dc095SDavid du Colombier     if ((code = pdf_free_font_cache(pdev)) < 0 ||
625*593dc095SDavid du Colombier 	(code = pdf_write_resource_objects(pdev, resourceCharProc)) < 0 ||
626*593dc095SDavid du Colombier  	(code = pdf_finish_font_descriptors(pdev, pdf_finish_FontDescriptor)) < 0 ||
627*593dc095SDavid du Colombier   	(code = write_font_resources(pdev, &pdev->resources[resourceCIDFont])) < 0 ||
628*593dc095SDavid du Colombier 	(code = write_font_resources(pdev, &pdev->resources[resourceFont])) < 0 ||
629*593dc095SDavid du Colombier 	(code = pdf_finish_font_descriptors(pdev, pdf_write_FontDescriptor)) < 0
630*593dc095SDavid du Colombier 	)
631*593dc095SDavid du Colombier 	return code;
632*593dc095SDavid du Colombier 
633*593dc095SDavid du Colombier     /* If required, write the Encoding for Type 3 bitmap fonts. */
634*593dc095SDavid du Colombier 
635*593dc095SDavid du Colombier     return pdf_write_bitmap_fonts_Encoding(pdev);
636*593dc095SDavid du Colombier }
637*593dc095SDavid du Colombier 
638*593dc095SDavid du Colombier /* ================ CMap resource writing ================ */
639*593dc095SDavid du Colombier 
640*593dc095SDavid du Colombier /*
641*593dc095SDavid du Colombier  * Write the CIDSystemInfo for a CIDFont or a CMap.
642*593dc095SDavid du Colombier  */
643*593dc095SDavid du Colombier private int
pdf_write_cid_system_info_to_stream(gx_device_pdf * pdev,stream * s,const gs_cid_system_info_t * pcidsi,gs_id object_id)644*593dc095SDavid du Colombier pdf_write_cid_system_info_to_stream(gx_device_pdf *pdev, stream *s,
645*593dc095SDavid du Colombier 			  const gs_cid_system_info_t *pcidsi, gs_id object_id)
646*593dc095SDavid du Colombier {
647*593dc095SDavid du Colombier     byte Registry[32], Ordering[32];
648*593dc095SDavid du Colombier 
649*593dc095SDavid du Colombier     if (pcidsi->Registry.size > sizeof(Registry))
650*593dc095SDavid du Colombier 	return_error(gs_error_limitcheck);
651*593dc095SDavid du Colombier     if (pcidsi->Ordering.size > sizeof(Ordering))
652*593dc095SDavid du Colombier 	return_error(gs_error_limitcheck);
653*593dc095SDavid du Colombier     memcpy(Registry, pcidsi->Registry.data, pcidsi->Registry.size);
654*593dc095SDavid du Colombier     memcpy(Ordering, pcidsi->Ordering.data, pcidsi->Ordering.size);
655*593dc095SDavid du Colombier     if (pdev->KeyLength && object_id != 0) {
656*593dc095SDavid du Colombier 	stream_arcfour_state sarc4;
657*593dc095SDavid du Colombier 	int code;
658*593dc095SDavid du Colombier 
659*593dc095SDavid du Colombier 	code = pdf_encrypt_init(pdev, object_id, &sarc4);
660*593dc095SDavid du Colombier 	if (code < 0)
661*593dc095SDavid du Colombier 	    return code;
662*593dc095SDavid du Colombier 	s_arcfour_process_buffer(&sarc4, Registry, pcidsi->Registry.size);
663*593dc095SDavid du Colombier 	code = pdf_encrypt_init(pdev, object_id, &sarc4);
664*593dc095SDavid du Colombier 	if (code < 0)
665*593dc095SDavid du Colombier 	    return code;
666*593dc095SDavid du Colombier 	s_arcfour_process_buffer(&sarc4, Ordering, pcidsi->Ordering.size);
667*593dc095SDavid du Colombier     }
668*593dc095SDavid du Colombier     stream_puts(s, "<<\n/Registry");
669*593dc095SDavid du Colombier     s_write_ps_string(s, Registry, pcidsi->Registry.size, PRINT_HEX_NOT_OK);
670*593dc095SDavid du Colombier     stream_puts(s, "\n/Ordering");
671*593dc095SDavid du Colombier     s_write_ps_string(s, Ordering, pcidsi->Ordering.size, PRINT_HEX_NOT_OK);
672*593dc095SDavid du Colombier     pprintd1(s, "\n/Supplement %d\n>>\n", pcidsi->Supplement);
673*593dc095SDavid du Colombier     return 0;
674*593dc095SDavid du Colombier }
675*593dc095SDavid du Colombier 
676*593dc095SDavid du Colombier int
pdf_write_cid_system_info(gx_device_pdf * pdev,const gs_cid_system_info_t * pcidsi,gs_id object_id)677*593dc095SDavid du Colombier pdf_write_cid_system_info(gx_device_pdf *pdev,
678*593dc095SDavid du Colombier 			  const gs_cid_system_info_t *pcidsi, gs_id object_id)
679*593dc095SDavid du Colombier {
680*593dc095SDavid du Colombier     return pdf_write_cid_system_info_to_stream(pdev, pdev->strm, pcidsi, object_id);
681*593dc095SDavid du Colombier }
682*593dc095SDavid du Colombier 
683*593dc095SDavid du Colombier 
684*593dc095SDavid du Colombier /*
685*593dc095SDavid du Colombier  * Write a CMap resource.  We pass the CMap object as well as the resource,
686*593dc095SDavid du Colombier  * because we write CMaps when they are created.
687*593dc095SDavid du Colombier  */
688*593dc095SDavid du Colombier int
pdf_write_cmap(gx_device_pdf * pdev,const gs_cmap_t * pcmap,pdf_resource_t ** ppres,int font_index_only)689*593dc095SDavid du Colombier pdf_write_cmap(gx_device_pdf *pdev, const gs_cmap_t *pcmap,
690*593dc095SDavid du Colombier 	       pdf_resource_t **ppres /*CMap*/, int font_index_only)
691*593dc095SDavid du Colombier {
692*593dc095SDavid du Colombier     int code;
693*593dc095SDavid du Colombier     pdf_data_writer_t writer;
694*593dc095SDavid du Colombier 
695*593dc095SDavid du Colombier     code = pdf_begin_data_stream(pdev, &writer,
696*593dc095SDavid du Colombier 				 DATA_STREAM_NOT_BINARY |
697*593dc095SDavid du Colombier 			    /* Don't set DATA_STREAM_ENCRYPT since we write to a temporary file.
698*593dc095SDavid du Colombier 			       See comment in pdf_begin_encrypt. */
699*593dc095SDavid du Colombier 				 (pdev->CompressFonts ?
700*593dc095SDavid du Colombier 				  DATA_STREAM_COMPRESS : 0), gs_no_id);
701*593dc095SDavid du Colombier     if (code < 0)
702*593dc095SDavid du Colombier 	return code;
703*593dc095SDavid du Colombier     *ppres = writer.pres;
704*593dc095SDavid du Colombier     writer.pres->where_used = 0; /* CMap isn't a PDF resource. */
705*593dc095SDavid du Colombier     if (!pcmap->ToUnicode) {
706*593dc095SDavid du Colombier 	byte buf[200];
707*593dc095SDavid du Colombier 	cos_dict_t *pcd = (cos_dict_t *)writer.pres->object;
708*593dc095SDavid du Colombier 	stream s;
709*593dc095SDavid du Colombier 
710*593dc095SDavid du Colombier 	code = cos_dict_put_c_key_int(pcd, "/WMode", pcmap->WMode);
711*593dc095SDavid du Colombier 	if (code < 0)
712*593dc095SDavid du Colombier 	    return code;
713*593dc095SDavid du Colombier 	buf[0] = '/';
714*593dc095SDavid du Colombier 	memcpy(buf + 1, pcmap->CMapName.data, pcmap->CMapName.size);
715*593dc095SDavid du Colombier 	code = cos_dict_put_c_key_string(pcd, "/CMapName",
716*593dc095SDavid du Colombier 			buf, pcmap->CMapName.size + 1);
717*593dc095SDavid du Colombier 	if (code < 0)
718*593dc095SDavid du Colombier 	    return code;
719*593dc095SDavid du Colombier 	s_init(&s, pdev->memory);
720*593dc095SDavid du Colombier 	swrite_string(&s, buf, sizeof(buf));
721*593dc095SDavid du Colombier 	code = pdf_write_cid_system_info_to_stream(pdev, &s, pcmap->CIDSystemInfo, 0);
722*593dc095SDavid du Colombier 	if (code < 0)
723*593dc095SDavid du Colombier 	    return code;
724*593dc095SDavid du Colombier 	code = cos_dict_put_c_key_string(pcd, "/CIDSystemInfo",
725*593dc095SDavid du Colombier 			buf, stell(&s));
726*593dc095SDavid du Colombier 	if (code < 0)
727*593dc095SDavid du Colombier 	    return code;
728*593dc095SDavid du Colombier 	code = cos_dict_put_string_copy(pcd, "/Type", "/CMap");
729*593dc095SDavid du Colombier 	if (code < 0)
730*593dc095SDavid du Colombier 	    return code;
731*593dc095SDavid du Colombier     }
732*593dc095SDavid du Colombier     code = psf_write_cmap(pdev->memory, writer.binary.strm, pcmap,
733*593dc095SDavid du Colombier 			  pdf_put_name_chars_proc(pdev), NULL, font_index_only);
734*593dc095SDavid du Colombier     if (code < 0)
735*593dc095SDavid du Colombier 	return code;
736*593dc095SDavid du Colombier     code = pdf_end_data(&writer);
737*593dc095SDavid du Colombier     if (code < 0)
738*593dc095SDavid du Colombier 	return code;
739*593dc095SDavid du Colombier     return code;
740*593dc095SDavid du Colombier }
741