xref: /plan9/sys/src/cmd/gs/src/gdevpsfu.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2000 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: gdevpsfu.c,v 1.12 2004/11/19 04:39:11 ray Exp $ */
18 /* PostScript/PDF font writing utilities */
19 #include "memory_.h"
20 #include <stdlib.h>		/* for qsort */
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsmatrix.h"		/* for gxfont.h */
24 #include "gxfont.h"
25 #include "gdevpsf.h"
26 
27 /* Begin enumerating the glyphs in a font or a font subset. */
28 private int
enumerate_font_next(psf_glyph_enum_t * ppge,gs_glyph * pglyph)29 enumerate_font_next(psf_glyph_enum_t *ppge, gs_glyph *pglyph)
30 {
31     gs_font *font = ppge->font;
32     int index = (int)ppge->index;
33     int code = font->procs.enumerate_glyph(font, &index,
34 					   ppge->glyph_space, pglyph);
35 
36     ppge->index = index;
37     return (index == 0 ? 1 : code < 0 ? code : 0);
38 }
39 private int
enumerate_glyphs_next(psf_glyph_enum_t * ppge,gs_glyph * pglyph)40 enumerate_glyphs_next(psf_glyph_enum_t *ppge, gs_glyph *pglyph)
41 {
42     if (ppge->index >= ppge->subset.size)
43 	return 1;
44     *pglyph = ppge->subset.selected.list[ppge->index++];
45     return 0;
46 }
47 private int
enumerate_range_next(psf_glyph_enum_t * ppge,gs_glyph * pglyph)48 enumerate_range_next(psf_glyph_enum_t *ppge, gs_glyph *pglyph)
49 {
50     if (ppge->index >= ppge->subset.size)
51 	return 1;
52     *pglyph = (gs_glyph)(ppge->index++ + gs_min_cid_glyph);
53     return 0;
54 }
55 void
psf_enumerate_list_begin(psf_glyph_enum_t * ppge,gs_font * font,const gs_glyph * subset_list,uint subset_size,gs_glyph_space_t glyph_space)56 psf_enumerate_list_begin(psf_glyph_enum_t *ppge, gs_font *font,
57 			 const gs_glyph *subset_list, uint subset_size,
58 			 gs_glyph_space_t glyph_space)
59 {
60     ppge->font = font;
61     ppge->subset.selected.list = subset_list;
62     ppge->subset.size = subset_size;
63     ppge->glyph_space = glyph_space;
64     ppge->enumerate_next =
65 	(subset_list ? enumerate_glyphs_next :
66 	 subset_size ? enumerate_range_next : enumerate_font_next);
67     psf_enumerate_glyphs_reset(ppge);
68 }
69 
70 /* Begin enumerating CID or TT glyphs in a subset given by a bit vector. */
71 private int
enumerate_bits_next(psf_glyph_enum_t * ppge,gs_glyph * pglyph)72 enumerate_bits_next(psf_glyph_enum_t *ppge, gs_glyph *pglyph)
73 {
74     for (; ppge->index < ppge->subset.size; ppge->index++)
75 	if (ppge->subset.selected.bits[ppge->index >> 3] & (0x80 >> (ppge->index & 7))) {
76 	    *pglyph = (gs_glyph)(ppge->index++ + gs_min_cid_glyph);
77 	    return 0;
78 	}
79     return 1;
80 }
81 void
psf_enumerate_bits_begin(psf_glyph_enum_t * ppge,gs_font * font,const byte * subset_bits,uint subset_size,gs_glyph_space_t glyph_space)82 psf_enumerate_bits_begin(psf_glyph_enum_t *ppge, gs_font *font,
83 			 const byte *subset_bits, uint subset_size,
84 			 gs_glyph_space_t glyph_space)
85 {
86     ppge->font = font;
87     ppge->subset.selected.bits = subset_bits;
88     ppge->subset.size = subset_size;
89     ppge->glyph_space = glyph_space;
90     ppge->enumerate_next =
91 	(subset_bits ? enumerate_bits_next :
92 	 subset_size ? enumerate_range_next : enumerate_font_next);
93     psf_enumerate_glyphs_reset(ppge);
94 }
95 
96 /* Reset a glyph enumeration. */
97 void
psf_enumerate_glyphs_reset(psf_glyph_enum_t * ppge)98 psf_enumerate_glyphs_reset(psf_glyph_enum_t *ppge)
99 {
100     ppge->index = 0;
101 }
102 
103 /* Enumerate the next glyph in a font or a font subset. */
104 /* Return 0 if more glyphs, 1 if done, <0 if error. */
105 int
psf_enumerate_glyphs_next(psf_glyph_enum_t * ppge,gs_glyph * pglyph)106 psf_enumerate_glyphs_next(psf_glyph_enum_t *ppge, gs_glyph *pglyph)
107 {
108     return ppge->enumerate_next(ppge, pglyph);
109 }
110 
111 /*
112  * Add composite glyph pieces to a list of glyphs.  Does not sort or
113  * remove duplicates.  max_pieces is the maximum number of pieces that a
114  * single glyph can have: if this value is not known, the caller should
115  * use max_count.
116  */
117 int
psf_add_subset_pieces(gs_glyph * glyphs,uint * pcount,uint max_count,uint max_pieces,gs_font * font)118 psf_add_subset_pieces(gs_glyph *glyphs, uint *pcount, uint max_count,
119 		       uint max_pieces, gs_font *font)
120 {
121     uint i;
122     uint count = *pcount;
123 
124     for (i = 0; i < count; ++i) {
125 	gs_glyph_info_t info;
126 	int code;
127 
128 	if (count + max_pieces > max_count) {
129 	    /* Check first to make sure there is enough room. */
130 	    code = font->procs.glyph_info(font, glyphs[i], NULL,
131 					  GLYPH_INFO_NUM_PIECES, &info);
132 	    if (code < 0)
133 		continue;
134 	    if (count + info.num_pieces > max_count)
135 		return_error(gs_error_rangecheck);
136 	}
137 	info.pieces = &glyphs[count];
138 	code = font->procs.glyph_info(font, glyphs[i], NULL,
139 				      GLYPH_INFO_NUM_PIECES |
140 				      GLYPH_INFO_PIECES, &info);
141 	if (code >= 0)
142 	    count += info.num_pieces;
143     }
144     *pcount = count;
145     return 0;
146 }
147 
148 /*
149  * Sort a list of glyphs and remove duplicates.  Return the number of glyphs
150  * in the result.
151  */
152 private int
compare_glyphs(const void * pg1,const void * pg2)153 compare_glyphs(const void *pg1, const void *pg2)
154 {
155     gs_glyph g1 = *(const gs_glyph *)pg1, g2 = *(const gs_glyph *)pg2;
156 
157     return (g1 < g2 ? -1 : g1 > g2 ? 1 : 0);
158 }
159 int
psf_sort_glyphs(gs_glyph * glyphs,int count)160 psf_sort_glyphs(gs_glyph *glyphs, int count)
161 {
162     int i, n;
163 
164     qsort(glyphs, count, sizeof(*glyphs), compare_glyphs);
165     for (i = n = 0; i < count; ++i)
166 	if (i == 0 || glyphs[i] != glyphs[i - 1])
167 	    glyphs[n++] = glyphs[i];
168     return n;
169 }
170 
171 /*
172  * Return the index of a given glyph in a sorted list of glyphs, or -1
173  * if the glyph is not present.
174  */
175 int
psf_sorted_glyphs_index_of(const gs_glyph * glyphs,int count,gs_glyph glyph)176 psf_sorted_glyphs_index_of(const gs_glyph *glyphs, int count, gs_glyph glyph)
177 {
178     int lo = 0, hi = count - 1;
179 
180     if (hi < 0)
181 	return -1;
182     if (glyph < glyphs[0] || glyph > glyphs[hi])
183 	return -1;
184     /*
185      * Loop invariants: hi > lo;
186      * glyphs[lo] <= glyph <= glyphs[hi].
187      */
188     while (hi - lo > 1) {
189 	int mid = (lo + hi) >> 1;
190 
191 	if (glyph >= glyphs[mid])
192 	    lo = mid;
193 	else
194 	    hi = mid;
195     }
196     return (glyph == glyphs[lo] ? lo : glyph == glyphs[hi] ? hi : -1);
197 }
198 /* Determine whether a sorted list of glyphs includes a given glyph. */
199 bool
psf_sorted_glyphs_include(const gs_glyph * glyphs,int count,gs_glyph glyph)200 psf_sorted_glyphs_include(const gs_glyph *glyphs, int count, gs_glyph glyph)
201 {
202     return psf_sorted_glyphs_index_of(glyphs, count, glyph) >= 0;
203 }
204 
205 /* Check that all selected glyphs can be written. */
206 int
psf_check_outline_glyphs(gs_font_base * pfont,psf_glyph_enum_t * ppge,glyph_data_proc_t glyph_data)207 psf_check_outline_glyphs(gs_font_base *pfont, psf_glyph_enum_t *ppge,
208 			 glyph_data_proc_t glyph_data)
209 {
210     uint members = GLYPH_INFO_WIDTH0 << pfont->WMode;
211     gs_glyph glyph;
212     int code;
213 
214     while ((code = psf_enumerate_glyphs_next(ppge, &glyph)) != 1) {
215 	gs_glyph_data_t gdata;
216 	gs_font_type1 *ignore_font;
217 	gs_glyph_info_t info;
218 
219 	if (code < 0)
220 	    return code;
221 	gdata.memory = pfont->memory;
222 	code = glyph_data(pfont, glyph, &gdata, &ignore_font);
223 	/*
224 	 * If the glyph isn't defined by a CharString, glyph_data will
225 	 * return a typecheck error.  But if there's merely a glyph in
226 	 * in the Encoding that isn't defined, glyph_data will return an
227 	 * undefined error, which is OK.
228 	 */
229 	if (code < 0) {
230 	    if (code == gs_error_undefined)
231 		continue;
232 	    return code;
233 	}
234 	gs_glyph_data_free(&gdata, "psf_check_outline_glyphs");
235 	/*
236 	 * If the font has a CDevProc or calls a non-standard OtherSubr,
237 	 * glyph_info will return a rangecheck error.
238 	 */
239 	code = pfont->procs.glyph_info((gs_font *)pfont, glyph, NULL,
240 				       members, &info);
241 	if (code < 0)
242 	    return code;
243     }
244     return 0;
245 }
246 
247 /* Gather glyph information for a Type 1 or Type 2 font. */
248 int
psf_get_outline_glyphs(psf_outline_glyphs_t * pglyphs,gs_font_base * pfont,gs_glyph * orig_subset_glyphs,uint orig_subset_size,glyph_data_proc_t glyph_data)249 psf_get_outline_glyphs(psf_outline_glyphs_t *pglyphs, gs_font_base *pfont,
250 		       gs_glyph *orig_subset_glyphs, uint orig_subset_size,
251 		       glyph_data_proc_t glyph_data)
252 {
253     gs_glyph notdef = gs_no_glyph;
254     gs_glyph *subset_glyphs = orig_subset_glyphs;
255     uint subset_size = orig_subset_size;
256 
257     if (subset_glyphs) {
258 	if (subset_size > countof(pglyphs->subset_data))
259 	    return_error(gs_error_limitcheck);
260 	memcpy(pglyphs->subset_data, orig_subset_glyphs,
261 	       sizeof(gs_glyph) * subset_size);
262 	subset_glyphs = pglyphs->subset_data;
263     }
264 
265     {
266 	/*
267 	 * Make sure that this font can be written out.  Specifically, it
268 	 * must have no CharStrings defined by PostScript procedures, no
269 	 * non-standard OtherSubrs, and no CDevProc.
270 	 */
271 	psf_glyph_enum_t genum;
272 	int code;
273 
274 	psf_enumerate_glyphs_begin(&genum, (gs_font *)pfont, subset_glyphs,
275 				    (subset_glyphs ? subset_size : 0),
276 				    GLYPH_SPACE_NAME);
277 	code = psf_check_outline_glyphs(pfont, &genum, glyph_data);
278 	if (code < 0)
279 	    return code;
280     }
281 
282     {
283 	/*
284 	 * Detect the .notdef glyph, needed for subset fonts and to
285 	 * eliminate unnecessary Encoding assignments.
286 	 */
287 	psf_glyph_enum_t genum;
288 	gs_glyph glyph;
289 	int code;
290 
291 	psf_enumerate_glyphs_begin(&genum, (gs_font *)pfont, NULL, 0,
292 				    GLYPH_SPACE_NAME);
293 	while ((code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1) {
294 	    if (gs_font_glyph_is_notdef(pfont, glyph)) {
295 		notdef = glyph;
296 		break;
297 	    }
298 	}
299     }
300 
301     if (subset_glyphs) {
302 	/*
303 	 * For subset fonts, we must ensure that characters referenced
304 	 * by seac are also included.  Note that seac creates at most
305 	 * 2 pieces.
306 	 */
307 	int code = psf_add_subset_pieces(subset_glyphs, &subset_size,
308 					  countof(pglyphs->subset_data) - 1, 2,
309 					  (gs_font *)pfont);
310 	uint keep_size, i;
311 
312 	if (code < 0)
313 	    return code;
314 	/* Subset fonts require .notdef. */
315 	if (notdef == gs_no_glyph)
316 	    return_error(gs_error_rangecheck);
317 	/* Remove undefined glyphs. */
318 	for (i = 0, keep_size = 0; i < subset_size; ++i) {
319 	    gs_glyph_info_t info;
320 	    gs_glyph glyph = subset_glyphs[i];
321 
322 	    /*
323 	     * The documentation for the glyph_info procedure says that
324 	     * using members = 0 is an inexpensive way to find out
325 	     * whether a given glyph exists, but the implementations
326 	     * don't actually do this.  Request an inexpensive value.
327 	     */
328 	    if (pfont->procs.glyph_info((gs_font *)pfont, glyph, NULL,
329 					GLYPH_INFO_NUM_PIECES, &info) >= 0)
330 		subset_glyphs[keep_size++] = glyph;
331 	}
332 	subset_size = keep_size;
333 	/* Sort the glyphs.  Make sure .notdef is included. */
334 	subset_glyphs[subset_size++] = notdef;
335 	subset_size = psf_sort_glyphs(subset_glyphs, subset_size);
336     }
337 
338     pglyphs->notdef = notdef;
339     pglyphs->subset_glyphs = subset_glyphs;
340     pglyphs->subset_size = subset_size;
341     return 0;
342 }
343