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.
33 * Kristian Høgsberg <krh@redhat.com>
34 * Adrian Johnson <ajohnson@redneon.com>
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() */
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
;
55 unsigned long location
;
58 typedef struct _cairo_truetype_font cairo_truetype_font_t
;
60 typedef struct table table_t
;
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];
76 unsigned int num_glyphs
;
78 long x_min
, y_min
, x_max
, y_max
;
83 subset_glyph_t
*glyphs
;
84 const cairo_scaled_font_backend_t
*backend
;
85 int num_glyphs_in_face
;
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
;
97 cairo_truetype_font_use_glyph (cairo_truetype_font_t
*font
,
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
)
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
;
127 tt_name_record_t
*record
;
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
,
147 (unsigned char *) &head
,
152 size
= sizeof (tt_maxp_t
);
153 status
= backend
->load_truetype_table (scaled_font_subset
->scaled_font
,
155 (unsigned char *) &maxp
,
160 size
= sizeof (tt_hhea_t
);
161 status
= backend
->load_truetype_table (scaled_font_subset
->scaled_font
,
163 (unsigned char *) &hhea
,
169 status
= backend
->load_truetype_table (scaled_font_subset
->scaled_font
,
178 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
180 status
= backend
->load_truetype_table (scaled_font_subset
->scaled_font
,
182 (unsigned char *) name
,
187 font
= malloc (sizeof (cairo_truetype_font_t
));
189 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
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);
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
);
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
);
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;
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
);
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
] == ' ')
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
);
278 _cairo_array_init (&font
->string_offsets
, sizeof (unsigned long));
279 status
= _cairo_array_grow_by (&font
->string_offsets
, 10);
283 font
->status
= CAIRO_STATUS_SUCCESS
;
287 return CAIRO_STATUS_SUCCESS
;
290 _cairo_array_fini (&font
->string_offsets
);
291 free (font
->base
.widths
);
293 free (font
->base
.base_font
);
295 free (font
->parent_to_subset
);
299 _cairo_array_fini (&font
->output
);
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
);
316 _cairo_array_fini (&font
->output
);
320 static cairo_status_t
321 cairo_truetype_font_allocate_write_buffer (cairo_truetype_font_t
*font
,
323 unsigned char **buffer
)
325 cairo_status_t status
;
330 status
= _cairo_array_allocate (&font
->output
, length
, (void **) buffer
);
332 return _cairo_truetype_font_set_error (font
, status
);
334 return CAIRO_STATUS_SUCCESS
;
338 cairo_truetype_font_write (cairo_truetype_font_t
*font
,
342 cairo_status_t status
;
347 status
= _cairo_array_append_multiple (&font
->output
, data
, length
);
349 status
= _cairo_truetype_font_set_error (font
, status
);
353 cairo_truetype_font_write_be16 (cairo_truetype_font_t
*font
,
361 be16_value
= cpu_to_be16 (value
);
362 cairo_truetype_font_write (font
, &be16_value
, sizeof be16_value
);
366 cairo_truetype_font_write_be32 (cairo_truetype_font_t
*font
,
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
)
383 unsigned char *padding
;
385 length
= _cairo_array_num_elements (&font
->output
);
386 *aligned
= (length
+ 3) & ~3;
387 pad
= *aligned
- length
;
390 cairo_status_t status
;
392 status
= cairo_truetype_font_allocate_write_buffer (font
, pad
,
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
;
412 if (boundary
- font
->last_offset
> SFNT_STRING_MAX_LENGTH
)
414 status
= _cairo_array_append (&font
->string_offsets
,
415 &font
->last_boundary
);
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
,
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
);
475 static cairo_status_t
476 cairo_truetype_font_write_generic_table (cairo_truetype_font_t
*font
,
479 cairo_status_t status
;
480 unsigned char *buffer
;
487 status
= font
->backend
->load_truetype_table(font
->scaled_font_subset
->scaled_font
,
488 tag
, 0, NULL
, &size
);
490 return _cairo_truetype_font_set_error (font
, status
);
492 status
= cairo_truetype_font_allocate_write_buffer (font
, size
, &buffer
);
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
);
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
,
509 tt_glyph_data_t
*glyph_data
;
510 tt_composite_glyph_t
*composite_glyph
;
512 int has_more_components
;
513 unsigned short flags
;
514 unsigned short index
;
515 cairo_status_t status
;
516 unsigned char *end
= buffer
+ size
;
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
;
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
);
539 composite_glyph
->index
= cpu_to_be16 (index
);
541 if (flags
& TT_ARG_1_AND_2_ARE_WORDS
)
543 if (flags
& TT_WE_HAVE_A_SCALE
)
545 else if (flags
& TT_WE_HAVE_AN_X_AND_Y_SCALE
)
547 else if (flags
& TT_WE_HAVE_A_TWO_BY_TWO
)
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
,
559 unsigned long start_offset
, index
, size
, next
;
561 unsigned long begin
, end
;
562 unsigned char *buffer
;
565 unsigned char *bytes
;
566 uint16_t *short_offsets
;
567 uint32_t *long_offsets
;
569 cairo_status_t status
;
574 size
= sizeof (tt_head_t
);
575 status
= font
->backend
->load_truetype_table (font
->scaled_font_subset
->scaled_font
,
577 (unsigned char*) &header
, &size
);
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);
584 size
= sizeof (int32_t) * (font
->num_glyphs_in_face
+ 1);
586 u
.bytes
= malloc (size
);
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
);
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;
603 begin
= be32_to_cpu (u
.long_offsets
[index
]);
604 end
= be32_to_cpu (u
.long_offsets
[index
+ 1]);
607 /* quick sanity check... */
609 status
= CAIRO_INT_STATUS_UNSUPPORTED
;
614 status
= cairo_truetype_font_align_output (font
, &next
);
618 status
= cairo_truetype_font_check_boundary (font
, next
);
622 font
->glyphs
[i
].location
= next
- start_offset
;
624 status
= cairo_truetype_font_allocate_write_buffer (font
, size
, &buffer
);
629 status
= font
->backend
->load_truetype_table (font
->scaled_font_subset
->scaled_font
,
630 TT_TAG_glyf
, begin
, buffer
, &size
);
634 status
= cairo_truetype_font_remap_composite_glyph (font
, buffer
, size
);
640 status
= cairo_truetype_font_align_output (font
, &next
);
644 font
->glyphs
[i
].location
= next
- start_offset
;
646 status
= font
->status
;
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
,
657 unsigned char *buffer
;
659 cairo_status_t status
;
665 status
= font
->backend
->load_truetype_table (font
->scaled_font_subset
->scaled_font
,
666 tag
, 0, NULL
, &size
);
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
);
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
);
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
)
691 cairo_status_t status
;
696 size
= sizeof (tt_hhea_t
);
697 status
= cairo_truetype_font_allocate_write_buffer (font
, size
, (unsigned char **) &hhea
);
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
);
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
,
716 unsigned long long_entry_size
;
717 unsigned long short_entry_size
;
722 cairo_status_t status
;
727 size
= sizeof (tt_hhea_t
);
728 status
= font
->backend
->load_truetype_table (font
->scaled_font_subset
->scaled_font
,
730 (unsigned char*) &hhea
, &size
);
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
,
741 (unsigned char **) &p
);
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
,
748 font
->glyphs
[i
].parent_index
* long_entry_size
,
749 (unsigned char *) p
, &long_entry_size
);
751 return _cairo_truetype_font_set_error (font
, status
);
755 status
= font
->backend
->load_truetype_table (font
->scaled_font_subset
->scaled_font
,
757 (num_hmetrics
- 1) * long_entry_size
,
758 (unsigned char *) p
, &short_entry_size
);
760 return _cairo_truetype_font_set_error (font
, status
);
762 status
= font
->backend
->load_truetype_table (font
->scaled_font_subset
->scaled_font
,
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
);
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
,
783 cairo_status_t status
;
788 size
= sizeof(tt_head_t
);
789 status
= font
->backend
->load_truetype_table (font
->scaled_font_subset
->scaled_font
,
791 (unsigned char*) &header
, &size
);
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);
800 for (i
= 0; i
< font
->base
.num_glyphs
+ 1; i
++)
801 cairo_truetype_font_write_be32 (font
, font
->glyphs
[i
].location
);
807 static cairo_status_t
808 cairo_truetype_font_write_maxp_table (cairo_truetype_font_t
*font
,
813 cairo_status_t status
;
818 size
= sizeof (tt_maxp_t
);
819 status
= cairo_truetype_font_allocate_write_buffer (font
, size
, (unsigned char **) &maxp
);
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
);
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
;
846 while (search_range
* 2 <= font
->num_tables
) {
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
,
866 return _cairo_truetype_font_set_error (font
, status
);
868 return CAIRO_STATUS_SUCCESS
;
872 cairo_truetype_font_calculate_checksum (cairo_truetype_font_t
*font
,
876 uint32_t *padded_end
;
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
++);
892 cairo_truetype_font_update_entry (cairo_truetype_font_t
*font
,
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
,
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
;
922 status
= cairo_truetype_font_write_offset_table (font
);
926 status
= cairo_truetype_font_align_output (font
, &start
);
931 for (i
= 0; i
< font
->num_tables
; i
++) {
932 status
= font
->truetype_tables
[i
].write (font
, font
->truetype_tables
[i
].tag
);
936 end
= _cairo_array_num_elements (&font
->output
);
937 status
= cairo_truetype_font_align_output (font
, &next
);
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
);
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);
961 *string_offsets
= NULL
;
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
,
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
;
986 cairo_truetype_font_add_truetype_table (cairo_truetype_font_t
*font
,
988 cairo_status_t (*write
) (cairo_truetype_font_t
*font
, unsigned long tag
),
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
;
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
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.
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
;
1029 if (font
->backend
->load_truetype_table (font
->scaled_font_subset
->scaled_font
,
1030 TT_TAG_cvt
, 0, NULL
,
1031 &size
) == CAIRO_STATUS_SUCCESS
)
1035 if (font
->backend
->load_truetype_table (font
->scaled_font_subset
->scaled_font
,
1036 TT_TAG_fpgm
, 0, NULL
,
1037 &size
) == CAIRO_STATUS_SUCCESS
)
1041 if (font
->backend
->load_truetype_table (font
->scaled_font_subset
->scaled_font
,
1042 TT_TAG_prep
, 0, NULL
,
1043 &size
) == CAIRO_STATUS_SUCCESS
)
1046 font
->num_tables
= 0;
1052 cairo_truetype_font_add_truetype_table (font
, TT_TAG_glyf
, cairo_truetype_font_write_glyf_table
, pos
);
1055 cairo_truetype_font_add_truetype_table (font
, TT_TAG_cmap
, cairo_truetype_font_write_cmap_table
, pos
++);
1057 cairo_truetype_font_add_truetype_table (font
, TT_TAG_cvt
, cairo_truetype_font_write_generic_table
, pos
++);
1059 cairo_truetype_font_add_truetype_table (font
, TT_TAG_fpgm
, cairo_truetype_font_write_generic_table
, 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
++);
1067 cairo_truetype_font_add_truetype_table (font
, TT_TAG_prep
, cairo_truetype_font_write_generic_table
, pos
);
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
;
1080 const unsigned long *string_offsets
= NULL
;
1081 unsigned long num_strings
= 0;
1083 status
= _cairo_truetype_font_create (font_subset
, &font
);
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
);
1094 cairo_truetype_font_create_truetype_table_list (font
);
1095 status
= cairo_truetype_font_generate (font
, &data
, &length
,
1096 &string_offsets
, &num_strings
);
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
);
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
);
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
;
1126 truetype_subset
->data
= malloc (length
);
1127 if (truetype_subset
->data
== NULL
) {
1128 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1132 memcpy (truetype_subset
->data
, data
, length
);
1134 truetype_subset
->data
= NULL
;
1135 truetype_subset
->data_length
= length
;
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
);
1145 memcpy (truetype_subset
->string_offsets
, string_offsets
, offsets_length
);
1146 truetype_subset
->num_string_offsets
= num_strings
;
1148 truetype_subset
->string_offsets
= NULL
;
1149 truetype_subset
->num_string_offsets
= 0;
1152 cairo_truetype_font_destroy (font
);
1154 return CAIRO_STATUS_SUCCESS
;
1157 free (truetype_subset
->data
);
1159 free (truetype_subset
->widths
);
1161 free (truetype_subset
->base_font
);
1163 cairo_truetype_font_destroy (font
);
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
,
1183 cairo_status_t status
;
1184 const cairo_scaled_font_backend_t
*backend
;
1185 tt_segment_map_t
*map
;
1187 unsigned int num_segments
, i
;
1189 uint16_t *start_code
;
1192 uint16_t *range_offset
;
1193 uint16_t *glyph_array
;
1196 backend
= scaled_font
->backend
;
1198 status
= backend
->load_truetype_table (scaled_font
,
1199 TT_TAG_cmap
, table_offset
,
1200 (unsigned char *) &buf
,
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
);
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
,
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
]))
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
);
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
;
1269 /* glyph not found */
1273 status
= CAIRO_STATUS_SUCCESS
;
1282 _cairo_truetype_index_to_ucs4 (cairo_scaled_font_t
*scaled_font
,
1283 unsigned long index
,
1286 cairo_status_t status
= CAIRO_INT_STATUS_UNSUPPORTED
;
1287 const cairo_scaled_font_backend_t
*backend
;
1293 backend
= scaled_font
->backend
;
1294 if (!backend
->load_truetype_table
)
1295 return CAIRO_INT_STATUS_UNSUPPORTED
;
1298 status
= backend
->load_truetype_table (scaled_font
,
1300 (unsigned char *) &buf
,
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);
1310 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
1312 status
= backend
->load_truetype_table (scaled_font
,
1314 (unsigned char *) cmap
,
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
),
1327 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
1338 #endif /* CAIRO_HAS_FONT_SUBSET */