Updated: Sudoku no longer crashes
[moon.git] / cairo / src / cairo-truetype-subset.c
blobe8be4b44429eac6ff56405ecbfab0a3cdd5fda72
1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2004 Red Hat, Inc
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
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/
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.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is Red Hat, Inc.
32 * Contributor(s):
33 * Kristian Høgsberg <krh@redhat.com>
34 * Adrian Johnson <ajohnson@redneon.com>
38 * Useful links:
39 * http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6.html
40 * http://www.microsoft.com/typography/specs/default.htm
43 #define _BSD_SOURCE /* for snprintf(), strdup() */
44 #include "cairoint.h"
46 #if CAIRO_HAS_FONT_SUBSET
48 #include "cairo-scaled-font-subsets-private.h"
49 #include "cairo-truetype-subset-private.h"
52 typedef struct subset_glyph subset_glyph_t;
53 struct subset_glyph {
54 int parent_index;
55 unsigned long location;
58 typedef struct _cairo_truetype_font cairo_truetype_font_t;
60 typedef struct table table_t;
61 struct table {
62 unsigned long tag;
63 cairo_status_t (*write) (cairo_truetype_font_t *font, unsigned long tag);
64 int pos; /* position in the font directory */
67 struct _cairo_truetype_font {
69 cairo_scaled_font_subset_t *scaled_font_subset;
71 table_t truetype_tables[10];
72 int num_tables;
74 struct {
75 char *base_font;
76 unsigned int num_glyphs;
77 int *widths;
78 long x_min, y_min, x_max, y_max;
79 long ascent, descent;
80 int units_per_em;
81 } base;
83 subset_glyph_t *glyphs;
84 const cairo_scaled_font_backend_t *backend;
85 int num_glyphs_in_face;
86 int checksum_index;
87 cairo_array_t output;
88 cairo_array_t string_offsets;
89 unsigned long last_offset;
90 unsigned long last_boundary;
91 int *parent_to_subset;
92 cairo_status_t status;
96 static cairo_status_t
97 cairo_truetype_font_use_glyph (cairo_truetype_font_t *font,
98 unsigned short glyph,
99 unsigned short *out);
101 #define SFNT_VERSION 0x00010000
102 #define SFNT_STRING_MAX_LENGTH 65535
104 static cairo_status_t
105 _cairo_truetype_font_set_error (cairo_truetype_font_t *font,
106 cairo_status_t status)
108 if (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED)
109 return status;
111 _cairo_status_set_error (&font->status, status);
113 return _cairo_error (status);
116 static cairo_status_t
117 _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
118 cairo_truetype_font_t **font_return)
120 cairo_status_t status;
121 cairo_truetype_font_t *font;
122 const cairo_scaled_font_backend_t *backend;
123 tt_head_t head;
124 tt_hhea_t hhea;
125 tt_maxp_t maxp;
126 tt_name_t *name;
127 tt_name_record_t *record;
128 unsigned long size;
129 int i, j;
131 backend = scaled_font_subset->scaled_font->backend;
132 if (!backend->load_truetype_table)
133 return CAIRO_INT_STATUS_UNSUPPORTED;
135 /* FIXME: We should either support subsetting vertical fonts, or fail on
136 * vertical. Currently font_options_t doesn't have vertical flag, but
137 * it should be added in the future. For now, the freetype backend
138 * returns UNSUPPORTED in load_truetype_table if the font is vertical.
140 * if (cairo_font_options_get_vertical_layout (scaled_font_subset->scaled_font))
141 * return CAIRO_INT_STATUS_UNSUPPORTED;
144 size = sizeof (tt_head_t);
145 status = backend->load_truetype_table (scaled_font_subset->scaled_font,
146 TT_TAG_head, 0,
147 (unsigned char *) &head,
148 &size);
149 if (status)
150 return status;
152 size = sizeof (tt_maxp_t);
153 status = backend->load_truetype_table (scaled_font_subset->scaled_font,
154 TT_TAG_maxp, 0,
155 (unsigned char *) &maxp,
156 &size);
157 if (status)
158 return status;
160 size = sizeof (tt_hhea_t);
161 status = backend->load_truetype_table (scaled_font_subset->scaled_font,
162 TT_TAG_hhea, 0,
163 (unsigned char *) &hhea,
164 &size);
165 if (status)
166 return status;
168 size = 0;
169 status = backend->load_truetype_table (scaled_font_subset->scaled_font,
170 TT_TAG_name, 0,
171 NULL,
172 &size);
173 if (status)
174 return status;
176 name = malloc(size);
177 if (name == NULL)
178 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
180 status = backend->load_truetype_table (scaled_font_subset->scaled_font,
181 TT_TAG_name, 0,
182 (unsigned char *) name,
183 &size);
184 if (status)
185 goto fail0;
187 font = malloc (sizeof (cairo_truetype_font_t));
188 if (font == NULL) {
189 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
190 goto fail0;
193 font->backend = backend;
194 font->num_glyphs_in_face = be16_to_cpu (maxp.num_glyphs);
195 font->scaled_font_subset = scaled_font_subset;
197 font->last_offset = 0;
198 font->last_boundary = 0;
199 _cairo_array_init (&font->output, sizeof (char));
200 status = _cairo_array_grow_by (&font->output, 4096);
201 if (status)
202 goto fail1;
204 font->glyphs = calloc (font->num_glyphs_in_face + 1, sizeof (subset_glyph_t));
205 if (font->glyphs == NULL) {
206 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
207 goto fail1;
210 font->parent_to_subset = calloc (font->num_glyphs_in_face, sizeof (int));
211 if (font->parent_to_subset == NULL) {
212 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
213 goto fail2;
216 font->base.num_glyphs = 0;
217 font->base.x_min = (int16_t) be16_to_cpu (head.x_min);
218 font->base.y_min = (int16_t) be16_to_cpu (head.y_min);
219 font->base.x_max = (int16_t) be16_to_cpu (head.x_max);
220 font->base.y_max = (int16_t) be16_to_cpu (head.y_max);
221 font->base.ascent = (int16_t) be16_to_cpu (hhea.ascender);
222 font->base.descent = (int16_t) be16_to_cpu (hhea.descender);
223 font->base.units_per_em = (int16_t) be16_to_cpu (head.units_per_em);
224 if (font->base.units_per_em == 0)
225 font->base.units_per_em = 2048;
227 /* Extract the font name from the name table. At present this
228 * just looks for the Mac platform/Roman encoded font name. It
229 * should be extended to use any suitable font name in the
230 * name table. If the mac/roman font name is not found a
231 * CairoFont-x-y name is created.
233 font->base.base_font = NULL;
234 for (i = 0; i < be16_to_cpu(name->num_records); i++) {
235 record = &(name->records[i]);
236 if ((be16_to_cpu (record->platform) == 1) &&
237 (be16_to_cpu (record->encoding) == 0) &&
238 (be16_to_cpu (record->name) == 4)) {
239 font->base.base_font = malloc (be16_to_cpu(record->length) + 1);
240 if (font->base.base_font) {
241 strncpy(font->base.base_font,
242 ((char*)name) + be16_to_cpu (name->strings_offset) + be16_to_cpu (record->offset),
243 be16_to_cpu (record->length));
244 font->base.base_font[be16_to_cpu (record->length)] = 0;
246 break;
250 free (name);
251 name = NULL;
253 if (font->base.base_font == NULL) {
254 font->base.base_font = malloc (30);
255 if (font->base.base_font == NULL) {
256 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
257 goto fail3;
260 snprintf(font->base.base_font, 30, "CairoFont-%u-%u",
261 scaled_font_subset->font_id,
262 scaled_font_subset->subset_id);
265 for (i = 0, j = 0; font->base.base_font[j]; j++) {
266 if (font->base.base_font[j] == ' ')
267 continue;
268 font->base.base_font[i++] = font->base.base_font[j];
270 font->base.base_font[i] = '\0';
272 font->base.widths = calloc (font->num_glyphs_in_face, sizeof (int));
273 if (font->base.widths == NULL) {
274 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
275 goto fail4;
278 _cairo_array_init (&font->string_offsets, sizeof (unsigned long));
279 status = _cairo_array_grow_by (&font->string_offsets, 10);
280 if (status)
281 goto fail5;
283 font->status = CAIRO_STATUS_SUCCESS;
285 *font_return = font;
287 return CAIRO_STATUS_SUCCESS;
289 fail5:
290 _cairo_array_fini (&font->string_offsets);
291 free (font->base.widths);
292 fail4:
293 free (font->base.base_font);
294 fail3:
295 free (font->parent_to_subset);
296 fail2:
297 free (font->glyphs);
298 fail1:
299 _cairo_array_fini (&font->output);
300 free (font);
301 fail0:
302 if (name)
303 free (name);
305 return status;
308 static void
309 cairo_truetype_font_destroy (cairo_truetype_font_t *font)
311 _cairo_array_fini (&font->string_offsets);
312 free (font->base.widths);
313 free (font->base.base_font);
314 free (font->parent_to_subset);
315 free (font->glyphs);
316 _cairo_array_fini (&font->output);
317 free (font);
320 static cairo_status_t
321 cairo_truetype_font_allocate_write_buffer (cairo_truetype_font_t *font,
322 size_t length,
323 unsigned char **buffer)
325 cairo_status_t status;
327 if (font->status)
328 return font->status;
330 status = _cairo_array_allocate (&font->output, length, (void **) buffer);
331 if (status)
332 return _cairo_truetype_font_set_error (font, status);
334 return CAIRO_STATUS_SUCCESS;
337 static void
338 cairo_truetype_font_write (cairo_truetype_font_t *font,
339 const void *data,
340 size_t length)
342 cairo_status_t status;
344 if (font->status)
345 return;
347 status = _cairo_array_append_multiple (&font->output, data, length);
348 if (status)
349 status = _cairo_truetype_font_set_error (font, status);
352 static void
353 cairo_truetype_font_write_be16 (cairo_truetype_font_t *font,
354 uint16_t value)
356 uint16_t be16_value;
358 if (font->status)
359 return;
361 be16_value = cpu_to_be16 (value);
362 cairo_truetype_font_write (font, &be16_value, sizeof be16_value);
365 static void
366 cairo_truetype_font_write_be32 (cairo_truetype_font_t *font,
367 uint32_t value)
369 uint32_t be32_value;
371 if (font->status)
372 return;
374 be32_value = cpu_to_be32 (value);
375 cairo_truetype_font_write (font, &be32_value, sizeof be32_value);
378 static cairo_status_t
379 cairo_truetype_font_align_output (cairo_truetype_font_t *font,
380 unsigned long *aligned)
382 int length, pad;
383 unsigned char *padding;
385 length = _cairo_array_num_elements (&font->output);
386 *aligned = (length + 3) & ~3;
387 pad = *aligned - length;
389 if (pad) {
390 cairo_status_t status;
392 status = cairo_truetype_font_allocate_write_buffer (font, pad,
393 &padding);
394 if (status)
395 return status;
397 memset (padding, 0, pad);
400 return CAIRO_STATUS_SUCCESS;
403 static cairo_status_t
404 cairo_truetype_font_check_boundary (cairo_truetype_font_t *font,
405 unsigned long boundary)
407 cairo_status_t status;
409 if (font->status)
410 return font->status;
412 if (boundary - font->last_offset > SFNT_STRING_MAX_LENGTH)
414 status = _cairo_array_append (&font->string_offsets,
415 &font->last_boundary);
416 if (status)
417 return _cairo_truetype_font_set_error (font, status);
419 font->last_offset = font->last_boundary;
421 font->last_boundary = boundary;
423 return CAIRO_STATUS_SUCCESS;
426 static cairo_status_t
427 cairo_truetype_font_write_cmap_table (cairo_truetype_font_t *font,
428 unsigned long tag)
430 unsigned int i;
432 cairo_truetype_font_write_be16 (font, 0); /* Table version */
433 cairo_truetype_font_write_be16 (font, 2); /* Num tables */
435 cairo_truetype_font_write_be16 (font, 3); /* Platform */
436 cairo_truetype_font_write_be16 (font, 0); /* Encoding */
437 cairo_truetype_font_write_be32 (font, 20); /* Offset to start of table */
439 cairo_truetype_font_write_be16 (font, 1); /* Platform */
440 cairo_truetype_font_write_be16 (font, 0); /* Encoding */
441 cairo_truetype_font_write_be32 (font, 52); /* Offset to start of table */
443 /* Output a format 4 encoding table. */
445 cairo_truetype_font_write_be16 (font, 4); /* Format */
446 cairo_truetype_font_write_be16 (font, 32); /* Length */
447 cairo_truetype_font_write_be16 (font, 0); /* Version */
448 cairo_truetype_font_write_be16 (font, 4); /* 2*segcount */
449 cairo_truetype_font_write_be16 (font, 4); /* searchrange */
450 cairo_truetype_font_write_be16 (font, 1); /* entry selector */
451 cairo_truetype_font_write_be16 (font, 0); /* rangeshift */
452 cairo_truetype_font_write_be16 (font, 0xf000 + font->base.num_glyphs - 1); /* end count[0] */
453 cairo_truetype_font_write_be16 (font, 0xffff); /* end count[1] */
454 cairo_truetype_font_write_be16 (font, 0); /* reserved */
455 cairo_truetype_font_write_be16 (font, 0xf000); /* startCode[0] */
456 cairo_truetype_font_write_be16 (font, 0xffff); /* startCode[1] */
457 cairo_truetype_font_write_be16 (font, 0x1000); /* delta[0] */
458 cairo_truetype_font_write_be16 (font, 1); /* delta[1] */
459 cairo_truetype_font_write_be16 (font, 0); /* rangeOffset[0] */
460 cairo_truetype_font_write_be16 (font, 0); /* rangeOffset[1] */
462 /* Output a format 6 encoding table. */
464 cairo_truetype_font_write_be16 (font, 6);
465 cairo_truetype_font_write_be16 (font, 10 + 2 * font->base.num_glyphs);
466 cairo_truetype_font_write_be16 (font, 0);
467 cairo_truetype_font_write_be16 (font, 0); /* First character */
468 cairo_truetype_font_write_be16 (font, font->base.num_glyphs);
469 for (i = 0; i < font->base.num_glyphs; i++)
470 cairo_truetype_font_write_be16 (font, i);
472 return font->status;
475 static cairo_status_t
476 cairo_truetype_font_write_generic_table (cairo_truetype_font_t *font,
477 unsigned long tag)
479 cairo_status_t status;
480 unsigned char *buffer;
481 unsigned long size;
483 if (font->status)
484 return font->status;
486 size = 0;
487 status = font->backend->load_truetype_table(font->scaled_font_subset->scaled_font,
488 tag, 0, NULL, &size);
489 if (status)
490 return _cairo_truetype_font_set_error (font, status);
492 status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
493 if (status)
494 return _cairo_truetype_font_set_error (font, status);
496 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
497 tag, 0, buffer, &size);
498 if (status)
499 return _cairo_truetype_font_set_error (font, status);
501 return CAIRO_STATUS_SUCCESS;
504 static cairo_status_t
505 cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t *font,
506 unsigned char *buffer,
507 unsigned long size)
509 tt_glyph_data_t *glyph_data;
510 tt_composite_glyph_t *composite_glyph;
511 int num_args;
512 int has_more_components;
513 unsigned short flags;
514 unsigned short index;
515 cairo_status_t status;
516 unsigned char *end = buffer + size;
518 if (font->status)
519 return font->status;
521 glyph_data = (tt_glyph_data_t *) buffer;
522 if ((unsigned char *)(&glyph_data->data) >= end)
523 return CAIRO_INT_STATUS_UNSUPPORTED;
525 if ((int16_t)be16_to_cpu (glyph_data->num_contours) >= 0)
526 return CAIRO_STATUS_SUCCESS;
528 composite_glyph = &glyph_data->glyph;
529 do {
530 if ((unsigned char *)(&composite_glyph->args[1]) >= end)
531 return CAIRO_INT_STATUS_UNSUPPORTED;
533 flags = be16_to_cpu (composite_glyph->flags);
534 has_more_components = flags & TT_MORE_COMPONENTS;
535 status = cairo_truetype_font_use_glyph (font, be16_to_cpu (composite_glyph->index), &index);
536 if (status)
537 return status;
539 composite_glyph->index = cpu_to_be16 (index);
540 num_args = 1;
541 if (flags & TT_ARG_1_AND_2_ARE_WORDS)
542 num_args += 1;
543 if (flags & TT_WE_HAVE_A_SCALE)
544 num_args += 1;
545 else if (flags & TT_WE_HAVE_AN_X_AND_Y_SCALE)
546 num_args += 2;
547 else if (flags & TT_WE_HAVE_A_TWO_BY_TWO)
548 num_args += 3;
549 composite_glyph = (tt_composite_glyph_t *) &(composite_glyph->args[num_args]);
550 } while (has_more_components);
552 return CAIRO_STATUS_SUCCESS;
555 static cairo_status_t
556 cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font,
557 unsigned long tag)
559 unsigned long start_offset, index, size, next;
560 tt_head_t header;
561 unsigned long begin, end;
562 unsigned char *buffer;
563 unsigned int i;
564 union {
565 unsigned char *bytes;
566 uint16_t *short_offsets;
567 uint32_t *long_offsets;
568 } u;
569 cairo_status_t status;
571 if (font->status)
572 return font->status;
574 size = sizeof (tt_head_t);
575 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
576 TT_TAG_head, 0,
577 (unsigned char*) &header, &size);
578 if (status)
579 return _cairo_truetype_font_set_error (font, status);
581 if (be16_to_cpu (header.index_to_loc_format) == 0)
582 size = sizeof (int16_t) * (font->num_glyphs_in_face + 1);
583 else
584 size = sizeof (int32_t) * (font->num_glyphs_in_face + 1);
586 u.bytes = malloc (size);
587 if (u.bytes == NULL)
588 return _cairo_truetype_font_set_error (font, CAIRO_STATUS_NO_MEMORY);
590 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
591 TT_TAG_loca, 0, u.bytes, &size);
592 if (status)
593 return _cairo_truetype_font_set_error (font, status);
595 start_offset = _cairo_array_num_elements (&font->output);
596 for (i = 0; i < font->base.num_glyphs; i++) {
597 index = font->glyphs[i].parent_index;
598 if (be16_to_cpu (header.index_to_loc_format) == 0) {
599 begin = be16_to_cpu (u.short_offsets[index]) * 2;
600 end = be16_to_cpu (u.short_offsets[index + 1]) * 2;
602 else {
603 begin = be32_to_cpu (u.long_offsets[index]);
604 end = be32_to_cpu (u.long_offsets[index + 1]);
607 /* quick sanity check... */
608 if (end < begin) {
609 status = CAIRO_INT_STATUS_UNSUPPORTED;
610 goto FAIL;
613 size = end - begin;
614 status = cairo_truetype_font_align_output (font, &next);
615 if (status)
616 goto FAIL;
618 status = cairo_truetype_font_check_boundary (font, next);
619 if (status)
620 goto FAIL;
622 font->glyphs[i].location = next - start_offset;
624 status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
625 if (status)
626 goto FAIL;
628 if (size != 0) {
629 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
630 TT_TAG_glyf, begin, buffer, &size);
631 if (status)
632 goto FAIL;
634 status = cairo_truetype_font_remap_composite_glyph (font, buffer, size);
635 if (status)
636 goto FAIL;
640 status = cairo_truetype_font_align_output (font, &next);
641 if (status)
642 goto FAIL;
644 font->glyphs[i].location = next - start_offset;
646 status = font->status;
647 FAIL:
648 free (u.bytes);
650 return _cairo_truetype_font_set_error (font, status);
653 static cairo_status_t
654 cairo_truetype_font_write_head_table (cairo_truetype_font_t *font,
655 unsigned long tag)
657 unsigned char *buffer;
658 unsigned long size;
659 cairo_status_t status;
661 if (font->status)
662 return font->status;
664 size = 0;
665 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
666 tag, 0, NULL, &size);
667 if (status)
668 return _cairo_truetype_font_set_error (font, status);
670 font->checksum_index = _cairo_array_num_elements (&font->output) + 8;
671 status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
672 if (status)
673 return _cairo_truetype_font_set_error (font, status);
675 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
676 tag, 0, buffer, &size);
677 if (status)
678 return _cairo_truetype_font_set_error (font, status);
680 /* set checkSumAdjustment to 0 for table checksum calcualtion */
681 *(uint32_t *)(buffer + 8) = 0;
683 return CAIRO_STATUS_SUCCESS;
686 static cairo_status_t
687 cairo_truetype_font_write_hhea_table (cairo_truetype_font_t *font, unsigned long tag)
689 tt_hhea_t *hhea;
690 unsigned long size;
691 cairo_status_t status;
693 if (font->status)
694 return font->status;
696 size = sizeof (tt_hhea_t);
697 status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &hhea);
698 if (status)
699 return _cairo_truetype_font_set_error (font, status);
701 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
702 tag, 0, (unsigned char *) hhea, &size);
703 if (status)
704 return _cairo_truetype_font_set_error (font, status);
706 hhea->num_hmetrics = cpu_to_be16 ((uint16_t)(font->base.num_glyphs));
708 return CAIRO_STATUS_SUCCESS;
711 static cairo_status_t
712 cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font,
713 unsigned long tag)
715 unsigned long size;
716 unsigned long long_entry_size;
717 unsigned long short_entry_size;
718 short *p;
719 unsigned int i;
720 tt_hhea_t hhea;
721 int num_hmetrics;
722 cairo_status_t status;
724 if (font->status)
725 return font->status;
727 size = sizeof (tt_hhea_t);
728 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
729 TT_TAG_hhea, 0,
730 (unsigned char*) &hhea, &size);
731 if (status)
732 return _cairo_truetype_font_set_error (font, status);
734 num_hmetrics = be16_to_cpu(hhea.num_hmetrics);
736 for (i = 0; i < font->base.num_glyphs; i++) {
737 long_entry_size = 2 * sizeof (int16_t);
738 short_entry_size = sizeof (int16_t);
739 status = cairo_truetype_font_allocate_write_buffer (font,
740 long_entry_size,
741 (unsigned char **) &p);
742 if (status)
743 return _cairo_truetype_font_set_error (font, status);
745 if (font->glyphs[i].parent_index < num_hmetrics) {
746 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
747 TT_TAG_hmtx,
748 font->glyphs[i].parent_index * long_entry_size,
749 (unsigned char *) p, &long_entry_size);
750 if (status)
751 return _cairo_truetype_font_set_error (font, status);
753 else
755 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
756 TT_TAG_hmtx,
757 (num_hmetrics - 1) * long_entry_size,
758 (unsigned char *) p, &short_entry_size);
759 if (status)
760 return _cairo_truetype_font_set_error (font, status);
762 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
763 TT_TAG_hmtx,
764 num_hmetrics * long_entry_size +
765 (font->glyphs[i].parent_index - num_hmetrics) * short_entry_size,
766 (unsigned char *) (p + 1), &short_entry_size);
767 if (status)
768 return _cairo_truetype_font_set_error (font, status);
770 font->base.widths[i] = be16_to_cpu (p[0]);
773 return CAIRO_STATUS_SUCCESS;
776 static cairo_status_t
777 cairo_truetype_font_write_loca_table (cairo_truetype_font_t *font,
778 unsigned long tag)
780 unsigned int i;
781 tt_head_t header;
782 unsigned long size;
783 cairo_status_t status;
785 if (font->status)
786 return font->status;
788 size = sizeof(tt_head_t);
789 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
790 TT_TAG_head, 0,
791 (unsigned char*) &header, &size);
792 if (status)
793 return _cairo_truetype_font_set_error (font, status);
795 if (be16_to_cpu (header.index_to_loc_format) == 0)
797 for (i = 0; i < font->base.num_glyphs + 1; i++)
798 cairo_truetype_font_write_be16 (font, font->glyphs[i].location / 2);
799 } else {
800 for (i = 0; i < font->base.num_glyphs + 1; i++)
801 cairo_truetype_font_write_be32 (font, font->glyphs[i].location);
804 return font->status;
807 static cairo_status_t
808 cairo_truetype_font_write_maxp_table (cairo_truetype_font_t *font,
809 unsigned long tag)
811 tt_maxp_t *maxp;
812 unsigned long size;
813 cairo_status_t status;
815 if (font->status)
816 return font->status;
818 size = sizeof (tt_maxp_t);
819 status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &maxp);
820 if (status)
821 return _cairo_truetype_font_set_error (font, status);
823 status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
824 tag, 0, (unsigned char *) maxp, &size);
825 if (status)
826 return _cairo_truetype_font_set_error (font, status);
828 maxp->num_glyphs = cpu_to_be16 (font->base.num_glyphs);
830 return CAIRO_STATUS_SUCCESS;
833 static cairo_status_t
834 cairo_truetype_font_write_offset_table (cairo_truetype_font_t *font)
836 cairo_status_t status;
837 unsigned char *table_buffer;
838 size_t table_buffer_length;
839 unsigned short search_range, entry_selector, range_shift;
841 if (font->status)
842 return font->status;
844 search_range = 1;
845 entry_selector = 0;
846 while (search_range * 2 <= font->num_tables) {
847 search_range *= 2;
848 entry_selector++;
850 search_range *= 16;
851 range_shift = font->num_tables * 16 - search_range;
853 cairo_truetype_font_write_be32 (font, SFNT_VERSION);
854 cairo_truetype_font_write_be16 (font, font->num_tables);
855 cairo_truetype_font_write_be16 (font, search_range);
856 cairo_truetype_font_write_be16 (font, entry_selector);
857 cairo_truetype_font_write_be16 (font, range_shift);
859 /* Allocate space for the table directory. Each directory entry
860 * will be filled in by cairo_truetype_font_update_entry() after
861 * the table is written. */
862 table_buffer_length = font->num_tables * 16;
863 status = cairo_truetype_font_allocate_write_buffer (font, table_buffer_length,
864 &table_buffer);
865 if (status)
866 return _cairo_truetype_font_set_error (font, status);
868 return CAIRO_STATUS_SUCCESS;
871 static uint32_t
872 cairo_truetype_font_calculate_checksum (cairo_truetype_font_t *font,
873 unsigned long start,
874 unsigned long end)
876 uint32_t *padded_end;
877 uint32_t *p;
878 uint32_t checksum;
879 char *data;
881 checksum = 0;
882 data = _cairo_array_index (&font->output, 0);
883 p = (uint32_t *) (data + start);
884 padded_end = (uint32_t *) (data + ((end + 3) & ~3));
885 while (p < padded_end)
886 checksum += be32_to_cpu(*p++);
888 return checksum;
891 static void
892 cairo_truetype_font_update_entry (cairo_truetype_font_t *font,
893 int index,
894 unsigned long tag,
895 unsigned long start,
896 unsigned long end)
898 uint32_t *entry;
900 entry = _cairo_array_index (&font->output, 12 + 16 * index);
901 entry[0] = cpu_to_be32 ((uint32_t)tag);
902 entry[1] = cpu_to_be32 (cairo_truetype_font_calculate_checksum (font, start, end));
903 entry[2] = cpu_to_be32 ((uint32_t)start);
904 entry[3] = cpu_to_be32 ((uint32_t)(end - start));
907 static cairo_status_t
908 cairo_truetype_font_generate (cairo_truetype_font_t *font,
909 const char **data,
910 unsigned long *length,
911 const unsigned long **string_offsets,
912 unsigned long *num_strings)
914 cairo_status_t status;
915 unsigned long start, end, next;
916 uint32_t checksum, *checksum_location;
917 int i;
919 if (font->status)
920 return font->status;
922 status = cairo_truetype_font_write_offset_table (font);
923 if (status)
924 goto FAIL;
926 status = cairo_truetype_font_align_output (font, &start);
927 if (status)
928 goto FAIL;
930 end = 0;
931 for (i = 0; i < font->num_tables; i++) {
932 status = font->truetype_tables[i].write (font, font->truetype_tables[i].tag);
933 if (status)
934 goto FAIL;
936 end = _cairo_array_num_elements (&font->output);
937 status = cairo_truetype_font_align_output (font, &next);
938 if (status)
939 goto FAIL;
941 cairo_truetype_font_update_entry (font, font->truetype_tables[i].pos,
942 font->truetype_tables[i].tag, start, end);
943 status = cairo_truetype_font_check_boundary (font, next);
944 if (status)
945 goto FAIL;
947 start = next;
950 checksum =
951 0xb1b0afba - cairo_truetype_font_calculate_checksum (font, 0, end);
952 checksum_location = _cairo_array_index (&font->output, font->checksum_index);
953 *checksum_location = cpu_to_be32 (checksum);
955 *data = _cairo_array_index (&font->output, 0);
956 *length = _cairo_array_num_elements (&font->output);
957 *num_strings = _cairo_array_num_elements (&font->string_offsets);
958 if (*num_strings != 0)
959 *string_offsets = _cairo_array_index (&font->string_offsets, 0);
960 else
961 *string_offsets = NULL;
963 FAIL:
964 return _cairo_truetype_font_set_error (font, status);
967 static cairo_status_t
968 cairo_truetype_font_use_glyph (cairo_truetype_font_t *font,
969 unsigned short glyph,
970 unsigned short *out)
972 if (glyph >= font->num_glyphs_in_face)
973 return CAIRO_INT_STATUS_UNSUPPORTED;
975 if (font->parent_to_subset[glyph] == 0) {
976 font->parent_to_subset[glyph] = font->base.num_glyphs;
977 font->glyphs[font->base.num_glyphs].parent_index = glyph;
978 font->base.num_glyphs++;
981 *out = font->parent_to_subset[glyph];
982 return CAIRO_STATUS_SUCCESS;
985 static void
986 cairo_truetype_font_add_truetype_table (cairo_truetype_font_t *font,
987 unsigned long tag,
988 cairo_status_t (*write) (cairo_truetype_font_t *font, unsigned long tag),
989 int pos)
991 font->truetype_tables[font->num_tables].tag = tag;
992 font->truetype_tables[font->num_tables].write = write;
993 font->truetype_tables[font->num_tables].pos = pos;
994 font->num_tables++;
997 /* cairo_truetype_font_create_truetype_table_list() builds the list of
998 * truetype tables to be embedded in the subsetted font. Each call to
999 * cairo_truetype_font_add_truetype_table() adds a table, the callback
1000 * for generating the table, and the position in the table directory
1001 * to the truetype_tables array.
1003 * As we write out the glyf table we remap composite glyphs.
1004 * Remapping composite glyphs will reference the sub glyphs the
1005 * composite glyph is made up of. The "glyf" table callback needs to
1006 * be called first so we have all the glyphs in the subset before
1007 * going further.
1009 * The order in which tables are added to the truetype_table array
1010 * using cairo_truetype_font_add_truetype_table() specifies the order
1011 * in which the callback functions will be called.
1013 * The tables in the table directory must be listed in alphabetical
1014 * order. The "cvt", "fpgm", and "prep" are optional tables. They
1015 * will only be embedded in the subset if they exist in the source
1016 * font. The pos parameter of cairo_truetype_font_add_truetype_table()
1017 * specifies the position of the table in the table directory.
1019 static void
1020 cairo_truetype_font_create_truetype_table_list (cairo_truetype_font_t *font)
1022 cairo_bool_t has_cvt = FALSE;
1023 cairo_bool_t has_fpgm = FALSE;
1024 cairo_bool_t has_prep = FALSE;
1025 unsigned long size;
1026 int pos;
1028 size = 0;
1029 if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
1030 TT_TAG_cvt, 0, NULL,
1031 &size) == CAIRO_STATUS_SUCCESS)
1032 has_cvt = TRUE;
1034 size = 0;
1035 if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
1036 TT_TAG_fpgm, 0, NULL,
1037 &size) == CAIRO_STATUS_SUCCESS)
1038 has_fpgm = TRUE;
1040 size = 0;
1041 if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
1042 TT_TAG_prep, 0, NULL,
1043 &size) == CAIRO_STATUS_SUCCESS)
1044 has_prep = TRUE;
1046 font->num_tables = 0;
1047 pos = 1;
1048 if (has_cvt)
1049 pos++;
1050 if (has_fpgm)
1051 pos++;
1052 cairo_truetype_font_add_truetype_table (font, TT_TAG_glyf, cairo_truetype_font_write_glyf_table, pos);
1054 pos = 0;
1055 cairo_truetype_font_add_truetype_table (font, TT_TAG_cmap, cairo_truetype_font_write_cmap_table, pos++);
1056 if (has_cvt)
1057 cairo_truetype_font_add_truetype_table (font, TT_TAG_cvt, cairo_truetype_font_write_generic_table, pos++);
1058 if (has_fpgm)
1059 cairo_truetype_font_add_truetype_table (font, TT_TAG_fpgm, cairo_truetype_font_write_generic_table, pos++);
1060 pos++;
1061 cairo_truetype_font_add_truetype_table (font, TT_TAG_head, cairo_truetype_font_write_head_table, pos++);
1062 cairo_truetype_font_add_truetype_table (font, TT_TAG_hhea, cairo_truetype_font_write_hhea_table, pos++);
1063 cairo_truetype_font_add_truetype_table (font, TT_TAG_hmtx, cairo_truetype_font_write_hmtx_table, pos++);
1064 cairo_truetype_font_add_truetype_table (font, TT_TAG_loca, cairo_truetype_font_write_loca_table, pos++);
1065 cairo_truetype_font_add_truetype_table (font, TT_TAG_maxp, cairo_truetype_font_write_maxp_table, pos++);
1066 if (has_prep)
1067 cairo_truetype_font_add_truetype_table (font, TT_TAG_prep, cairo_truetype_font_write_generic_table, pos);
1070 cairo_status_t
1071 _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
1072 cairo_scaled_font_subset_t *font_subset)
1074 cairo_truetype_font_t *font = NULL;
1075 cairo_status_t status;
1076 const char *data = NULL; /* squelch bogus compiler warning */
1077 unsigned long length = 0; /* squelch bogus compiler warning */
1078 unsigned long offsets_length;
1079 unsigned int i;
1080 const unsigned long *string_offsets = NULL;
1081 unsigned long num_strings = 0;
1083 status = _cairo_truetype_font_create (font_subset, &font);
1084 if (status)
1085 return status;
1087 for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
1088 unsigned short parent_glyph = font->scaled_font_subset->glyphs[i];
1089 status = cairo_truetype_font_use_glyph (font, parent_glyph, &parent_glyph);
1090 if (status)
1091 goto fail1;
1094 cairo_truetype_font_create_truetype_table_list (font);
1095 status = cairo_truetype_font_generate (font, &data, &length,
1096 &string_offsets, &num_strings);
1097 if (status)
1098 goto fail1;
1100 truetype_subset->base_font = strdup (font->base.base_font);
1101 if (truetype_subset->base_font == NULL) {
1102 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1103 goto fail1;
1106 /* The widths array returned must contain only widths for the
1107 * glyphs in font_subset. Any subglyphs appended after
1108 * font_subset->num_glyphs are omitted. */
1109 truetype_subset->widths = calloc (sizeof (double),
1110 font->scaled_font_subset->num_glyphs);
1111 if (truetype_subset->widths == NULL) {
1112 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1113 goto fail2;
1115 for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
1116 truetype_subset->widths[i] = (double)font->base.widths[i]/font->base.units_per_em;
1118 truetype_subset->x_min = (double)font->base.x_min/font->base.units_per_em;
1119 truetype_subset->y_min = (double)font->base.y_min/font->base.units_per_em;
1120 truetype_subset->x_max = (double)font->base.x_max/font->base.units_per_em;
1121 truetype_subset->y_max = (double)font->base.y_max/font->base.units_per_em;
1122 truetype_subset->ascent = (double)font->base.ascent/font->base.units_per_em;
1123 truetype_subset->descent = (double)font->base.descent/font->base.units_per_em;
1125 if (length) {
1126 truetype_subset->data = malloc (length);
1127 if (truetype_subset->data == NULL) {
1128 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1129 goto fail3;
1132 memcpy (truetype_subset->data, data, length);
1133 } else
1134 truetype_subset->data = NULL;
1135 truetype_subset->data_length = length;
1137 if (num_strings) {
1138 offsets_length = num_strings * sizeof (unsigned long);
1139 truetype_subset->string_offsets = malloc (offsets_length);
1140 if (truetype_subset->string_offsets == NULL) {
1141 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1142 goto fail4;
1145 memcpy (truetype_subset->string_offsets, string_offsets, offsets_length);
1146 truetype_subset->num_string_offsets = num_strings;
1147 } else {
1148 truetype_subset->string_offsets = NULL;
1149 truetype_subset->num_string_offsets = 0;
1152 cairo_truetype_font_destroy (font);
1154 return CAIRO_STATUS_SUCCESS;
1156 fail4:
1157 free (truetype_subset->data);
1158 fail3:
1159 free (truetype_subset->widths);
1160 fail2:
1161 free (truetype_subset->base_font);
1162 fail1:
1163 cairo_truetype_font_destroy (font);
1165 return status;
1168 void
1169 _cairo_truetype_subset_fini (cairo_truetype_subset_t *subset)
1171 free (subset->base_font);
1172 free (subset->widths);
1173 free (subset->data);
1174 free (subset->string_offsets);
1177 static cairo_int_status_t
1178 _cairo_truetype_reverse_cmap (cairo_scaled_font_t *scaled_font,
1179 unsigned long table_offset,
1180 unsigned long index,
1181 uint32_t *ucs4)
1183 cairo_status_t status;
1184 const cairo_scaled_font_backend_t *backend;
1185 tt_segment_map_t *map;
1186 char buf[4];
1187 unsigned int num_segments, i;
1188 unsigned long size;
1189 uint16_t *start_code;
1190 uint16_t *end_code;
1191 uint16_t *delta;
1192 uint16_t *range_offset;
1193 uint16_t *glyph_array;
1194 uint16_t c;
1196 backend = scaled_font->backend;
1197 size = 4;
1198 status = backend->load_truetype_table (scaled_font,
1199 TT_TAG_cmap, table_offset,
1200 (unsigned char *) &buf,
1201 &size);
1202 if (status)
1203 return status;
1205 /* All table formats have the same first two words */
1206 map = (tt_segment_map_t *) buf;
1207 if (be16_to_cpu (map->format) != 4)
1208 return CAIRO_INT_STATUS_UNSUPPORTED;
1210 size = be16_to_cpu (map->length);
1211 map = malloc (size);
1212 if (map == NULL)
1213 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1215 status = backend->load_truetype_table (scaled_font,
1216 TT_TAG_cmap, table_offset,
1217 (unsigned char *) map,
1218 &size);
1219 if (status)
1220 goto fail;
1222 num_segments = be16_to_cpu (map->segCountX2)/2;
1224 /* A Format 4 cmap contains 8 uint16_t numbers and 4 arrays of
1225 * uint16_t each num_segments long. */
1226 if (size < (8 + 4*num_segments)*sizeof(uint16_t))
1227 return CAIRO_INT_STATUS_UNSUPPORTED;
1229 end_code = map->endCount;
1230 start_code = &(end_code[num_segments + 1]);
1231 delta = &(start_code[num_segments]);
1232 range_offset = &(delta[num_segments]);
1233 glyph_array = &(range_offset[num_segments]);
1235 /* search for glyph in segments with rangeOffset=0 */
1236 for (i = 0; i < num_segments; i++) {
1237 c = index - be16_to_cpu (delta[i]);
1238 if (range_offset[i] == 0 &&
1239 c >= be16_to_cpu (start_code[i]) &&
1240 c <= be16_to_cpu (end_code[i]))
1242 *ucs4 = c;
1243 goto found;
1247 /* search for glyph in segments with rangeOffset=1 */
1248 for (i = 0; i < num_segments; i++) {
1249 if (range_offset[i] != 0) {
1250 uint16_t *glyph_ids = &range_offset[i] + be16_to_cpu (range_offset[i])/2;
1251 int range_size = be16_to_cpu (end_code[i]) - be16_to_cpu (start_code[i]) + 1;
1252 uint16_t g_id_be = cpu_to_be16 (index);
1253 int j;
1255 if (range_size > 0) {
1256 if ((char*)glyph_ids + 2*range_size > (char*)map + size)
1257 return CAIRO_INT_STATUS_UNSUPPORTED;
1259 for (j = 0; j < range_size; j++) {
1260 if (glyph_ids[j] == g_id_be) {
1261 *ucs4 = be16_to_cpu (start_code[i]) + j;
1262 goto found;
1269 /* glyph not found */
1270 *ucs4 = -1;
1272 found:
1273 status = CAIRO_STATUS_SUCCESS;
1275 fail:
1276 free (map);
1278 return status;
1281 cairo_int_status_t
1282 _cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font,
1283 unsigned long index,
1284 uint32_t *ucs4)
1286 cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
1287 const cairo_scaled_font_backend_t *backend;
1288 tt_cmap_t *cmap;
1289 char buf[4];
1290 int num_tables, i;
1291 unsigned long size;
1293 backend = scaled_font->backend;
1294 if (!backend->load_truetype_table)
1295 return CAIRO_INT_STATUS_UNSUPPORTED;
1297 size = 4;
1298 status = backend->load_truetype_table (scaled_font,
1299 TT_TAG_cmap, 0,
1300 (unsigned char *) &buf,
1301 &size);
1302 if (status)
1303 return status;
1305 cmap = (tt_cmap_t *) buf;
1306 num_tables = be16_to_cpu (cmap->num_tables);
1307 size = 4 + num_tables*sizeof(tt_cmap_index_t);
1308 cmap = _cairo_malloc_ab_plus_c (num_tables, sizeof (tt_cmap_index_t), 4);
1309 if (cmap == NULL)
1310 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1312 status = backend->load_truetype_table (scaled_font,
1313 TT_TAG_cmap, 0,
1314 (unsigned char *) cmap,
1315 &size);
1316 if (status)
1317 goto cleanup;
1319 /* Find a table with Unicode mapping */
1320 for (i = 0; i < num_tables; i++) {
1321 if (be16_to_cpu (cmap->index[i].platform) == 3 &&
1322 be16_to_cpu (cmap->index[i].encoding) == 1) {
1323 status = _cairo_truetype_reverse_cmap (scaled_font,
1324 be32_to_cpu (cmap->index[i].offset),
1325 index,
1326 ucs4);
1327 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1328 break;
1332 cleanup:
1333 free (cmap);
1335 return status;
1338 #endif /* CAIRO_HAS_FONT_SUBSET */