1 : /* cairo - a vector graphics library with display and print output
2 : *
3 : * Copyright © 2006 Red Hat, Inc
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it either under the terms of the GNU Lesser General Public
7 : * License version 2.1 as published by the Free Software Foundation
8 : * (the "LGPL") or, at your option, under the terms of the Mozilla
9 : * Public License Version 1.1 (the "MPL"). If you do not alter this
10 : * notice, a recipient may use your version of this file under either
11 : * the MPL or the LGPL.
12 : *
13 : * You should have received a copy of the LGPL along with this library
14 : * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 : * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
16 : * You should have received a copy of the MPL along with this library
17 : * in the file COPYING-MPL-1.1
18 : *
19 : * The contents of this file are subject to the Mozilla Public License
20 : * Version 1.1 (the "License"); you may not use this file except in
21 : * compliance with the License. You may obtain a copy of the License at
22 : * http://www.mozilla.org/MPL/
23 : *
24 : * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 : * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 : * the specific language governing rights and limitations.
27 : *
28 : * The Original Code is the cairo graphics library.
29 : *
30 : * The Initial Developer of the Original Code is Red Hat, Inc.
31 : *
32 : * Contributor(s):
33 : * Kristian Høgsberg <krh@redhat.com>
34 : */
35 :
36 : /*
37 : * Useful links:
38 : * http://partners.adobe.com/public/developer/en/font/T1_SPEC.PDF
39 : */
40 :
41 :
42 : #define _BSD_SOURCE /* for snprintf(), strdup() */
43 : #include "cairoint.h"
44 : #include "cairo-error-private.h"
45 :
46 : #if CAIRO_HAS_FONT_SUBSET
47 :
48 : #include "cairo-type1-private.h"
49 : #include "cairo-scaled-font-subsets-private.h"
50 : #include "cairo-output-stream-private.h"
51 :
52 : /* XXX: Eventually, we need to handle other font backends */
53 : #if CAIRO_HAS_FT_FONT
54 :
55 : #include "cairo-ft-private.h"
56 :
57 : #include <ft2build.h>
58 : #include FT_FREETYPE_H
59 : #include FT_OUTLINE_H
60 : #include FT_TYPE1_TABLES_H
61 :
62 : #include <ctype.h>
63 :
64 : typedef struct _cairo_type1_font_subset {
65 : cairo_scaled_font_subset_t *scaled_font_subset;
66 :
67 : struct {
68 : cairo_unscaled_font_t *unscaled_font;
69 : unsigned int font_id;
70 : char *base_font;
71 : unsigned int num_glyphs;
72 : double x_min, y_min, x_max, y_max;
73 : double ascent, descent;
74 :
75 : const char *data;
76 : unsigned long header_size;
77 : unsigned long data_size;
78 : unsigned long trailer_size;
79 : } base;
80 :
81 : FT_Face face;
82 : int num_glyphs;
83 :
84 : struct {
85 : int subset_index;
86 : double width;
87 : char *name;
88 : } *glyphs;
89 :
90 : cairo_output_stream_t *output;
91 : cairo_array_t contents;
92 :
93 : const char *rd, *nd;
94 :
95 : char *type1_data;
96 : unsigned int type1_length;
97 : char *type1_end;
98 :
99 : char *header_segment;
100 : int header_segment_size;
101 : char *eexec_segment;
102 : int eexec_segment_size;
103 : cairo_bool_t eexec_segment_is_ascii;
104 :
105 : char *cleartext;
106 : char *cleartext_end;
107 :
108 : int header_size;
109 :
110 : unsigned short eexec_key;
111 : cairo_bool_t hex_encode;
112 : int hex_column;
113 : } cairo_type1_font_subset_t;
114 :
115 :
116 : static cairo_status_t
117 0 : _cairo_type1_font_subset_init (cairo_type1_font_subset_t *font,
118 : cairo_unscaled_font_t *unscaled_font,
119 : cairo_bool_t hex_encode)
120 : {
121 : cairo_ft_unscaled_font_t *ft_unscaled_font;
122 : cairo_status_t status;
123 : FT_Face face;
124 : PS_FontInfoRec font_info;
125 : int i, j;
126 :
127 0 : ft_unscaled_font = (cairo_ft_unscaled_font_t *) unscaled_font;
128 :
129 0 : face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font);
130 0 : if (unlikely (face == NULL))
131 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
132 :
133 0 : if (FT_Get_PS_Font_Info(face, &font_info) != 0) {
134 0 : status = CAIRO_INT_STATUS_UNSUPPORTED;
135 0 : goto fail1;
136 : }
137 :
138 : /* OpenType/CFF fonts also have a PS_FontInfoRec */
139 : #if HAVE_FT_LOAD_SFNT_TABLE
140 0 : if (FT_IS_SFNT (face)) {
141 0 : status = CAIRO_INT_STATUS_UNSUPPORTED;
142 0 : goto fail1;
143 : }
144 : #endif
145 :
146 0 : memset (font, 0, sizeof (*font));
147 0 : font->base.unscaled_font = _cairo_unscaled_font_reference (unscaled_font);
148 0 : font->base.num_glyphs = face->num_glyphs;
149 0 : font->base.x_min = face->bbox.xMin / (double)face->units_per_EM;
150 0 : font->base.y_min = face->bbox.yMin / (double)face->units_per_EM;
151 0 : font->base.x_max = face->bbox.xMax / (double)face->units_per_EM;
152 0 : font->base.y_max = face->bbox.yMax / (double)face->units_per_EM;
153 0 : font->base.ascent = face->ascender / (double)face->units_per_EM;
154 0 : font->base.descent = face->descender / (double)face->units_per_EM;
155 :
156 0 : if (face->family_name) {
157 0 : font->base.base_font = strdup (face->family_name);
158 0 : if (unlikely (font->base.base_font == NULL)) {
159 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
160 0 : goto fail2;
161 : }
162 0 : for (i = 0, j = 0; font->base.base_font[j]; j++) {
163 0 : if (font->base.base_font[j] == ' ')
164 0 : continue;
165 0 : font->base.base_font[i++] = font->base.base_font[j];
166 : }
167 0 : font->base.base_font[i] = '\0';
168 : }
169 :
170 0 : font->glyphs = calloc (face->num_glyphs, sizeof font->glyphs[0]);
171 0 : if (unlikely (font->glyphs == NULL)) {
172 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
173 0 : goto fail3;
174 : }
175 :
176 0 : font->hex_encode = hex_encode;
177 0 : font->num_glyphs = 0;
178 0 : for (i = 0; i < face->num_glyphs; i++)
179 0 : font->glyphs[i].subset_index = -1;
180 :
181 0 : _cairo_array_init (&font->contents, sizeof (char));
182 :
183 0 : _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font);
184 :
185 0 : return CAIRO_STATUS_SUCCESS;
186 :
187 : fail3:
188 0 : if (font->base.base_font)
189 0 : free (font->base.base_font);
190 : fail2:
191 0 : _cairo_unscaled_font_destroy (unscaled_font);
192 : fail1:
193 0 : _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font);
194 :
195 0 : return status;
196 : }
197 :
198 : static void
199 0 : cairo_type1_font_subset_use_glyph (cairo_type1_font_subset_t *font, int glyph)
200 : {
201 0 : if (font->glyphs[glyph].subset_index >= 0)
202 0 : return;
203 :
204 0 : font->glyphs[glyph].subset_index = font->num_glyphs++;
205 : }
206 :
207 : static cairo_bool_t
208 0 : is_ps_delimiter(int c)
209 : {
210 : static const char delimiters[] = "()[]{}<>/% \t\r\n";
211 :
212 0 : return strchr (delimiters, c) != NULL;
213 : }
214 :
215 : static const char *
216 0 : find_token (const char *buffer, const char *end, const char *token)
217 : {
218 : int i, length;
219 : /* FIXME: find substring really must be find_token */
220 :
221 0 : if (buffer == NULL)
222 0 : return NULL;
223 :
224 0 : length = strlen (token);
225 0 : for (i = 0; buffer + i < end - length + 1; i++)
226 0 : if (memcmp (buffer + i, token, length) == 0)
227 0 : if ((i == 0 || token[0] == '/' || is_ps_delimiter(buffer[i - 1])) &&
228 0 : (buffer + i == end - length || is_ps_delimiter(buffer[i + length])))
229 0 : return buffer + i;
230 :
231 0 : return NULL;
232 : }
233 :
234 : static cairo_status_t
235 0 : cairo_type1_font_subset_find_segments (cairo_type1_font_subset_t *font)
236 : {
237 : unsigned char *p;
238 : const char *eexec_token;
239 : int size, i;
240 :
241 0 : p = (unsigned char *) font->type1_data;
242 0 : font->type1_end = font->type1_data + font->type1_length;
243 0 : if (p[0] == 0x80 && p[1] == 0x01) {
244 0 : font->header_segment_size =
245 0 : p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24);
246 0 : font->header_segment = (char *) p + 6;
247 :
248 0 : p += 6 + font->header_segment_size;
249 0 : font->eexec_segment_size =
250 0 : p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24);
251 0 : font->eexec_segment = (char *) p + 6;
252 0 : font->eexec_segment_is_ascii = (p[1] == 1);
253 :
254 0 : p += 6 + font->eexec_segment_size;
255 0 : while (p < (unsigned char *) (font->type1_end) && p[1] != 0x03) {
256 0 : size = p[2] | (p[3] << 8) | (p[4] << 16) | (p[5] << 24);
257 0 : p += 6 + size;
258 : }
259 0 : font->type1_end = (char *) p;
260 : } else {
261 0 : eexec_token = find_token ((char *) p, font->type1_end, "eexec");
262 0 : if (eexec_token == NULL)
263 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
264 :
265 0 : font->header_segment_size = eexec_token - (char *) p + strlen ("eexec\n");
266 0 : font->header_segment = (char *) p;
267 0 : font->eexec_segment_size = font->type1_length - font->header_segment_size;
268 0 : font->eexec_segment = (char *) p + font->header_segment_size;
269 0 : font->eexec_segment_is_ascii = TRUE;
270 0 : for (i = 0; i < 4; i++) {
271 0 : if (!isxdigit(font->eexec_segment[i]))
272 0 : font->eexec_segment_is_ascii = FALSE;
273 : }
274 : }
275 :
276 0 : return CAIRO_STATUS_SUCCESS;
277 : }
278 :
279 : /* Search for the definition of key and erase it by overwriting with spaces.
280 : * This function is looks for definitions of the form:
281 : *
282 : * /key1 1234 def
283 : * /key2 [12 34 56] def
284 : *
285 : * ie a key defined as an integer or array of integers.
286 : *
287 : */
288 : static void
289 0 : cairo_type1_font_erase_dict_key (cairo_type1_font_subset_t *font,
290 : const char *key)
291 : {
292 : const char *start, *p, *segment_end;
293 :
294 0 : segment_end = font->header_segment + font->header_segment_size;
295 :
296 0 : start = font->header_segment;
297 : do {
298 0 : start = find_token (start, segment_end, key);
299 0 : if (start) {
300 0 : p = start + strlen(key);
301 : /* skip integers or array of integers */
302 0 : while (p < segment_end &&
303 0 : (_cairo_isspace(*p) ||
304 0 : _cairo_isdigit(*p) ||
305 0 : *p == '[' ||
306 0 : *p == ']'))
307 : {
308 0 : p++;
309 : }
310 :
311 0 : if (p + 3 < segment_end && memcmp(p, "def", 3) == 0) {
312 : /* erase definition of the key */
313 0 : memset((char *) start, ' ', p + 3 - start);
314 : }
315 0 : start += strlen(key);
316 : }
317 0 : } while (start);
318 0 : }
319 :
320 : static cairo_status_t
321 0 : cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
322 : const char *name)
323 : {
324 : const char *start, *end, *segment_end;
325 : unsigned int i;
326 :
327 : /* FIXME:
328 : * This function assumes that /FontName always appears
329 : * before /Encoding. This appears to always be the case with Type1
330 : * fonts.
331 : *
332 : * The more recently added code for removing the UniqueID and XUID
333 : * keys can not make any assumptions about the position of the
334 : * keys in the dictionary so it is implemented by overwriting the
335 : * key definition with spaces before we start copying the font to
336 : * the output.
337 : *
338 : * This code should be rewritten to not make any assumptions about
339 : * the order of dictionary keys. This will allow UniqueID to be
340 : * stripped out instead of leaving a bunch of spaces in the
341 : * output.
342 : */
343 0 : cairo_type1_font_erase_dict_key (font, "/UniqueID");
344 0 : cairo_type1_font_erase_dict_key (font, "/XUID");
345 :
346 0 : segment_end = font->header_segment + font->header_segment_size;
347 :
348 : /* Type 1 fonts created by Fontforge have some PostScript code at
349 : * the start of the font that skips the font if the printer has a
350 : * cached copy of the font with the same unique id. This breaks
351 : * our subsetted font so we disable it by searching for the
352 : * PostScript operator "known" when used to check for the
353 : * "/UniqueID" dictionary key. We append " pop false " after it to
354 : * pop the result of this check off the stack and replace it with
355 : * "false" to make the PostScript code think "/UniqueID" does not
356 : * exist.
357 : */
358 0 : end = font->header_segment;
359 0 : start = find_token (font->header_segment, segment_end, "/UniqueID");
360 0 : if (start) {
361 0 : start += 9;
362 0 : while (start < segment_end && _cairo_isspace (*start))
363 0 : start++;
364 0 : if (start + 5 < segment_end && memcmp(start, "known", 5) == 0) {
365 0 : _cairo_output_stream_write (font->output, font->header_segment,
366 0 : start + 5 - font->header_segment);
367 0 : _cairo_output_stream_printf (font->output, " pop false ");
368 0 : end = start + 5;
369 : }
370 : }
371 :
372 0 : start = find_token (end, segment_end, "/FontName");
373 0 : if (start == NULL)
374 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
375 :
376 0 : _cairo_output_stream_write (font->output, end,
377 0 : start - end);
378 :
379 0 : _cairo_output_stream_printf (font->output, "/FontName /%s def", name);
380 :
381 0 : end = find_token (start, segment_end, "def");
382 0 : if (end == NULL)
383 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
384 0 : end += 3;
385 :
386 0 : start = find_token (end, segment_end, "/Encoding");
387 0 : if (start == NULL)
388 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
389 0 : _cairo_output_stream_write (font->output, end, start - end);
390 :
391 0 : _cairo_output_stream_printf (font->output,
392 : "/Encoding 256 array\n"
393 : "0 1 255 {1 index exch /.notdef put} for\n");
394 0 : for (i = 1; i < font->base.num_glyphs; i++) {
395 0 : if (font->glyphs[i].subset_index < 0)
396 0 : continue;
397 0 : _cairo_output_stream_printf (font->output,
398 : "dup %d /%s put\n",
399 0 : font->glyphs[i].subset_index,
400 0 : font->glyphs[i].name);
401 : }
402 0 : _cairo_output_stream_printf (font->output, "readonly def");
403 :
404 0 : end = find_token (start, segment_end, "def");
405 0 : if (end == NULL)
406 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
407 0 : end += 3;
408 :
409 0 : _cairo_output_stream_write (font->output, end, segment_end - end);
410 :
411 0 : return font->output->status;
412 : }
413 :
414 : static int
415 0 : hex_to_int (int ch)
416 : {
417 0 : if (ch <= '9')
418 0 : return ch - '0';
419 0 : else if (ch <= 'F')
420 0 : return ch - 'A' + 10;
421 : else
422 0 : return ch - 'a' + 10;
423 : }
424 :
425 : static cairo_status_t
426 0 : cairo_type1_font_subset_write_encrypted (cairo_type1_font_subset_t *font,
427 : const char *data, unsigned int length)
428 : {
429 : const unsigned char *in, *end;
430 : int c, p;
431 : static const char hex_digits[16] = "0123456789abcdef";
432 : char digits[3];
433 :
434 0 : in = (const unsigned char *) data;
435 0 : end = (const unsigned char *) data + length;
436 0 : while (in < end) {
437 0 : p = *in++;
438 0 : c = p ^ (font->eexec_key >> 8);
439 0 : font->eexec_key = (c + font->eexec_key) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2;
440 :
441 0 : if (font->hex_encode) {
442 0 : digits[0] = hex_digits[c >> 4];
443 0 : digits[1] = hex_digits[c & 0x0f];
444 0 : digits[2] = '\n';
445 0 : font->hex_column += 2;
446 :
447 0 : if (font->hex_column == 78) {
448 0 : _cairo_output_stream_write (font->output, digits, 3);
449 0 : font->hex_column = 0;
450 : } else {
451 0 : _cairo_output_stream_write (font->output, digits, 2);
452 : }
453 : } else {
454 0 : digits[0] = c;
455 0 : _cairo_output_stream_write (font->output, digits, 1);
456 : }
457 : }
458 :
459 0 : return font->output->status;
460 : }
461 :
462 : static cairo_status_t
463 0 : cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font)
464 : {
465 0 : unsigned short r = CAIRO_TYPE1_PRIVATE_DICT_KEY;
466 : unsigned char *in, *end;
467 : char *out;
468 : int c, p;
469 : int i;
470 :
471 0 : in = (unsigned char *) font->eexec_segment;
472 0 : end = (unsigned char *) in + font->eexec_segment_size;
473 :
474 0 : font->cleartext = malloc (font->eexec_segment_size);
475 0 : if (unlikely (font->cleartext == NULL))
476 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
477 :
478 0 : out = font->cleartext;
479 0 : while (in < end) {
480 0 : if (font->eexec_segment_is_ascii) {
481 0 : c = *in++;
482 0 : if (_cairo_isspace (c))
483 0 : continue;
484 0 : c = (hex_to_int (c) << 4) | hex_to_int (*in++);
485 : } else {
486 0 : c = *in++;
487 : }
488 0 : p = c ^ (r >> 8);
489 0 : r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2;
490 :
491 0 : *out++ = p;
492 : }
493 0 : font->cleartext_end = out;
494 :
495 : /* Overwrite random bytes with spaces.
496 : *
497 : * The first 4 bytes of the cleartext are the random bytes
498 : * required by the encryption algorithm. When encrypting the
499 : * cleartext, the first ciphertext byte must not be a white space
500 : * character and the first 4 bytes must not be an ASCII Hex
501 : * character. Some fonts do not check that their randomly chosen
502 : * bytes results in ciphertext that complies with this
503 : * restriction. This may cause problems for some PDF consumers. By
504 : * replacing the random bytes with spaces, the first four bytes of
505 : * ciphertext will always be 0xf9, 0x83, 0xef, 0x00 which complies
506 : * with this restriction. Using spaces also means we don't have to
507 : * skip over the random bytes when parsing the cleartext.
508 : */
509 0 : for (i = 0; i < 4 && i < font->eexec_segment_size; i++)
510 0 : font->cleartext[i] = ' ';
511 :
512 0 : return CAIRO_STATUS_SUCCESS;
513 : }
514 :
515 : static const char *
516 0 : skip_token (const char *p, const char *end)
517 : {
518 0 : while (p < end && _cairo_isspace(*p))
519 0 : p++;
520 :
521 0 : while (p < end && !_cairo_isspace(*p))
522 0 : p++;
523 :
524 0 : if (p == end)
525 0 : return NULL;
526 :
527 0 : return p;
528 : }
529 :
530 : static int
531 0 : cairo_type1_font_subset_lookup_glyph (cairo_type1_font_subset_t *font,
532 : const char *glyph_name, int length)
533 : {
534 : unsigned int i;
535 :
536 0 : for (i = 0; i < font->base.num_glyphs; i++) {
537 0 : if (font->glyphs[i].name &&
538 0 : strncmp (font->glyphs[i].name, glyph_name, length) == 0 &&
539 0 : font->glyphs[i].name[length] == '\0')
540 0 : return i;
541 : }
542 :
543 0 : return -1;
544 : }
545 :
546 : static cairo_status_t
547 0 : cairo_type1_font_subset_get_glyph_names_and_widths (cairo_type1_font_subset_t *font)
548 : {
549 : unsigned int i;
550 : char buffer[256];
551 : FT_Error error;
552 :
553 : /* Get glyph names and width using the freetype API */
554 0 : for (i = 0; i < font->base.num_glyphs; i++) {
555 0 : if (font->glyphs[i].name != NULL)
556 0 : continue;
557 :
558 0 : error = FT_Load_Glyph (font->face, i,
559 : FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING |
560 : FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM);
561 0 : if (error != FT_Err_Ok) {
562 : /* propagate fatal errors from FreeType */
563 0 : if (error == FT_Err_Out_Of_Memory)
564 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
565 :
566 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
567 : }
568 :
569 0 : font->glyphs[i].width = font->face->glyph->metrics.horiAdvance / (double)font->face->units_per_EM;
570 :
571 0 : error = FT_Get_Glyph_Name(font->face, i, buffer, sizeof buffer);
572 0 : if (error != FT_Err_Ok) {
573 : /* propagate fatal errors from FreeType */
574 0 : if (error == FT_Err_Out_Of_Memory)
575 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
576 :
577 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
578 : }
579 :
580 0 : font->glyphs[i].name = strdup (buffer);
581 0 : if (unlikely (font->glyphs[i].name == NULL))
582 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
583 : }
584 :
585 0 : return CAIRO_STATUS_SUCCESS;
586 : }
587 :
588 : static void
589 0 : cairo_type1_font_subset_decrypt_charstring (const unsigned char *in, int size, unsigned char *out)
590 : {
591 0 : unsigned short r = CAIRO_TYPE1_CHARSTRING_KEY;
592 : int c, p, i;
593 :
594 0 : for (i = 0; i < size; i++) {
595 0 : c = *in++;
596 0 : p = c ^ (r >> 8);
597 0 : r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2;
598 0 : *out++ = p;
599 : }
600 0 : }
601 :
602 : static const unsigned char *
603 0 : cairo_type1_font_subset_decode_integer (const unsigned char *p, int *integer)
604 : {
605 0 : if (*p <= 246) {
606 0 : *integer = *p++ - 139;
607 0 : } else if (*p <= 250) {
608 0 : *integer = (p[0] - 247) * 256 + p[1] + 108;
609 0 : p += 2;
610 0 : } else if (*p <= 254) {
611 0 : *integer = -(p[0] - 251) * 256 - p[1] - 108;
612 0 : p += 2;
613 : } else {
614 0 : *integer = (p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4];
615 0 : p += 5;
616 : }
617 :
618 0 : return p;
619 : }
620 :
621 : #if 0
622 : /*
623 : * The two tables that follow are generated using this perl code:
624 : */
625 :
626 : @encoding = (
627 : /* 0 */
628 : NULL, NULL, NULL, NULL,
629 : NULL, NULL, NULL, NULL,
630 : NULL, NULL, NULL, NULL,
631 : NULL, NULL, NULL, NULL,
632 : /* 16 */
633 : NULL, NULL, NULL, NULL,
634 : NULL, NULL, NULL, NULL,
635 : NULL, NULL, NULL, NULL,
636 : NULL, NULL, NULL, NULL,
637 : /* 32 */
638 : "space", "exclam", "quotedbl", "numbersign",
639 : "dollar", "percent", "ampersand", "quoteright",
640 : "parenleft", "parenright", "asterisk", "plus",
641 : "comma", "hyphen", "period", "slash",
642 : /* 48 */
643 : "zero", "one", "two", "three",
644 : "four", "five", "six", "seven",
645 : "eight", "nine", "colon", "semicolon",
646 : "less", "equal", "greater", "question",
647 : /* 64 */
648 : "at", "A", "B", "C",
649 : "D", "E", "F", "G",
650 : "H", "I", "J", "K",
651 : "L", "M", "N", "O",
652 : /* 80 */
653 : "P", "Q", "R", "S",
654 : "T", "U", "V", "W",
655 : "X", "Y", "Z", "bracketleft",
656 : "backslash", "bracketright", "asciicircum", "underscore",
657 : /* 96 */
658 : "quoteleft", "a", "b", "c",
659 : "d", "e", "f", "g",
660 : "h", "i", "j", "k",
661 : "l", "m", "n", "o",
662 : /* 112 */
663 : "p", "q", "r", "s",
664 : "t", "u", "v", "w",
665 : "x", "y", "z", "braceleft",
666 : "bar", "braceright", "asciitilde", NULL,
667 : /* 128 */
668 : NULL, NULL, NULL, NULL,
669 : NULL, NULL, NULL, NULL,
670 : NULL, NULL, NULL, NULL,
671 : NULL, NULL, NULL, NULL,
672 : /* 144 */
673 : NULL, NULL, NULL, NULL,
674 : NULL, NULL, NULL, NULL,
675 : NULL, NULL, NULL, NULL,
676 : NULL, NULL, NULL, NULL,
677 : /* 160 */
678 : NULL, "exclamdown", "cent", "sterling",
679 : "fraction", "yen", "florin", "section",
680 : "currency", "quotesingle", "quotedblleft", "guillemotleft",
681 : "guilsinglleft","guilsinglright","fi", "fl",
682 : /* 176 */
683 : NULL, "endash", "dagger", "daggerdbl",
684 : "periodcentered",NULL, "paragraph", "bullet",
685 : "quotesinglbase","quotedblbase","quotedblright","guillemotright",
686 : "ellipsis", "perthousand", NULL, "questiondown",
687 : /* 192 */
688 : NULL, "grave", "acute", "circumflex",
689 : "tilde", "macron", "breve", "dotaccent",
690 : "dieresis", NULL, "ring", "cedilla",
691 : NULL, "hungarumlaut", "ogonek", "caron",
692 : /* 208 */
693 : "emdash", NULL, NULL, NULL,
694 : NULL, NULL, NULL, NULL,
695 : NULL, NULL, NULL, NULL,
696 : NULL, NULL, NULL, NULL,
697 : /* 224 */
698 : NULL, "AE", NULL, "ordfeminine",
699 : NULL, NULL, NULL, NULL,
700 : "Lslash", "Oslash", "OE", "ordmasculine",
701 : NULL, NULL, NULL, NULL,
702 : /* 240 */
703 : NULL, "ae", NULL, NULL,
704 : NULL, "dotlessi", NULL, NULL,
705 : "lslash", "oslash", "oe", "germandbls",
706 : NULL, NULL, NULL, NULL
707 : );
708 :
709 : print "static const char ps_standard_encoding_symbol[] = {\n";
710 : $s = qq( "\\0");
711 : for $sym (@encoding) {
712 : if (! ($sym eq NULL)) {
713 : $ss = qq( "$sym\\0");
714 : if (length($s) + length($ss) > 78) {
715 : print qq( $s\n);
716 : $s = "";
717 : }
718 : $s .= $ss;
719 : }
720 : }
721 : print qq( $s\n);
722 : print "};\n\n";
723 : print "static const int16_t ps_standard_encoding_offset[256] = {\n";
724 : $offset = 1;
725 : $s = qq();
726 : for $sym (@encoding) {
727 : if (! ($sym eq NULL)) {
728 : $ss = qq( $offset/*$sym*/,);
729 : $offset += length($sym) + 1;
730 : } else {
731 : $ss = qq( 0,);
732 : }
733 : if (length($s) + length($ss) > 78) {
734 : print qq( $s\n);
735 : $s = "";
736 : }
737 : $s .= $ss;
738 : }
739 : print qq( $s\n);
740 : print "};\n";
741 : exit;
742 : #endif
743 :
744 : static const char ps_standard_encoding_symbol[] = {
745 : "\0" "space\0" "exclam\0" "quotedbl\0" "numbersign\0" "dollar\0" "percent\0"
746 : "ampersand\0" "quoteright\0" "parenleft\0" "parenright\0" "asterisk\0"
747 : "plus\0" "comma\0" "hyphen\0" "period\0" "slash\0" "zero\0" "one\0" "two\0"
748 : "three\0" "four\0" "five\0" "six\0" "seven\0" "eight\0" "nine\0" "colon\0"
749 : "semicolon\0" "less\0" "equal\0" "greater\0" "question\0" "at\0" "A\0" "B\0"
750 : "C\0" "D\0" "E\0" "F\0" "G\0" "H\0" "I\0" "J\0" "K\0" "L\0" "M\0" "N\0" "O\0"
751 : "P\0" "Q\0" "R\0" "S\0" "T\0" "U\0" "V\0" "W\0" "X\0" "Y\0" "Z\0"
752 : "bracketleft\0" "backslash\0" "bracketright\0" "asciicircum\0" "underscore\0"
753 : "quoteleft\0" "a\0" "b\0" "c\0" "d\0" "e\0" "f\0" "g\0" "h\0" "i\0" "j\0"
754 : "k\0" "l\0" "m\0" "n\0" "o\0" "p\0" "q\0" "r\0" "s\0" "t\0" "u\0" "v\0" "w\0"
755 : "x\0" "y\0" "z\0" "braceleft\0" "bar\0" "braceright\0" "asciitilde\0"
756 : "exclamdown\0" "cent\0" "sterling\0" "fraction\0" "yen\0" "florin\0"
757 : "section\0" "currency\0" "quotesingle\0" "quotedblleft\0" "guillemotleft\0"
758 : "guilsinglleft\0" "guilsinglright\0" "fi\0" "fl\0" "endash\0" "dagger\0"
759 : "daggerdbl\0" "periodcentered\0" "paragraph\0" "bullet\0" "quotesinglbase\0"
760 : "quotedblbase\0" "quotedblright\0" "guillemotright\0" "ellipsis\0"
761 : "perthousand\0" "questiondown\0" "grave\0" "acute\0" "circumflex\0" "tilde\0"
762 : "macron\0" "breve\0" "dotaccent\0" "dieresis\0" "ring\0" "cedilla\0"
763 : "hungarumlaut\0" "ogonek\0" "caron\0" "emdash\0" "AE\0" "ordfeminine\0"
764 : "Lslash\0" "Oslash\0" "OE\0" "ordmasculine\0" "ae\0" "dotlessi\0" "lslash\0"
765 : "oslash\0" "oe\0" "germandbls\0"
766 : };
767 :
768 : static const int16_t ps_standard_encoding_offset[256] = {
769 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
770 : 0, 0, 0, 0, 0, 0, 1/*space*/, 7/*exclam*/, 14/*quotedbl*/, 23/*numbersign*/,
771 : 34/*dollar*/, 41/*percent*/, 49/*ampersand*/, 59/*quoteright*/,
772 : 70/*parenleft*/, 80/*parenright*/, 91/*asterisk*/, 100/*plus*/, 105/*comma*/,
773 : 111/*hyphen*/, 118/*period*/, 125/*slash*/, 131/*zero*/, 136/*one*/,
774 : 140/*two*/, 144/*three*/, 150/*four*/, 155/*five*/, 160/*six*/, 164/*seven*/,
775 : 170/*eight*/, 176/*nine*/, 181/*colon*/, 187/*semicolon*/, 197/*less*/,
776 : 202/*equal*/, 208/*greater*/, 216/*question*/, 225/*at*/, 228/*A*/, 230/*B*/,
777 : 232/*C*/, 234/*D*/, 236/*E*/, 238/*F*/, 240/*G*/, 242/*H*/, 244/*I*/,
778 : 246/*J*/, 248/*K*/, 250/*L*/, 252/*M*/, 254/*N*/, 256/*O*/, 258/*P*/,
779 : 260/*Q*/, 262/*R*/, 264/*S*/, 266/*T*/, 268/*U*/, 270/*V*/, 272/*W*/,
780 : 274/*X*/, 276/*Y*/, 278/*Z*/, 280/*bracketleft*/, 292/*backslash*/,
781 : 302/*bracketright*/, 315/*asciicircum*/, 327/*underscore*/, 338/*quoteleft*/,
782 : 348/*a*/, 350/*b*/, 352/*c*/, 354/*d*/, 356/*e*/, 358/*f*/, 360/*g*/,
783 : 362/*h*/, 364/*i*/, 366/*j*/, 368/*k*/, 370/*l*/, 372/*m*/, 374/*n*/,
784 : 376/*o*/, 378/*p*/, 380/*q*/, 382/*r*/, 384/*s*/, 386/*t*/, 388/*u*/,
785 : 390/*v*/, 392/*w*/, 394/*x*/, 396/*y*/, 398/*z*/, 400/*braceleft*/,
786 : 410/*bar*/, 414/*braceright*/, 425/*asciitilde*/, 0, 0, 0, 0, 0, 0, 0, 0, 0,
787 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
788 : 436/*exclamdown*/, 447/*cent*/, 452/*sterling*/, 461/*fraction*/, 470/*yen*/,
789 : 474/*florin*/, 481/*section*/, 489/*currency*/, 498/*quotesingle*/,
790 : 510/*quotedblleft*/, 523/*guillemotleft*/, 537/*guilsinglleft*/,
791 : 551/*guilsinglright*/, 566/*fi*/, 569/*fl*/, 0, 572/*endash*/, 579/*dagger*/,
792 : 586/*daggerdbl*/, 596/*periodcentered*/, 0, 611/*paragraph*/, 621/*bullet*/,
793 : 628/*quotesinglbase*/, 643/*quotedblbase*/, 656/*quotedblright*/,
794 : 670/*guillemotright*/, 685/*ellipsis*/, 694/*perthousand*/, 0,
795 : 706/*questiondown*/, 0, 719/*grave*/, 725/*acute*/, 731/*circumflex*/,
796 : 742/*tilde*/, 748/*macron*/, 755/*breve*/, 761/*dotaccent*/, 771/*dieresis*/,
797 : 0, 780/*ring*/, 785/*cedilla*/, 0, 793/*hungarumlaut*/, 806/*ogonek*/,
798 : 813/*caron*/, 819/*emdash*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
799 : 826/*AE*/, 0, 829/*ordfeminine*/, 0, 0, 0, 0, 841/*Lslash*/, 848/*Oslash*/,
800 : 855/*OE*/, 858/*ordmasculine*/, 0, 0, 0, 0, 0, 871/*ae*/, 0, 0, 0,
801 : 874/*dotlessi*/, 0, 0, 883/*lslash*/, 890/*oslash*/, 897/*oe*/,
802 : 900/*germandbls*/, 0, 0, 0, 0,
803 : };
804 :
805 : #define ps_standard_encoding(index) ((index) ? ps_standard_encoding_symbol+ps_standard_encoding_offset[(index)] : NULL)
806 :
807 : static cairo_status_t
808 0 : use_standard_encoding_glyph (cairo_type1_font_subset_t *font, int index)
809 : {
810 : const char *glyph_name;
811 :
812 0 : if (index < 0 || index > 255)
813 0 : return CAIRO_STATUS_SUCCESS;
814 :
815 0 : glyph_name = ps_standard_encoding(index);
816 0 : if (glyph_name == NULL)
817 0 : return CAIRO_STATUS_SUCCESS;
818 :
819 0 : index = cairo_type1_font_subset_lookup_glyph (font,
820 : glyph_name,
821 0 : strlen(glyph_name));
822 0 : if (index < 0)
823 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
824 :
825 0 : cairo_type1_font_subset_use_glyph (font, index);
826 :
827 0 : return CAIRO_STATUS_SUCCESS;
828 : }
829 :
830 : #define TYPE1_CHARSTRING_COMMAND_ESCAPE (12)
831 : #define TYPE1_CHARSTRING_COMMAND_SEAC (32 + 6)
832 :
833 : static cairo_status_t
834 0 : cairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font,
835 : const char *name, int name_length,
836 : const char *encrypted_charstring, int encrypted_charstring_length)
837 : {
838 : cairo_status_t status;
839 : unsigned char *charstring;
840 : const unsigned char *end;
841 : const unsigned char *p;
842 : int stack[5], sp, value;
843 : int command;
844 :
845 0 : charstring = malloc (encrypted_charstring_length);
846 0 : if (unlikely (charstring == NULL))
847 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
848 :
849 0 : cairo_type1_font_subset_decrypt_charstring ((const unsigned char *)
850 : encrypted_charstring,
851 : encrypted_charstring_length,
852 : charstring);
853 0 : end = charstring + encrypted_charstring_length;
854 :
855 0 : p = charstring + 4;
856 0 : sp = 0;
857 :
858 0 : while (p < end) {
859 0 : if (*p < 32) {
860 0 : command = *p++;
861 :
862 0 : if (command == TYPE1_CHARSTRING_COMMAND_ESCAPE)
863 0 : command = 32 + *p++;
864 :
865 0 : switch (command) {
866 : case TYPE1_CHARSTRING_COMMAND_SEAC:
867 : /* The seac command takes five integer arguments. The
868 : * last two are glyph indices into the PS standard
869 : * encoding give the names of the glyphs that this
870 : * glyph is composed from. All we need to do is to
871 : * make sure those glyphs are present in the subset
872 : * under their standard names. */
873 0 : status = use_standard_encoding_glyph (font, stack[3]);
874 0 : if (unlikely (status))
875 0 : return status;
876 :
877 0 : status = use_standard_encoding_glyph (font, stack[4]);
878 0 : if (unlikely (status))
879 0 : return status;
880 :
881 0 : sp = 0;
882 0 : break;
883 :
884 : default:
885 0 : sp = 0;
886 0 : break;
887 : }
888 : } else {
889 : /* integer argument */
890 0 : p = cairo_type1_font_subset_decode_integer (p, &value);
891 0 : if (sp < 5)
892 0 : stack[sp++] = value;
893 : }
894 : }
895 :
896 0 : free (charstring);
897 :
898 0 : return CAIRO_STATUS_SUCCESS;
899 : }
900 :
901 : static cairo_status_t
902 0 : write_used_glyphs (cairo_type1_font_subset_t *font,
903 : const char *name, int name_length,
904 : const char *charstring, int charstring_length)
905 : {
906 : cairo_status_t status;
907 : char buffer[256];
908 : int length;
909 :
910 0 : length = snprintf (buffer, sizeof buffer,
911 : "/%.*s %d %s ",
912 : name_length, name, charstring_length, font->rd);
913 0 : status = cairo_type1_font_subset_write_encrypted (font, buffer, length);
914 0 : if (unlikely (status))
915 0 : return status;
916 :
917 0 : status = cairo_type1_font_subset_write_encrypted (font,
918 : charstring,
919 : charstring_length);
920 0 : if (unlikely (status))
921 0 : return status;
922 :
923 0 : length = snprintf (buffer, sizeof buffer, "%s\n", font->nd);
924 0 : status = cairo_type1_font_subset_write_encrypted (font, buffer, length);
925 0 : if (unlikely (status))
926 0 : return status;
927 :
928 0 : return CAIRO_STATUS_SUCCESS;
929 : }
930 :
931 : typedef cairo_status_t (*glyph_func_t) (cairo_type1_font_subset_t *font,
932 : const char *name, int name_length,
933 : const char *charstring, int charstring_length);
934 :
935 : static cairo_status_t
936 0 : cairo_type1_font_subset_for_each_glyph (cairo_type1_font_subset_t *font,
937 : const char *dict_start,
938 : const char *dict_end,
939 : glyph_func_t func,
940 : const char **dict_out)
941 : {
942 : int charstring_length, name_length, glyph_index;
943 : const char *p, *charstring, *name;
944 : char *end;
945 :
946 : /* We're looking at '/' in the name of the first glyph. The glyph
947 : * definitions are on the form:
948 : *
949 : * /name 23 RD <23 binary bytes> ND
950 : *
951 : * or alternatively using -| and |- instead of RD and ND.
952 : *
953 : * We parse the glyph name and see if it is in the subset. If it
954 : * is, we call the specified callback with the glyph name and
955 : * glyph data, otherwise we just skip it. We need to parse
956 : * through a glyph definition; we can't just find the next '/',
957 : * since the binary data could contain a '/'.
958 : */
959 :
960 0 : p = dict_start;
961 :
962 0 : while (*p == '/') {
963 0 : name = p + 1;
964 0 : p = skip_token (p, dict_end);
965 0 : name_length = p - name;
966 :
967 0 : charstring_length = strtol (p, &end, 10);
968 0 : if (p == end)
969 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
970 :
971 : /* Skip past -| or RD to binary data. There is exactly one space
972 : * between the -| or RD token and the encrypted data, thus '+ 1'. */
973 0 : charstring = skip_token (end, dict_end) + 1;
974 :
975 : /* Skip binary data and |- or ND token. */
976 0 : p = skip_token (charstring + charstring_length, dict_end);
977 0 : while (p < dict_end && _cairo_isspace(*p))
978 0 : p++;
979 :
980 : /* In case any of the skip_token() calls above reached EOF, p will
981 : * be equal to dict_end. */
982 0 : if (p == dict_end)
983 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
984 :
985 0 : glyph_index = cairo_type1_font_subset_lookup_glyph (font,
986 : name, name_length);
987 0 : if (font->glyphs[glyph_index].subset_index >= 0) {
988 0 : cairo_status_t status = func (font,
989 : name, name_length,
990 : charstring, charstring_length);
991 0 : if (unlikely (status))
992 0 : return status;
993 : }
994 : }
995 :
996 0 : *dict_out = p;
997 :
998 0 : return CAIRO_STATUS_SUCCESS;
999 : }
1000 :
1001 :
1002 : static cairo_status_t
1003 0 : cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
1004 : const char *name)
1005 : {
1006 : cairo_status_t status;
1007 : const char *p, *charstrings, *dict_start;
1008 : const char *closefile_token;
1009 : char buffer[32], *glyph_count_end;
1010 : int num_charstrings, length;
1011 :
1012 : /* The private dict holds hint information, common subroutines and
1013 : * the actual glyph definitions (charstrings).
1014 : *
1015 : * FIXME: update this comment.
1016 : *
1017 : * What we do here is scan directly the /CharString token, which
1018 : * marks the beginning of the glyph definitions. Then we parse
1019 : * through the glyph definitions and weed out the glyphs not in
1020 : * our subset. Everything else before and after the glyph
1021 : * definitions is copied verbatim to the output. It might be
1022 : * worthwile to figure out which of the common subroutines are
1023 : * used by the glyphs in the subset and get rid of the rest. */
1024 :
1025 : /* FIXME: The /Subrs array contains binary data and could
1026 : * conceivably have "/CharStrings" in it, so we might need to skip
1027 : * this more cleverly. */
1028 0 : charstrings = find_token (font->cleartext, font->cleartext_end, "/CharStrings");
1029 0 : if (charstrings == NULL)
1030 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1031 :
1032 : /* Scan past /CharStrings and the integer following it. */
1033 0 : p = charstrings + strlen ("/CharStrings");
1034 0 : num_charstrings = strtol (p, &glyph_count_end, 10);
1035 0 : if (p == glyph_count_end)
1036 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1037 :
1038 : /* Look for a '/' which marks the beginning of the first glyph
1039 : * definition. */
1040 0 : for (p = glyph_count_end; p < font->cleartext_end; p++)
1041 0 : if (*p == '/')
1042 0 : break;
1043 0 : if (p == font->cleartext_end)
1044 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1045 0 : dict_start = p;
1046 :
1047 0 : status = cairo_type1_font_subset_get_glyph_names_and_widths (font);
1048 0 : if (unlikely (status))
1049 0 : return status;
1050 :
1051 : /* Now that we have the private dictionary broken down in
1052 : * sections, do the first pass through the glyph definitions to
1053 : * figure out which subrs and othersubrs are use and which extra
1054 : * glyphs may be required by the seac operator. */
1055 0 : status = cairo_type1_font_subset_for_each_glyph (font,
1056 : dict_start,
1057 0 : font->cleartext_end,
1058 : cairo_type1_font_subset_look_for_seac,
1059 : &p);
1060 0 : if (unlikely (status))
1061 0 : return status;
1062 :
1063 0 : closefile_token = find_token (p, font->cleartext_end, "closefile");
1064 0 : if (closefile_token == NULL)
1065 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1066 :
1067 0 : status = cairo_type1_font_subset_get_glyph_names_and_widths (font);
1068 0 : if (unlikely (status))
1069 0 : return status;
1070 :
1071 : /* We're ready to start outputting. First write the header,
1072 : * i.e. the public part of the font dict.*/
1073 0 : status = cairo_type1_font_subset_write_header (font, name);
1074 0 : if (unlikely (status))
1075 0 : return status;
1076 :
1077 0 : font->base.header_size = _cairo_output_stream_get_position (font->output);
1078 :
1079 :
1080 : /* Start outputting the private dict. First output everything up
1081 : * to the /CharStrings token. */
1082 0 : status = cairo_type1_font_subset_write_encrypted (font, font->cleartext,
1083 0 : charstrings - font->cleartext);
1084 0 : if (unlikely (status))
1085 0 : return status;
1086 :
1087 : /* Write out new charstring count */
1088 0 : length = snprintf (buffer, sizeof buffer,
1089 : "/CharStrings %d", font->num_glyphs);
1090 0 : status = cairo_type1_font_subset_write_encrypted (font, buffer, length);
1091 0 : if (unlikely (status))
1092 0 : return status;
1093 :
1094 : /* Write out text between the charstring count and the first
1095 : * charstring definition */
1096 0 : status = cairo_type1_font_subset_write_encrypted (font, glyph_count_end,
1097 0 : dict_start - glyph_count_end);
1098 0 : if (unlikely (status))
1099 0 : return status;
1100 :
1101 : /* Write out the charstring definitions for each of the glyphs in
1102 : * the subset. */
1103 0 : status = cairo_type1_font_subset_for_each_glyph (font,
1104 : dict_start,
1105 0 : font->cleartext_end,
1106 : write_used_glyphs,
1107 : &p);
1108 0 : if (unlikely (status))
1109 0 : return status;
1110 :
1111 : /* Output what's left between the end of the glyph definitions and
1112 : * the end of the private dict to the output. */
1113 0 : status = cairo_type1_font_subset_write_encrypted (font, p,
1114 0 : closefile_token - p + strlen ("closefile") + 1);
1115 0 : if (unlikely (status))
1116 0 : return status;
1117 :
1118 0 : if (font->hex_encode)
1119 0 : _cairo_output_stream_write (font->output, "\n", 1);
1120 :
1121 0 : return CAIRO_STATUS_SUCCESS;
1122 : }
1123 :
1124 : static cairo_status_t
1125 0 : cairo_type1_font_subset_write_trailer(cairo_type1_font_subset_t *font)
1126 : {
1127 : const char *cleartomark_token;
1128 : int i;
1129 : static const char zeros[65] =
1130 : "0000000000000000000000000000000000000000000000000000000000000000\n";
1131 :
1132 :
1133 0 : for (i = 0; i < 8; i++)
1134 0 : _cairo_output_stream_write (font->output, zeros, sizeof zeros);
1135 :
1136 0 : cleartomark_token = find_token (font->type1_data, font->type1_end, "cleartomark");
1137 0 : if (cleartomark_token) {
1138 : /* Some fonts have conditional save/restore around the entire
1139 : * font dict, so we need to retain whatever postscript code
1140 : * that may come after 'cleartomark'. */
1141 :
1142 0 : _cairo_output_stream_write (font->output, cleartomark_token,
1143 0 : font->type1_end - cleartomark_token);
1144 0 : } else if (!font->eexec_segment_is_ascii) {
1145 : /* Fonts embedded in PDF may omit the fixed-content portion
1146 : * that includes the 'cleartomark' operator. Type 1 in PDF is
1147 : * always binary. */
1148 :
1149 0 : _cairo_output_stream_printf (font->output, "cleartomark");
1150 : } else {
1151 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1152 : }
1153 :
1154 : /* some fonts do not have a newline at the end of the last line */
1155 0 : _cairo_output_stream_printf (font->output, "\n");
1156 :
1157 0 : return CAIRO_STATUS_SUCCESS;
1158 : }
1159 :
1160 : static cairo_status_t
1161 0 : type1_font_write (void *closure, const unsigned char *data, unsigned int length)
1162 : {
1163 0 : cairo_type1_font_subset_t *font = closure;
1164 :
1165 0 : return _cairo_array_append_multiple (&font->contents, data, length);
1166 : }
1167 :
1168 : static cairo_status_t
1169 0 : cairo_type1_font_subset_write (cairo_type1_font_subset_t *font,
1170 : const char *name)
1171 : {
1172 : cairo_status_t status;
1173 :
1174 0 : status = cairo_type1_font_subset_find_segments (font);
1175 0 : if (unlikely (status))
1176 0 : return status;
1177 :
1178 0 : status = cairo_type1_font_subset_decrypt_eexec_segment (font);
1179 0 : if (unlikely (status))
1180 0 : return status;
1181 :
1182 : /* Determine which glyph definition delimiters to use. */
1183 0 : if (find_token (font->cleartext, font->cleartext_end, "/-|") != NULL) {
1184 0 : font->rd = "-|";
1185 0 : font->nd = "|-";
1186 0 : } else if (find_token (font->cleartext, font->cleartext_end, "/RD") != NULL) {
1187 0 : font->rd = "RD";
1188 0 : font->nd = "ND";
1189 : } else {
1190 : /* Don't know *what* kind of font this is... */
1191 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1192 : }
1193 :
1194 0 : font->eexec_key = CAIRO_TYPE1_PRIVATE_DICT_KEY;
1195 0 : font->hex_column = 0;
1196 :
1197 0 : status = cairo_type1_font_subset_write_private_dict (font, name);
1198 0 : if (unlikely (status))
1199 0 : return status;
1200 :
1201 0 : font->base.data_size = _cairo_output_stream_get_position (font->output) -
1202 0 : font->base.header_size;
1203 :
1204 0 : status = cairo_type1_font_subset_write_trailer (font);
1205 0 : if (unlikely (status))
1206 0 : return status;
1207 :
1208 0 : font->base.trailer_size =
1209 0 : _cairo_output_stream_get_position (font->output) -
1210 0 : font->base.header_size - font->base.data_size;
1211 :
1212 0 : return CAIRO_STATUS_SUCCESS;
1213 : }
1214 :
1215 : static cairo_status_t
1216 0 : cairo_type1_font_subset_generate (void *abstract_font,
1217 : const char *name)
1218 :
1219 : {
1220 0 : cairo_type1_font_subset_t *font = abstract_font;
1221 : cairo_ft_unscaled_font_t *ft_unscaled_font;
1222 : unsigned long ret;
1223 : cairo_status_t status;
1224 :
1225 0 : ft_unscaled_font = (cairo_ft_unscaled_font_t *) font->base.unscaled_font;
1226 0 : font->face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font);
1227 0 : if (unlikely (font->face == NULL))
1228 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1229 :
1230 0 : font->type1_length = font->face->stream->size;
1231 0 : font->type1_data = malloc (font->type1_length);
1232 0 : if (unlikely (font->type1_data == NULL)) {
1233 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1234 0 : goto fail;
1235 : }
1236 :
1237 0 : if (font->face->stream->read != NULL) {
1238 : /* Note that read() may be implemented as a macro, thanks POSIX!, so we
1239 : * need to wrap the following usage in parentheses in order to
1240 : * disambiguate it for the pre-processor - using the verbose function
1241 : * pointer dereference for clarity.
1242 : */
1243 0 : ret = (* font->face->stream->read) (font->face->stream, 0,
1244 0 : (unsigned char *) font->type1_data,
1245 0 : font->type1_length);
1246 0 : if (ret != font->type1_length) {
1247 0 : status = _cairo_error (CAIRO_STATUS_READ_ERROR);
1248 0 : goto fail;
1249 : }
1250 : } else {
1251 0 : memcpy (font->type1_data,
1252 0 : font->face->stream->base, font->type1_length);
1253 : }
1254 :
1255 0 : status = _cairo_array_grow_by (&font->contents, 4096);
1256 0 : if (unlikely (status))
1257 0 : goto fail;
1258 :
1259 0 : font->output = _cairo_output_stream_create (type1_font_write, NULL, font);
1260 0 : if (unlikely ((status = font->output->status)))
1261 0 : goto fail;
1262 :
1263 0 : status = cairo_type1_font_subset_write (font, name);
1264 0 : if (unlikely (status))
1265 0 : goto fail;
1266 :
1267 0 : font->base.data = _cairo_array_index (&font->contents, 0);
1268 :
1269 : fail:
1270 0 : _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font);
1271 :
1272 0 : return status;
1273 : }
1274 :
1275 : static cairo_status_t
1276 0 : _cairo_type1_font_subset_fini (cairo_type1_font_subset_t *font)
1277 : {
1278 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
1279 : unsigned int i;
1280 :
1281 : /* If the subset generation failed, some of the pointers below may
1282 : * be NULL depending on at which point the error occurred. */
1283 :
1284 0 : _cairo_array_fini (&font->contents);
1285 :
1286 0 : free (font->type1_data);
1287 0 : if (font->glyphs != NULL) {
1288 0 : for (i = 0; i < font->base.num_glyphs; i++)
1289 0 : free (font->glyphs[i].name);
1290 : }
1291 :
1292 0 : _cairo_unscaled_font_destroy (font->base.unscaled_font);
1293 :
1294 0 : if (font->output != NULL)
1295 0 : status = _cairo_output_stream_destroy (font->output);
1296 :
1297 0 : if (font->base.base_font)
1298 0 : free (font->base.base_font);
1299 0 : free (font->glyphs);
1300 :
1301 0 : return status;
1302 : }
1303 :
1304 : cairo_status_t
1305 0 : _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset,
1306 : const char *name,
1307 : cairo_scaled_font_subset_t *scaled_font_subset,
1308 : cairo_bool_t hex_encode)
1309 : {
1310 : cairo_type1_font_subset_t font;
1311 : cairo_status_t status, status_ignored;
1312 : unsigned long parent_glyph, length;
1313 : unsigned int i;
1314 : cairo_unscaled_font_t *unscaled_font;
1315 : char buf[30];
1316 :
1317 : /* XXX: Need to fix this to work with a general cairo_unscaled_font_t. */
1318 0 : if (!_cairo_scaled_font_is_ft (scaled_font_subset->scaled_font))
1319 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1320 :
1321 0 : if (_cairo_ft_scaled_font_is_vertical (scaled_font_subset->scaled_font))
1322 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1323 :
1324 0 : unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font_subset->scaled_font);
1325 :
1326 0 : status = _cairo_type1_font_subset_init (&font, unscaled_font, hex_encode);
1327 0 : if (unlikely (status))
1328 0 : return status;
1329 :
1330 0 : for (i = 0; i < scaled_font_subset->num_glyphs; i++) {
1331 0 : parent_glyph = scaled_font_subset->glyphs[i];
1332 0 : cairo_type1_font_subset_use_glyph (&font, parent_glyph);
1333 : }
1334 :
1335 0 : status = cairo_type1_font_subset_generate (&font, name);
1336 0 : if (unlikely (status))
1337 0 : goto fail1;
1338 :
1339 0 : if (font.base.base_font) {
1340 0 : type1_subset->base_font = strdup (font.base.base_font);
1341 : } else {
1342 0 : snprintf(buf, sizeof (buf), "CairoFont-%u-%u",
1343 : scaled_font_subset->font_id, scaled_font_subset->subset_id);
1344 0 : type1_subset->base_font = strdup (buf);
1345 : }
1346 0 : if (unlikely (type1_subset->base_font == NULL))
1347 0 : goto fail1;
1348 :
1349 0 : type1_subset->widths = calloc (sizeof (double), font.num_glyphs);
1350 0 : if (unlikely (type1_subset->widths == NULL))
1351 0 : goto fail2;
1352 0 : for (i = 0; i < font.base.num_glyphs; i++) {
1353 0 : if (font.glyphs[i].subset_index < 0)
1354 0 : continue;
1355 0 : type1_subset->widths[font.glyphs[i].subset_index] =
1356 0 : font.glyphs[i].width;
1357 : }
1358 :
1359 0 : type1_subset->x_min = font.base.x_min/1000.0;
1360 0 : type1_subset->y_min = font.base.y_min/1000.0;
1361 0 : type1_subset->x_max = font.base.x_max/1000.0;
1362 0 : type1_subset->y_max = font.base.y_max/1000.0;
1363 0 : type1_subset->ascent = font.base.ascent/1000.0;
1364 0 : type1_subset->descent = font.base.descent/1000.0;
1365 :
1366 0 : length = font.base.header_size +
1367 0 : font.base.data_size +
1368 0 : font.base.trailer_size;
1369 0 : type1_subset->data = malloc (length);
1370 0 : if (unlikely (type1_subset->data == NULL))
1371 0 : goto fail3;
1372 :
1373 0 : memcpy (type1_subset->data,
1374 0 : _cairo_array_index (&font.contents, 0), length);
1375 :
1376 0 : type1_subset->header_length = font.base.header_size;
1377 0 : type1_subset->data_length = font.base.data_size;
1378 0 : type1_subset->trailer_length = font.base.trailer_size;
1379 :
1380 0 : return _cairo_type1_font_subset_fini (&font);
1381 :
1382 : fail3:
1383 0 : free (type1_subset->widths);
1384 : fail2:
1385 0 : free (type1_subset->base_font);
1386 : fail1:
1387 0 : status_ignored = _cairo_type1_font_subset_fini (&font);
1388 :
1389 0 : return status;
1390 : }
1391 :
1392 : void
1393 0 : _cairo_type1_subset_fini (cairo_type1_subset_t *subset)
1394 : {
1395 0 : free (subset->base_font);
1396 0 : free (subset->widths);
1397 0 : free (subset->data);
1398 0 : }
1399 :
1400 : cairo_bool_t
1401 0 : _cairo_type1_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font)
1402 : {
1403 : cairo_ft_unscaled_font_t *unscaled;
1404 : FT_Face face;
1405 : PS_FontInfoRec font_info;
1406 0 : cairo_bool_t is_type1 = FALSE;
1407 :
1408 0 : if (!_cairo_scaled_font_is_ft (scaled_font))
1409 0 : return FALSE;
1410 0 : unscaled = (cairo_ft_unscaled_font_t *) _cairo_ft_scaled_font_get_unscaled_font (scaled_font);
1411 0 : face = _cairo_ft_unscaled_font_lock_face (unscaled);
1412 0 : if (!face)
1413 0 : return FALSE;
1414 :
1415 0 : if (FT_Get_PS_Font_Info(face, &font_info) == 0)
1416 0 : is_type1 = TRUE;
1417 :
1418 : /* OpenType/CFF fonts also have a PS_FontInfoRec */
1419 : #if HAVE_FT_LOAD_SFNT_TABLE
1420 0 : if (FT_IS_SFNT (face))
1421 0 : is_type1 = FALSE;
1422 : #endif
1423 :
1424 0 : _cairo_ft_unscaled_font_unlock_face (unscaled);
1425 :
1426 0 : return is_type1;
1427 : }
1428 :
1429 : #endif /* CAIRO_HAS_FT_FONT */
1430 :
1431 : #endif /* CAIRO_HAS_FONT_SUBSET */
|