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