Line data Source code
1 : /* cairo - a vector graphics library with display and print output
2 : *
3 : * Copyright © 2004 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 : * Adrian Johnson <ajohnson@redneon.com>
35 : */
36 :
37 : /*
38 : * Useful links:
39 : * http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6.html
40 : * http://www.microsoft.com/typography/specs/default.htm
41 : */
42 :
43 : #define _BSD_SOURCE /* for snprintf(), strdup() */
44 : #include "cairoint.h"
45 : #include "cairo-error-private.h"
46 :
47 : #if CAIRO_HAS_FONT_SUBSET
48 :
49 : #include "cairo-scaled-font-subsets-private.h"
50 : #include "cairo-truetype-subset-private.h"
51 :
52 :
53 : typedef struct subset_glyph subset_glyph_t;
54 : struct subset_glyph {
55 : int parent_index;
56 : unsigned long location;
57 : };
58 :
59 : typedef struct _cairo_truetype_font cairo_truetype_font_t;
60 :
61 : typedef struct table table_t;
62 : struct table {
63 : unsigned long tag;
64 : cairo_status_t (*write) (cairo_truetype_font_t *font, unsigned long tag);
65 : int pos; /* position in the font directory */
66 : };
67 :
68 : struct _cairo_truetype_font {
69 :
70 : cairo_scaled_font_subset_t *scaled_font_subset;
71 :
72 : table_t truetype_tables[10];
73 : int num_tables;
74 :
75 : struct {
76 : char *font_name;
77 : char *ps_name;
78 : unsigned int num_glyphs;
79 : int *widths;
80 : long x_min, y_min, x_max, y_max;
81 : long ascent, descent;
82 : int units_per_em;
83 : } base;
84 :
85 : subset_glyph_t *glyphs;
86 : const cairo_scaled_font_backend_t *backend;
87 : int num_glyphs_in_face;
88 : int checksum_index;
89 : cairo_array_t output;
90 : cairo_array_t string_offsets;
91 : unsigned long last_offset;
92 : unsigned long last_boundary;
93 : int *parent_to_subset;
94 : cairo_status_t status;
95 :
96 : };
97 :
98 : /*
99 : * Test that the structs we define for TrueType tables have the
100 : * correct size, ie. they are not padded.
101 : */
102 : #define check(T, S) COMPILE_TIME_ASSERT (sizeof (T) == (S))
103 : check (tt_head_t, 54);
104 : check (tt_hhea_t, 36);
105 : check (tt_maxp_t, 32);
106 : check (tt_name_record_t, 12);
107 : check (tt_name_t, 18);
108 : check (tt_name_t, 18);
109 : check (tt_composite_glyph_t, 16);
110 : check (tt_glyph_data_t, 26);
111 : #undef check
112 :
113 : static cairo_status_t
114 : cairo_truetype_font_use_glyph (cairo_truetype_font_t *font,
115 : unsigned short glyph,
116 : unsigned short *out);
117 :
118 : #define SFNT_VERSION 0x00010000
119 : #define SFNT_STRING_MAX_LENGTH 65535
120 :
121 : static cairo_status_t
122 0 : _cairo_truetype_font_set_error (cairo_truetype_font_t *font,
123 : cairo_status_t status)
124 : {
125 0 : if (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED)
126 0 : return status;
127 :
128 0 : _cairo_status_set_error (&font->status, status);
129 :
130 0 : return _cairo_error (status);
131 : }
132 :
133 : static cairo_status_t
134 0 : _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
135 : cairo_truetype_font_t **font_return)
136 : {
137 : cairo_status_t status;
138 : cairo_truetype_font_t *font;
139 : const cairo_scaled_font_backend_t *backend;
140 : tt_head_t head;
141 : tt_hhea_t hhea;
142 : tt_maxp_t maxp;
143 : unsigned long size;
144 :
145 0 : backend = scaled_font_subset->scaled_font->backend;
146 0 : if (!backend->load_truetype_table)
147 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
148 :
149 : /* FIXME: We should either support subsetting vertical fonts, or fail on
150 : * vertical. Currently font_options_t doesn't have vertical flag, but
151 : * it should be added in the future. For now, the freetype backend
152 : * returns UNSUPPORTED in load_truetype_table if the font is vertical.
153 : *
154 : * if (cairo_font_options_get_vertical_layout (scaled_font_subset->scaled_font))
155 : * return CAIRO_INT_STATUS_UNSUPPORTED;
156 : */
157 :
158 0 : size = sizeof (tt_head_t);
159 0 : status = backend->load_truetype_table (scaled_font_subset->scaled_font,
160 : TT_TAG_head, 0,
161 : (unsigned char *) &head,
162 : &size);
163 0 : if (unlikely (status))
164 0 : return status;
165 :
166 0 : size = sizeof (tt_maxp_t);
167 0 : status = backend->load_truetype_table (scaled_font_subset->scaled_font,
168 : TT_TAG_maxp, 0,
169 : (unsigned char *) &maxp,
170 : &size);
171 0 : if (unlikely (status))
172 0 : return status;
173 :
174 0 : size = sizeof (tt_hhea_t);
175 0 : status = backend->load_truetype_table (scaled_font_subset->scaled_font,
176 : TT_TAG_hhea, 0,
177 : (unsigned char *) &hhea,
178 : &size);
179 0 : if (unlikely (status))
180 0 : return status;
181 :
182 0 : font = malloc (sizeof (cairo_truetype_font_t));
183 0 : if (unlikely (font == NULL))
184 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
185 :
186 0 : font->backend = backend;
187 0 : font->num_glyphs_in_face = be16_to_cpu (maxp.num_glyphs);
188 0 : font->scaled_font_subset = scaled_font_subset;
189 :
190 0 : font->last_offset = 0;
191 0 : font->last_boundary = 0;
192 0 : _cairo_array_init (&font->output, sizeof (char));
193 0 : status = _cairo_array_grow_by (&font->output, 4096);
194 0 : if (unlikely (status))
195 0 : goto fail1;
196 :
197 0 : font->glyphs = calloc (font->num_glyphs_in_face + 1, sizeof (subset_glyph_t));
198 0 : if (unlikely (font->glyphs == NULL)) {
199 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
200 0 : goto fail1;
201 : }
202 :
203 0 : font->parent_to_subset = calloc (font->num_glyphs_in_face, sizeof (int));
204 0 : if (unlikely (font->parent_to_subset == NULL)) {
205 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
206 0 : goto fail2;
207 : }
208 :
209 0 : font->base.num_glyphs = 0;
210 0 : font->base.x_min = (int16_t) be16_to_cpu (head.x_min);
211 0 : font->base.y_min = (int16_t) be16_to_cpu (head.y_min);
212 0 : font->base.x_max = (int16_t) be16_to_cpu (head.x_max);
213 0 : font->base.y_max = (int16_t) be16_to_cpu (head.y_max);
214 0 : font->base.ascent = (int16_t) be16_to_cpu (hhea.ascender);
215 0 : font->base.descent = (int16_t) be16_to_cpu (hhea.descender);
216 0 : font->base.units_per_em = (int16_t) be16_to_cpu (head.units_per_em);
217 0 : if (font->base.units_per_em == 0)
218 0 : font->base.units_per_em = 2048;
219 :
220 0 : font->base.ps_name = NULL;
221 0 : font->base.font_name = NULL;
222 0 : status = _cairo_truetype_read_font_name (scaled_font_subset->scaled_font,
223 : &font->base.ps_name,
224 : &font->base.font_name);
225 0 : if (_cairo_status_is_error (status))
226 0 : goto fail3;
227 :
228 : /* If the PS name is not found, create a CairoFont-x-y name. */
229 0 : if (font->base.ps_name == NULL) {
230 0 : font->base.ps_name = malloc (30);
231 0 : if (unlikely (font->base.ps_name == NULL)) {
232 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
233 0 : goto fail3;
234 : }
235 :
236 0 : snprintf(font->base.ps_name, 30, "CairoFont-%u-%u",
237 : scaled_font_subset->font_id,
238 : scaled_font_subset->subset_id);
239 : }
240 :
241 0 : font->base.widths = calloc (font->num_glyphs_in_face, sizeof (int));
242 0 : if (unlikely (font->base.widths == NULL)) {
243 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
244 0 : goto fail4;
245 : }
246 :
247 0 : _cairo_array_init (&font->string_offsets, sizeof (unsigned long));
248 0 : status = _cairo_array_grow_by (&font->string_offsets, 10);
249 0 : if (unlikely (status))
250 0 : goto fail5;
251 :
252 0 : font->status = CAIRO_STATUS_SUCCESS;
253 :
254 0 : *font_return = font;
255 :
256 0 : return CAIRO_STATUS_SUCCESS;
257 :
258 : fail5:
259 0 : _cairo_array_fini (&font->string_offsets);
260 0 : free (font->base.widths);
261 : fail4:
262 0 : free (font->base.ps_name);
263 : fail3:
264 0 : free (font->parent_to_subset);
265 0 : if (font->base.font_name)
266 0 : free (font->base.font_name);
267 : fail2:
268 0 : free (font->glyphs);
269 : fail1:
270 0 : _cairo_array_fini (&font->output);
271 0 : free (font);
272 :
273 0 : return status;
274 : }
275 :
276 : static void
277 0 : cairo_truetype_font_destroy (cairo_truetype_font_t *font)
278 : {
279 0 : _cairo_array_fini (&font->string_offsets);
280 0 : free (font->base.widths);
281 0 : free (font->base.ps_name);
282 0 : if (font->base.font_name)
283 0 : free (font->base.font_name);
284 0 : free (font->parent_to_subset);
285 0 : free (font->glyphs);
286 0 : _cairo_array_fini (&font->output);
287 0 : free (font);
288 0 : }
289 :
290 : static cairo_status_t
291 0 : cairo_truetype_font_allocate_write_buffer (cairo_truetype_font_t *font,
292 : size_t length,
293 : unsigned char **buffer)
294 : {
295 : cairo_status_t status;
296 :
297 0 : if (font->status)
298 0 : return font->status;
299 :
300 0 : status = _cairo_array_allocate (&font->output, length, (void **) buffer);
301 0 : if (unlikely (status))
302 0 : return _cairo_truetype_font_set_error (font, status);
303 :
304 0 : return CAIRO_STATUS_SUCCESS;
305 : }
306 :
307 : static void
308 0 : cairo_truetype_font_write (cairo_truetype_font_t *font,
309 : const void *data,
310 : size_t length)
311 : {
312 : cairo_status_t status;
313 :
314 0 : if (font->status)
315 0 : return;
316 :
317 0 : status = _cairo_array_append_multiple (&font->output, data, length);
318 0 : if (unlikely (status))
319 0 : status = _cairo_truetype_font_set_error (font, status);
320 : }
321 :
322 : static void
323 0 : cairo_truetype_font_write_be16 (cairo_truetype_font_t *font,
324 : uint16_t value)
325 : {
326 : uint16_t be16_value;
327 :
328 0 : if (font->status)
329 0 : return;
330 :
331 0 : be16_value = cpu_to_be16 (value);
332 0 : cairo_truetype_font_write (font, &be16_value, sizeof be16_value);
333 : }
334 :
335 : static void
336 0 : cairo_truetype_font_write_be32 (cairo_truetype_font_t *font,
337 : uint32_t value)
338 : {
339 : uint32_t be32_value;
340 :
341 0 : if (font->status)
342 0 : return;
343 :
344 0 : be32_value = cpu_to_be32 (value);
345 0 : cairo_truetype_font_write (font, &be32_value, sizeof be32_value);
346 : }
347 :
348 : static cairo_status_t
349 0 : cairo_truetype_font_align_output (cairo_truetype_font_t *font,
350 : unsigned long *aligned)
351 : {
352 : int length, pad;
353 : unsigned char *padding;
354 :
355 0 : length = _cairo_array_num_elements (&font->output);
356 0 : *aligned = (length + 3) & ~3;
357 0 : pad = *aligned - length;
358 :
359 0 : if (pad) {
360 : cairo_status_t status;
361 :
362 0 : status = cairo_truetype_font_allocate_write_buffer (font, pad,
363 : &padding);
364 0 : if (unlikely (status))
365 0 : return status;
366 :
367 0 : memset (padding, 0, pad);
368 : }
369 :
370 0 : return CAIRO_STATUS_SUCCESS;
371 : }
372 :
373 : static cairo_status_t
374 0 : cairo_truetype_font_check_boundary (cairo_truetype_font_t *font,
375 : unsigned long boundary)
376 : {
377 : cairo_status_t status;
378 :
379 0 : if (font->status)
380 0 : return font->status;
381 :
382 0 : if (boundary - font->last_offset > SFNT_STRING_MAX_LENGTH)
383 : {
384 0 : status = _cairo_array_append (&font->string_offsets,
385 0 : &font->last_boundary);
386 0 : if (unlikely (status))
387 0 : return _cairo_truetype_font_set_error (font, status);
388 :
389 0 : font->last_offset = font->last_boundary;
390 : }
391 0 : font->last_boundary = boundary;
392 :
393 0 : return CAIRO_STATUS_SUCCESS;
394 : }
395 :
396 : static cairo_status_t
397 0 : cairo_truetype_font_write_cmap_table (cairo_truetype_font_t *font,
398 : unsigned long tag)
399 : {
400 : unsigned int i;
401 :
402 0 : cairo_truetype_font_write_be16 (font, 0); /* Table version */
403 0 : cairo_truetype_font_write_be16 (font, 2); /* Num tables */
404 :
405 0 : cairo_truetype_font_write_be16 (font, 3); /* Platform */
406 0 : cairo_truetype_font_write_be16 (font, 0); /* Encoding */
407 0 : cairo_truetype_font_write_be32 (font, 20); /* Offset to start of table */
408 :
409 0 : cairo_truetype_font_write_be16 (font, 1); /* Platform */
410 0 : cairo_truetype_font_write_be16 (font, 0); /* Encoding */
411 0 : cairo_truetype_font_write_be32 (font, 52); /* Offset to start of table */
412 :
413 : /* Output a format 4 encoding table. */
414 :
415 0 : cairo_truetype_font_write_be16 (font, 4); /* Format */
416 0 : cairo_truetype_font_write_be16 (font, 32); /* Length */
417 0 : cairo_truetype_font_write_be16 (font, 0); /* Version */
418 0 : cairo_truetype_font_write_be16 (font, 4); /* 2*segcount */
419 0 : cairo_truetype_font_write_be16 (font, 4); /* searchrange */
420 0 : cairo_truetype_font_write_be16 (font, 1); /* entry selector */
421 0 : cairo_truetype_font_write_be16 (font, 0); /* rangeshift */
422 0 : cairo_truetype_font_write_be16 (font, 0xf000 + font->base.num_glyphs - 1); /* end count[0] */
423 0 : cairo_truetype_font_write_be16 (font, 0xffff); /* end count[1] */
424 0 : cairo_truetype_font_write_be16 (font, 0); /* reserved */
425 0 : cairo_truetype_font_write_be16 (font, 0xf000); /* startCode[0] */
426 0 : cairo_truetype_font_write_be16 (font, 0xffff); /* startCode[1] */
427 0 : cairo_truetype_font_write_be16 (font, 0x1000); /* delta[0] */
428 0 : cairo_truetype_font_write_be16 (font, 1); /* delta[1] */
429 0 : cairo_truetype_font_write_be16 (font, 0); /* rangeOffset[0] */
430 0 : cairo_truetype_font_write_be16 (font, 0); /* rangeOffset[1] */
431 :
432 : /* Output a format 6 encoding table. */
433 :
434 0 : cairo_truetype_font_write_be16 (font, 6);
435 0 : cairo_truetype_font_write_be16 (font, 10 + 2 * font->base.num_glyphs);
436 0 : cairo_truetype_font_write_be16 (font, 0);
437 0 : cairo_truetype_font_write_be16 (font, 0); /* First character */
438 0 : cairo_truetype_font_write_be16 (font, font->base.num_glyphs);
439 0 : for (i = 0; i < font->base.num_glyphs; i++)
440 0 : cairo_truetype_font_write_be16 (font, i);
441 :
442 0 : return font->status;
443 : }
444 :
445 : static cairo_status_t
446 0 : cairo_truetype_font_write_generic_table (cairo_truetype_font_t *font,
447 : unsigned long tag)
448 : {
449 : cairo_status_t status;
450 : unsigned char *buffer;
451 : unsigned long size;
452 :
453 0 : if (font->status)
454 0 : return font->status;
455 :
456 0 : size = 0;
457 0 : status = font->backend->load_truetype_table(font->scaled_font_subset->scaled_font,
458 : tag, 0, NULL, &size);
459 0 : if (unlikely (status))
460 0 : return _cairo_truetype_font_set_error (font, status);
461 :
462 0 : status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
463 0 : if (unlikely (status))
464 0 : return _cairo_truetype_font_set_error (font, status);
465 :
466 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
467 : tag, 0, buffer, &size);
468 0 : if (unlikely (status))
469 0 : return _cairo_truetype_font_set_error (font, status);
470 :
471 0 : return CAIRO_STATUS_SUCCESS;
472 : }
473 :
474 : static cairo_status_t
475 0 : cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t *font,
476 : unsigned char *buffer,
477 : unsigned long size)
478 : {
479 : tt_glyph_data_t *glyph_data;
480 : tt_composite_glyph_t *composite_glyph;
481 : int num_args;
482 : int has_more_components;
483 : unsigned short flags;
484 : unsigned short index;
485 : cairo_status_t status;
486 0 : unsigned char *end = buffer + size;
487 :
488 0 : if (font->status)
489 0 : return font->status;
490 :
491 0 : glyph_data = (tt_glyph_data_t *) buffer;
492 0 : if ((unsigned char *)(&glyph_data->data) >= end)
493 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
494 :
495 0 : if ((int16_t)be16_to_cpu (glyph_data->num_contours) >= 0)
496 0 : return CAIRO_STATUS_SUCCESS;
497 :
498 0 : composite_glyph = &glyph_data->glyph;
499 : do {
500 0 : if ((unsigned char *)(&composite_glyph->args[1]) > end)
501 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
502 :
503 0 : flags = be16_to_cpu (composite_glyph->flags);
504 0 : has_more_components = flags & TT_MORE_COMPONENTS;
505 0 : status = cairo_truetype_font_use_glyph (font, be16_to_cpu (composite_glyph->index), &index);
506 0 : if (unlikely (status))
507 0 : return status;
508 :
509 0 : composite_glyph->index = cpu_to_be16 (index);
510 0 : num_args = 1;
511 0 : if (flags & TT_ARG_1_AND_2_ARE_WORDS)
512 0 : num_args += 1;
513 :
514 0 : if (flags & TT_WE_HAVE_A_SCALE)
515 0 : num_args += 1;
516 0 : else if (flags & TT_WE_HAVE_AN_X_AND_Y_SCALE)
517 0 : num_args += 2;
518 0 : else if (flags & TT_WE_HAVE_A_TWO_BY_TWO)
519 0 : num_args += 4;
520 :
521 0 : composite_glyph = (tt_composite_glyph_t *) &(composite_glyph->args[num_args]);
522 0 : } while (has_more_components);
523 :
524 0 : return CAIRO_STATUS_SUCCESS;
525 : }
526 :
527 : static cairo_status_t
528 0 : cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font,
529 : unsigned long tag)
530 : {
531 : unsigned long start_offset, index, size, next;
532 : tt_head_t header;
533 : unsigned long begin, end;
534 : unsigned char *buffer;
535 : unsigned int i;
536 : union {
537 : unsigned char *bytes;
538 : uint16_t *short_offsets;
539 : uint32_t *long_offsets;
540 : } u;
541 : cairo_status_t status;
542 :
543 0 : if (font->status)
544 0 : return font->status;
545 :
546 0 : size = sizeof (tt_head_t);
547 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
548 : TT_TAG_head, 0,
549 : (unsigned char*) &header, &size);
550 0 : if (unlikely (status))
551 0 : return _cairo_truetype_font_set_error (font, status);
552 :
553 0 : if (be16_to_cpu (header.index_to_loc_format) == 0)
554 0 : size = sizeof (int16_t) * (font->num_glyphs_in_face + 1);
555 : else
556 0 : size = sizeof (int32_t) * (font->num_glyphs_in_face + 1);
557 :
558 0 : u.bytes = malloc (size);
559 0 : if (unlikely (u.bytes == NULL))
560 0 : return _cairo_truetype_font_set_error (font, CAIRO_STATUS_NO_MEMORY);
561 :
562 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
563 : TT_TAG_loca, 0, u.bytes, &size);
564 0 : if (unlikely (status))
565 0 : return _cairo_truetype_font_set_error (font, status);
566 :
567 0 : start_offset = _cairo_array_num_elements (&font->output);
568 0 : for (i = 0; i < font->base.num_glyphs; i++) {
569 0 : index = font->glyphs[i].parent_index;
570 0 : if (be16_to_cpu (header.index_to_loc_format) == 0) {
571 0 : begin = be16_to_cpu (u.short_offsets[index]) * 2;
572 0 : end = be16_to_cpu (u.short_offsets[index + 1]) * 2;
573 : }
574 : else {
575 0 : begin = be32_to_cpu (u.long_offsets[index]);
576 0 : end = be32_to_cpu (u.long_offsets[index + 1]);
577 : }
578 :
579 : /* quick sanity check... */
580 0 : if (end < begin) {
581 0 : status = CAIRO_INT_STATUS_UNSUPPORTED;
582 0 : goto FAIL;
583 : }
584 :
585 0 : size = end - begin;
586 0 : status = cairo_truetype_font_align_output (font, &next);
587 0 : if (unlikely (status))
588 0 : goto FAIL;
589 :
590 0 : status = cairo_truetype_font_check_boundary (font, next);
591 0 : if (unlikely (status))
592 0 : goto FAIL;
593 :
594 0 : font->glyphs[i].location = next - start_offset;
595 :
596 0 : status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
597 0 : if (unlikely (status))
598 0 : goto FAIL;
599 :
600 0 : if (size != 0) {
601 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
602 : TT_TAG_glyf, begin, buffer, &size);
603 0 : if (unlikely (status))
604 0 : goto FAIL;
605 :
606 0 : status = cairo_truetype_font_remap_composite_glyph (font, buffer, size);
607 0 : if (unlikely (status))
608 0 : goto FAIL;
609 : }
610 : }
611 :
612 0 : status = cairo_truetype_font_align_output (font, &next);
613 0 : if (unlikely (status))
614 0 : goto FAIL;
615 :
616 0 : font->glyphs[i].location = next - start_offset;
617 :
618 0 : status = font->status;
619 : FAIL:
620 0 : free (u.bytes);
621 :
622 0 : return _cairo_truetype_font_set_error (font, status);
623 : }
624 :
625 : static cairo_status_t
626 0 : cairo_truetype_font_write_head_table (cairo_truetype_font_t *font,
627 : unsigned long tag)
628 : {
629 : unsigned char *buffer;
630 : unsigned long size;
631 : cairo_status_t status;
632 :
633 0 : if (font->status)
634 0 : return font->status;
635 :
636 0 : size = 0;
637 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
638 : tag, 0, NULL, &size);
639 0 : if (unlikely (status))
640 0 : return _cairo_truetype_font_set_error (font, status);
641 :
642 0 : font->checksum_index = _cairo_array_num_elements (&font->output) + 8;
643 0 : status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
644 0 : if (unlikely (status))
645 0 : return _cairo_truetype_font_set_error (font, status);
646 :
647 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
648 : tag, 0, buffer, &size);
649 0 : if (unlikely (status))
650 0 : return _cairo_truetype_font_set_error (font, status);
651 :
652 : /* set checkSumAdjustment to 0 for table checksum calculation */
653 0 : *(uint32_t *)(buffer + 8) = 0;
654 :
655 0 : return CAIRO_STATUS_SUCCESS;
656 : }
657 :
658 : static cairo_status_t
659 0 : cairo_truetype_font_write_hhea_table (cairo_truetype_font_t *font, unsigned long tag)
660 : {
661 : tt_hhea_t *hhea;
662 : unsigned long size;
663 : cairo_status_t status;
664 :
665 0 : if (font->status)
666 0 : return font->status;
667 :
668 0 : size = sizeof (tt_hhea_t);
669 0 : status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &hhea);
670 0 : if (unlikely (status))
671 0 : return _cairo_truetype_font_set_error (font, status);
672 :
673 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
674 : tag, 0, (unsigned char *) hhea, &size);
675 0 : if (unlikely (status))
676 0 : return _cairo_truetype_font_set_error (font, status);
677 :
678 0 : hhea->num_hmetrics = cpu_to_be16 ((uint16_t)(font->base.num_glyphs));
679 :
680 0 : return CAIRO_STATUS_SUCCESS;
681 : }
682 :
683 : static cairo_status_t
684 0 : cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font,
685 : unsigned long tag)
686 : {
687 : unsigned long size;
688 : unsigned long long_entry_size;
689 : unsigned long short_entry_size;
690 : short *p;
691 : unsigned int i;
692 : tt_hhea_t hhea;
693 : int num_hmetrics;
694 : cairo_status_t status;
695 :
696 0 : if (font->status)
697 0 : return font->status;
698 :
699 0 : size = sizeof (tt_hhea_t);
700 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
701 : TT_TAG_hhea, 0,
702 : (unsigned char*) &hhea, &size);
703 0 : if (unlikely (status))
704 0 : return _cairo_truetype_font_set_error (font, status);
705 :
706 0 : num_hmetrics = be16_to_cpu(hhea.num_hmetrics);
707 :
708 0 : for (i = 0; i < font->base.num_glyphs; i++) {
709 0 : long_entry_size = 2 * sizeof (int16_t);
710 0 : short_entry_size = sizeof (int16_t);
711 0 : status = cairo_truetype_font_allocate_write_buffer (font,
712 : long_entry_size,
713 : (unsigned char **) &p);
714 0 : if (unlikely (status))
715 0 : return _cairo_truetype_font_set_error (font, status);
716 :
717 0 : if (font->glyphs[i].parent_index < num_hmetrics) {
718 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
719 : TT_TAG_hmtx,
720 0 : font->glyphs[i].parent_index * long_entry_size,
721 : (unsigned char *) p, &long_entry_size);
722 0 : if (unlikely (status))
723 0 : return _cairo_truetype_font_set_error (font, status);
724 : }
725 : else
726 : {
727 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
728 : TT_TAG_hmtx,
729 0 : (num_hmetrics - 1) * long_entry_size,
730 : (unsigned char *) p, &short_entry_size);
731 0 : if (unlikely (status))
732 0 : return _cairo_truetype_font_set_error (font, status);
733 :
734 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
735 : TT_TAG_hmtx,
736 0 : num_hmetrics * long_entry_size +
737 0 : (font->glyphs[i].parent_index - num_hmetrics) * short_entry_size,
738 0 : (unsigned char *) (p + 1), &short_entry_size);
739 0 : if (unlikely (status))
740 0 : return _cairo_truetype_font_set_error (font, status);
741 : }
742 0 : font->base.widths[i] = be16_to_cpu (p[0]);
743 : }
744 :
745 0 : return CAIRO_STATUS_SUCCESS;
746 : }
747 :
748 : static cairo_status_t
749 0 : cairo_truetype_font_write_loca_table (cairo_truetype_font_t *font,
750 : unsigned long tag)
751 : {
752 : unsigned int i;
753 : tt_head_t header;
754 : unsigned long size;
755 : cairo_status_t status;
756 :
757 0 : if (font->status)
758 0 : return font->status;
759 :
760 0 : size = sizeof(tt_head_t);
761 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
762 : TT_TAG_head, 0,
763 : (unsigned char*) &header, &size);
764 0 : if (unlikely (status))
765 0 : return _cairo_truetype_font_set_error (font, status);
766 :
767 0 : if (be16_to_cpu (header.index_to_loc_format) == 0)
768 : {
769 0 : for (i = 0; i < font->base.num_glyphs + 1; i++)
770 0 : cairo_truetype_font_write_be16 (font, font->glyphs[i].location / 2);
771 : } else {
772 0 : for (i = 0; i < font->base.num_glyphs + 1; i++)
773 0 : cairo_truetype_font_write_be32 (font, font->glyphs[i].location);
774 : }
775 :
776 0 : return font->status;
777 : }
778 :
779 : static cairo_status_t
780 0 : cairo_truetype_font_write_maxp_table (cairo_truetype_font_t *font,
781 : unsigned long tag)
782 : {
783 : tt_maxp_t *maxp;
784 : unsigned long size;
785 : cairo_status_t status;
786 :
787 0 : if (font->status)
788 0 : return font->status;
789 :
790 0 : size = sizeof (tt_maxp_t);
791 0 : status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &maxp);
792 0 : if (unlikely (status))
793 0 : return _cairo_truetype_font_set_error (font, status);
794 :
795 0 : status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
796 : tag, 0, (unsigned char *) maxp, &size);
797 0 : if (unlikely (status))
798 0 : return _cairo_truetype_font_set_error (font, status);
799 :
800 0 : maxp->num_glyphs = cpu_to_be16 (font->base.num_glyphs);
801 :
802 0 : return CAIRO_STATUS_SUCCESS;
803 : }
804 :
805 : static cairo_status_t
806 0 : cairo_truetype_font_write_offset_table (cairo_truetype_font_t *font)
807 : {
808 : cairo_status_t status;
809 : unsigned char *table_buffer;
810 : size_t table_buffer_length;
811 : unsigned short search_range, entry_selector, range_shift;
812 :
813 0 : if (font->status)
814 0 : return font->status;
815 :
816 0 : search_range = 1;
817 0 : entry_selector = 0;
818 0 : while (search_range * 2 <= font->num_tables) {
819 0 : search_range *= 2;
820 0 : entry_selector++;
821 : }
822 0 : search_range *= 16;
823 0 : range_shift = font->num_tables * 16 - search_range;
824 :
825 0 : cairo_truetype_font_write_be32 (font, SFNT_VERSION);
826 0 : cairo_truetype_font_write_be16 (font, font->num_tables);
827 0 : cairo_truetype_font_write_be16 (font, search_range);
828 0 : cairo_truetype_font_write_be16 (font, entry_selector);
829 0 : cairo_truetype_font_write_be16 (font, range_shift);
830 :
831 : /* Allocate space for the table directory. Each directory entry
832 : * will be filled in by cairo_truetype_font_update_entry() after
833 : * the table is written. */
834 0 : table_buffer_length = font->num_tables * 16;
835 0 : status = cairo_truetype_font_allocate_write_buffer (font, table_buffer_length,
836 : &table_buffer);
837 0 : if (unlikely (status))
838 0 : return _cairo_truetype_font_set_error (font, status);
839 :
840 0 : return CAIRO_STATUS_SUCCESS;
841 : }
842 :
843 : static uint32_t
844 0 : cairo_truetype_font_calculate_checksum (cairo_truetype_font_t *font,
845 : unsigned long start,
846 : unsigned long end)
847 : {
848 : uint32_t *padded_end;
849 : uint32_t *p;
850 : uint32_t checksum;
851 : char *data;
852 :
853 0 : checksum = 0;
854 0 : data = _cairo_array_index (&font->output, 0);
855 0 : p = (uint32_t *) (data + start);
856 0 : padded_end = (uint32_t *) (data + ((end + 3) & ~3));
857 0 : while (p < padded_end)
858 0 : checksum += be32_to_cpu(*p++);
859 :
860 0 : return checksum;
861 : }
862 :
863 : static void
864 0 : cairo_truetype_font_update_entry (cairo_truetype_font_t *font,
865 : int index,
866 : unsigned long tag,
867 : unsigned long start,
868 : unsigned long end)
869 : {
870 : uint32_t *entry;
871 :
872 0 : entry = _cairo_array_index (&font->output, 12 + 16 * index);
873 0 : entry[0] = cpu_to_be32 ((uint32_t)tag);
874 0 : entry[1] = cpu_to_be32 (cairo_truetype_font_calculate_checksum (font, start, end));
875 0 : entry[2] = cpu_to_be32 ((uint32_t)start);
876 0 : entry[3] = cpu_to_be32 ((uint32_t)(end - start));
877 0 : }
878 :
879 : static cairo_status_t
880 0 : cairo_truetype_font_generate (cairo_truetype_font_t *font,
881 : const char **data,
882 : unsigned long *length,
883 : const unsigned long **string_offsets,
884 : unsigned long *num_strings)
885 : {
886 : cairo_status_t status;
887 : unsigned long start, end, next;
888 : uint32_t checksum, *checksum_location;
889 : int i;
890 :
891 0 : if (font->status)
892 0 : return font->status;
893 :
894 0 : status = cairo_truetype_font_write_offset_table (font);
895 0 : if (unlikely (status))
896 0 : goto FAIL;
897 :
898 0 : status = cairo_truetype_font_align_output (font, &start);
899 0 : if (unlikely (status))
900 0 : goto FAIL;
901 :
902 0 : end = 0;
903 0 : for (i = 0; i < font->num_tables; i++) {
904 0 : status = font->truetype_tables[i].write (font, font->truetype_tables[i].tag);
905 0 : if (unlikely (status))
906 0 : goto FAIL;
907 :
908 0 : end = _cairo_array_num_elements (&font->output);
909 0 : status = cairo_truetype_font_align_output (font, &next);
910 0 : if (unlikely (status))
911 0 : goto FAIL;
912 :
913 0 : cairo_truetype_font_update_entry (font, font->truetype_tables[i].pos,
914 : font->truetype_tables[i].tag, start, end);
915 0 : status = cairo_truetype_font_check_boundary (font, next);
916 0 : if (unlikely (status))
917 0 : goto FAIL;
918 :
919 0 : start = next;
920 : }
921 :
922 0 : checksum =
923 0 : 0xb1b0afba - cairo_truetype_font_calculate_checksum (font, 0, end);
924 0 : checksum_location = _cairo_array_index (&font->output, font->checksum_index);
925 0 : *checksum_location = cpu_to_be32 (checksum);
926 :
927 0 : *data = _cairo_array_index (&font->output, 0);
928 0 : *length = _cairo_array_num_elements (&font->output);
929 0 : *num_strings = _cairo_array_num_elements (&font->string_offsets);
930 0 : if (*num_strings != 0)
931 0 : *string_offsets = _cairo_array_index (&font->string_offsets, 0);
932 : else
933 0 : *string_offsets = NULL;
934 :
935 : FAIL:
936 0 : return _cairo_truetype_font_set_error (font, status);
937 : }
938 :
939 : static cairo_status_t
940 0 : cairo_truetype_font_use_glyph (cairo_truetype_font_t *font,
941 : unsigned short glyph,
942 : unsigned short *out)
943 : {
944 0 : if (glyph >= font->num_glyphs_in_face)
945 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
946 :
947 0 : if (font->parent_to_subset[glyph] == 0) {
948 0 : font->parent_to_subset[glyph] = font->base.num_glyphs;
949 0 : font->glyphs[font->base.num_glyphs].parent_index = glyph;
950 0 : font->base.num_glyphs++;
951 : }
952 :
953 0 : *out = font->parent_to_subset[glyph];
954 0 : return CAIRO_STATUS_SUCCESS;
955 : }
956 :
957 : static void
958 0 : cairo_truetype_font_add_truetype_table (cairo_truetype_font_t *font,
959 : unsigned long tag,
960 : cairo_status_t (*write) (cairo_truetype_font_t *font, unsigned long tag),
961 : int pos)
962 : {
963 0 : font->truetype_tables[font->num_tables].tag = tag;
964 0 : font->truetype_tables[font->num_tables].write = write;
965 0 : font->truetype_tables[font->num_tables].pos = pos;
966 0 : font->num_tables++;
967 0 : }
968 :
969 : /* cairo_truetype_font_create_truetype_table_list() builds the list of
970 : * truetype tables to be embedded in the subsetted font. Each call to
971 : * cairo_truetype_font_add_truetype_table() adds a table, the callback
972 : * for generating the table, and the position in the table directory
973 : * to the truetype_tables array.
974 : *
975 : * As we write out the glyf table we remap composite glyphs.
976 : * Remapping composite glyphs will reference the sub glyphs the
977 : * composite glyph is made up of. The "glyf" table callback needs to
978 : * be called first so we have all the glyphs in the subset before
979 : * going further.
980 : *
981 : * The order in which tables are added to the truetype_table array
982 : * using cairo_truetype_font_add_truetype_table() specifies the order
983 : * in which the callback functions will be called.
984 : *
985 : * The tables in the table directory must be listed in alphabetical
986 : * order. The "cvt", "fpgm", and "prep" are optional tables. They
987 : * will only be embedded in the subset if they exist in the source
988 : * font. The pos parameter of cairo_truetype_font_add_truetype_table()
989 : * specifies the position of the table in the table directory.
990 : */
991 : static void
992 0 : cairo_truetype_font_create_truetype_table_list (cairo_truetype_font_t *font)
993 : {
994 0 : cairo_bool_t has_cvt = FALSE;
995 0 : cairo_bool_t has_fpgm = FALSE;
996 0 : cairo_bool_t has_prep = FALSE;
997 : unsigned long size;
998 : int pos;
999 :
1000 0 : size = 0;
1001 0 : if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
1002 : TT_TAG_cvt, 0, NULL,
1003 : &size) == CAIRO_STATUS_SUCCESS)
1004 0 : has_cvt = TRUE;
1005 :
1006 0 : size = 0;
1007 0 : if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
1008 : TT_TAG_fpgm, 0, NULL,
1009 : &size) == CAIRO_STATUS_SUCCESS)
1010 0 : has_fpgm = TRUE;
1011 :
1012 0 : size = 0;
1013 0 : if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
1014 : TT_TAG_prep, 0, NULL,
1015 : &size) == CAIRO_STATUS_SUCCESS)
1016 0 : has_prep = TRUE;
1017 :
1018 0 : font->num_tables = 0;
1019 0 : pos = 1;
1020 0 : if (has_cvt)
1021 0 : pos++;
1022 0 : if (has_fpgm)
1023 0 : pos++;
1024 0 : cairo_truetype_font_add_truetype_table (font, TT_TAG_glyf, cairo_truetype_font_write_glyf_table, pos);
1025 :
1026 0 : pos = 0;
1027 0 : cairo_truetype_font_add_truetype_table (font, TT_TAG_cmap, cairo_truetype_font_write_cmap_table, pos++);
1028 0 : if (has_cvt)
1029 0 : cairo_truetype_font_add_truetype_table (font, TT_TAG_cvt, cairo_truetype_font_write_generic_table, pos++);
1030 0 : if (has_fpgm)
1031 0 : cairo_truetype_font_add_truetype_table (font, TT_TAG_fpgm, cairo_truetype_font_write_generic_table, pos++);
1032 0 : pos++;
1033 0 : cairo_truetype_font_add_truetype_table (font, TT_TAG_head, cairo_truetype_font_write_head_table, pos++);
1034 0 : cairo_truetype_font_add_truetype_table (font, TT_TAG_hhea, cairo_truetype_font_write_hhea_table, pos++);
1035 0 : cairo_truetype_font_add_truetype_table (font, TT_TAG_hmtx, cairo_truetype_font_write_hmtx_table, pos++);
1036 0 : cairo_truetype_font_add_truetype_table (font, TT_TAG_loca, cairo_truetype_font_write_loca_table, pos++);
1037 0 : cairo_truetype_font_add_truetype_table (font, TT_TAG_maxp, cairo_truetype_font_write_maxp_table, pos++);
1038 0 : if (has_prep)
1039 0 : cairo_truetype_font_add_truetype_table (font, TT_TAG_prep, cairo_truetype_font_write_generic_table, pos);
1040 0 : }
1041 :
1042 : cairo_status_t
1043 0 : _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
1044 : cairo_scaled_font_subset_t *font_subset)
1045 : {
1046 0 : cairo_truetype_font_t *font = NULL;
1047 : cairo_status_t status;
1048 0 : const char *data = NULL; /* squelch bogus compiler warning */
1049 0 : unsigned long length = 0; /* squelch bogus compiler warning */
1050 : unsigned long offsets_length;
1051 : unsigned int i;
1052 0 : const unsigned long *string_offsets = NULL;
1053 0 : unsigned long num_strings = 0;
1054 :
1055 0 : status = _cairo_truetype_font_create (font_subset, &font);
1056 0 : if (unlikely (status))
1057 0 : return status;
1058 :
1059 0 : for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
1060 0 : unsigned short parent_glyph = font->scaled_font_subset->glyphs[i];
1061 0 : status = cairo_truetype_font_use_glyph (font, parent_glyph, &parent_glyph);
1062 0 : if (unlikely (status))
1063 0 : goto fail1;
1064 : }
1065 :
1066 0 : cairo_truetype_font_create_truetype_table_list (font);
1067 0 : status = cairo_truetype_font_generate (font, &data, &length,
1068 : &string_offsets, &num_strings);
1069 0 : if (unlikely (status))
1070 0 : goto fail1;
1071 :
1072 0 : truetype_subset->ps_name = strdup (font->base.ps_name);
1073 0 : if (unlikely (truetype_subset->ps_name == NULL)) {
1074 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1075 0 : goto fail1;
1076 : }
1077 :
1078 0 : if (font->base.font_name != NULL) {
1079 0 : truetype_subset->font_name = strdup (font->base.font_name);
1080 0 : if (unlikely (truetype_subset->font_name == NULL)) {
1081 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1082 0 : goto fail2;
1083 : }
1084 : } else {
1085 0 : truetype_subset->font_name = NULL;
1086 : }
1087 :
1088 : /* The widths array returned must contain only widths for the
1089 : * glyphs in font_subset. Any subglyphs appended after
1090 : * font_subset->num_glyphs are omitted. */
1091 0 : truetype_subset->widths = calloc (sizeof (double),
1092 0 : font->scaled_font_subset->num_glyphs);
1093 0 : if (unlikely (truetype_subset->widths == NULL)) {
1094 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1095 0 : goto fail3;
1096 : }
1097 0 : for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
1098 0 : truetype_subset->widths[i] = (double)font->base.widths[i]/font->base.units_per_em;
1099 :
1100 0 : truetype_subset->x_min = (double)font->base.x_min/font->base.units_per_em;
1101 0 : truetype_subset->y_min = (double)font->base.y_min/font->base.units_per_em;
1102 0 : truetype_subset->x_max = (double)font->base.x_max/font->base.units_per_em;
1103 0 : truetype_subset->y_max = (double)font->base.y_max/font->base.units_per_em;
1104 0 : truetype_subset->ascent = (double)font->base.ascent/font->base.units_per_em;
1105 0 : truetype_subset->descent = (double)font->base.descent/font->base.units_per_em;
1106 :
1107 0 : if (length) {
1108 0 : truetype_subset->data = malloc (length);
1109 0 : if (unlikely (truetype_subset->data == NULL)) {
1110 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1111 0 : goto fail4;
1112 : }
1113 :
1114 0 : memcpy (truetype_subset->data, data, length);
1115 : } else
1116 0 : truetype_subset->data = NULL;
1117 0 : truetype_subset->data_length = length;
1118 :
1119 0 : if (num_strings) {
1120 0 : offsets_length = num_strings * sizeof (unsigned long);
1121 0 : truetype_subset->string_offsets = malloc (offsets_length);
1122 0 : if (unlikely (truetype_subset->string_offsets == NULL)) {
1123 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1124 0 : goto fail5;
1125 : }
1126 :
1127 0 : memcpy (truetype_subset->string_offsets, string_offsets, offsets_length);
1128 0 : truetype_subset->num_string_offsets = num_strings;
1129 : } else {
1130 0 : truetype_subset->string_offsets = NULL;
1131 0 : truetype_subset->num_string_offsets = 0;
1132 : }
1133 :
1134 0 : cairo_truetype_font_destroy (font);
1135 :
1136 0 : return CAIRO_STATUS_SUCCESS;
1137 :
1138 : fail5:
1139 0 : free (truetype_subset->data);
1140 : fail4:
1141 0 : free (truetype_subset->widths);
1142 : fail3:
1143 0 : if (truetype_subset->font_name)
1144 0 : free (truetype_subset->font_name);
1145 : fail2:
1146 0 : free (truetype_subset->ps_name);
1147 : fail1:
1148 0 : cairo_truetype_font_destroy (font);
1149 :
1150 0 : return status;
1151 : }
1152 :
1153 : void
1154 0 : _cairo_truetype_subset_fini (cairo_truetype_subset_t *subset)
1155 : {
1156 0 : free (subset->ps_name);
1157 0 : if (subset->font_name)
1158 0 : free (subset->font_name);
1159 0 : free (subset->widths);
1160 0 : free (subset->data);
1161 0 : free (subset->string_offsets);
1162 0 : }
1163 :
1164 : static cairo_int_status_t
1165 0 : _cairo_truetype_reverse_cmap (cairo_scaled_font_t *scaled_font,
1166 : unsigned long table_offset,
1167 : unsigned long index,
1168 : uint32_t *ucs4)
1169 : {
1170 : cairo_status_t status;
1171 : const cairo_scaled_font_backend_t *backend;
1172 : tt_segment_map_t *map;
1173 : char buf[4];
1174 : unsigned int num_segments, i;
1175 : unsigned long size;
1176 : uint16_t *start_code;
1177 : uint16_t *end_code;
1178 : uint16_t *delta;
1179 : uint16_t *range_offset;
1180 : uint16_t *glyph_array;
1181 : uint16_t c;
1182 :
1183 0 : backend = scaled_font->backend;
1184 0 : size = 4;
1185 0 : status = backend->load_truetype_table (scaled_font,
1186 : TT_TAG_cmap, table_offset,
1187 : (unsigned char *) &buf,
1188 : &size);
1189 0 : if (unlikely (status))
1190 0 : return status;
1191 :
1192 : /* All table formats have the same first two words */
1193 0 : map = (tt_segment_map_t *) buf;
1194 0 : if (be16_to_cpu (map->format) != 4)
1195 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1196 :
1197 0 : size = be16_to_cpu (map->length);
1198 0 : map = malloc (size);
1199 0 : if (unlikely (map == NULL))
1200 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1201 :
1202 0 : status = backend->load_truetype_table (scaled_font,
1203 : TT_TAG_cmap, table_offset,
1204 : (unsigned char *) map,
1205 : &size);
1206 0 : if (unlikely (status))
1207 0 : goto fail;
1208 :
1209 0 : num_segments = be16_to_cpu (map->segCountX2)/2;
1210 :
1211 : /* A Format 4 cmap contains 8 uint16_t numbers and 4 arrays of
1212 : * uint16_t each num_segments long. */
1213 0 : if (size < (8 + 4*num_segments)*sizeof(uint16_t))
1214 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1215 :
1216 0 : end_code = map->endCount;
1217 0 : start_code = &(end_code[num_segments + 1]);
1218 0 : delta = &(start_code[num_segments]);
1219 0 : range_offset = &(delta[num_segments]);
1220 0 : glyph_array = &(range_offset[num_segments]);
1221 :
1222 : /* search for glyph in segments with rangeOffset=0 */
1223 0 : for (i = 0; i < num_segments; i++) {
1224 0 : c = index - be16_to_cpu (delta[i]);
1225 0 : if (range_offset[i] == 0 &&
1226 0 : c >= be16_to_cpu (start_code[i]) &&
1227 0 : c <= be16_to_cpu (end_code[i]))
1228 : {
1229 0 : *ucs4 = c;
1230 0 : goto found;
1231 : }
1232 : }
1233 :
1234 : /* search for glyph in segments with rangeOffset=1 */
1235 0 : for (i = 0; i < num_segments; i++) {
1236 0 : if (range_offset[i] != 0) {
1237 0 : uint16_t *glyph_ids = &range_offset[i] + be16_to_cpu (range_offset[i])/2;
1238 0 : int range_size = be16_to_cpu (end_code[i]) - be16_to_cpu (start_code[i]) + 1;
1239 0 : uint16_t g_id_be = cpu_to_be16 (index);
1240 : int j;
1241 :
1242 0 : if (range_size > 0) {
1243 0 : if ((char*)glyph_ids + 2*range_size > (char*)map + size)
1244 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1245 :
1246 0 : for (j = 0; j < range_size; j++) {
1247 0 : if (glyph_ids[j] == g_id_be) {
1248 0 : *ucs4 = be16_to_cpu (start_code[i]) + j;
1249 0 : goto found;
1250 : }
1251 : }
1252 : }
1253 : }
1254 : }
1255 :
1256 : /* glyph not found */
1257 0 : *ucs4 = -1;
1258 :
1259 : found:
1260 0 : status = CAIRO_STATUS_SUCCESS;
1261 :
1262 : fail:
1263 0 : free (map);
1264 :
1265 0 : return status;
1266 : }
1267 :
1268 : cairo_int_status_t
1269 0 : _cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font,
1270 : unsigned long index,
1271 : uint32_t *ucs4)
1272 : {
1273 0 : cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
1274 : const cairo_scaled_font_backend_t *backend;
1275 : tt_cmap_t *cmap;
1276 : char buf[4];
1277 : int num_tables, i;
1278 : unsigned long size;
1279 :
1280 0 : backend = scaled_font->backend;
1281 0 : if (!backend->load_truetype_table)
1282 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1283 :
1284 0 : size = 4;
1285 0 : status = backend->load_truetype_table (scaled_font,
1286 : TT_TAG_cmap, 0,
1287 : (unsigned char *) &buf,
1288 : &size);
1289 0 : if (unlikely (status))
1290 0 : return status;
1291 :
1292 0 : cmap = (tt_cmap_t *) buf;
1293 0 : num_tables = be16_to_cpu (cmap->num_tables);
1294 0 : size = 4 + num_tables*sizeof(tt_cmap_index_t);
1295 0 : cmap = _cairo_malloc_ab_plus_c (num_tables, sizeof (tt_cmap_index_t), 4);
1296 0 : if (unlikely (cmap == NULL))
1297 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1298 :
1299 0 : status = backend->load_truetype_table (scaled_font,
1300 : TT_TAG_cmap, 0,
1301 : (unsigned char *) cmap,
1302 : &size);
1303 0 : if (unlikely (status))
1304 0 : goto cleanup;
1305 :
1306 : /* Find a table with Unicode mapping */
1307 0 : for (i = 0; i < num_tables; i++) {
1308 0 : if (be16_to_cpu (cmap->index[i].platform) == 3 &&
1309 0 : be16_to_cpu (cmap->index[i].encoding) == 1) {
1310 0 : status = _cairo_truetype_reverse_cmap (scaled_font,
1311 0 : be32_to_cpu (cmap->index[i].offset),
1312 : index,
1313 : ucs4);
1314 0 : if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1315 0 : break;
1316 : }
1317 : }
1318 :
1319 : cleanup:
1320 0 : free (cmap);
1321 :
1322 0 : return status;
1323 : }
1324 :
1325 : cairo_int_status_t
1326 0 : _cairo_truetype_read_font_name (cairo_scaled_font_t *scaled_font,
1327 : char **ps_name_out,
1328 : char **font_name_out)
1329 : {
1330 : cairo_status_t status;
1331 : const cairo_scaled_font_backend_t *backend;
1332 : tt_name_t *name;
1333 : tt_name_record_t *record;
1334 : unsigned long size;
1335 : int i, j;
1336 0 : char *ps_name = NULL;
1337 0 : char *font_name = NULL;
1338 :
1339 0 : backend = scaled_font->backend;
1340 0 : if (!backend->load_truetype_table)
1341 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
1342 :
1343 0 : size = 0;
1344 0 : status = backend->load_truetype_table (scaled_font,
1345 : TT_TAG_name, 0,
1346 : NULL,
1347 : &size);
1348 0 : if (status)
1349 0 : return status;
1350 :
1351 0 : name = malloc (size);
1352 0 : if (name == NULL)
1353 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1354 :
1355 0 : status = backend->load_truetype_table (scaled_font,
1356 : TT_TAG_name, 0,
1357 : (unsigned char *) name,
1358 : &size);
1359 0 : if (status)
1360 0 : goto fail;
1361 :
1362 : /* Extract the font name and PS name from the name table. At
1363 : * present this just looks for the Mac platform/Roman encoded font
1364 : * name. It should be extended to use any suitable font name in
1365 : * the name table.
1366 : */
1367 0 : for (i = 0; i < be16_to_cpu(name->num_records); i++) {
1368 0 : record = &(name->records[i]);
1369 0 : if ((be16_to_cpu (record->platform) == 1) &&
1370 0 : (be16_to_cpu (record->encoding) == 0)) {
1371 :
1372 0 : if (be16_to_cpu (record->name) == 4) {
1373 0 : font_name = malloc (be16_to_cpu(record->length) + 1);
1374 0 : if (font_name == NULL) {
1375 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1376 0 : goto fail;
1377 : }
1378 0 : strncpy(font_name,
1379 0 : ((char*)name) + be16_to_cpu (name->strings_offset) + be16_to_cpu (record->offset),
1380 0 : be16_to_cpu (record->length));
1381 0 : font_name[be16_to_cpu (record->length)] = 0;
1382 : }
1383 :
1384 0 : if (be16_to_cpu (record->name) == 6) {
1385 0 : ps_name = malloc (be16_to_cpu(record->length) + 1);
1386 0 : if (ps_name == NULL) {
1387 0 : status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1388 0 : goto fail;
1389 : }
1390 0 : strncpy(ps_name,
1391 0 : ((char*)name) + be16_to_cpu (name->strings_offset) + be16_to_cpu (record->offset),
1392 0 : be16_to_cpu (record->length));
1393 0 : ps_name[be16_to_cpu (record->length)] = 0;
1394 : }
1395 :
1396 0 : if (font_name && ps_name)
1397 0 : break;
1398 : }
1399 : }
1400 :
1401 0 : free (name);
1402 :
1403 : /* Ensure PS name does not contain any spaces */
1404 0 : if (ps_name) {
1405 0 : for (i = 0, j = 0; ps_name[j]; j++) {
1406 0 : if (ps_name[j] == ' ')
1407 0 : continue;
1408 0 : ps_name[i++] = ps_name[j];
1409 : }
1410 0 : ps_name[i] = '\0';
1411 : }
1412 :
1413 0 : *ps_name_out = ps_name;
1414 0 : *font_name_out = font_name;
1415 :
1416 0 : return CAIRO_STATUS_SUCCESS;
1417 :
1418 : fail:
1419 0 : free (name);
1420 :
1421 0 : if (ps_name != NULL)
1422 0 : free (ps_name);
1423 :
1424 0 : if (font_name != NULL)
1425 0 : free (font_name);
1426 :
1427 0 : *ps_name_out = NULL;
1428 0 : *font_name_out = NULL;
1429 :
1430 0 : return status;
1431 : }
1432 :
1433 : #endif /* CAIRO_HAS_FONT_SUBSET */
|