only check as many Flash versions as we have functions for
[swfdec.git] / libswfdec / swfdec_font.c
blobb7878a001e5455be828ebf63b22609b261f51d2a
1 /* Swfdec
2 * Copyright (C) 2003-2006 David Schleef <ds@schleef.org>
3 * 2005-2006 Eric Anholt <eric@anholt.net>
4 * 2006-2007 Benjamin Otte <otte@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
26 #include "swfdec_font.h"
27 #include "swfdec_bits.h"
28 #include "swfdec_debug.h"
29 #include "swfdec_shape.h"
30 #include "swfdec_stroke.h"
31 #include "swfdec_swf_decoder.h"
32 #include "swfdec_tag.h"
34 G_DEFINE_TYPE (SwfdecFont, swfdec_font, SWFDEC_TYPE_CHARACTER)
36 static void
37 swfdec_font_dispose (GObject *object)
39 SwfdecFont * font = SWFDEC_FONT (object);
40 guint i;
42 if (font->glyphs) {
43 for (i = 0; i < font->glyphs->len; i++) {
44 g_object_unref (g_array_index (font->glyphs, SwfdecFontEntry, i).shape);
46 g_array_free (font->glyphs, TRUE);
47 font->glyphs = NULL;
49 if (font->desc) {
50 pango_font_description_free (font->desc);
51 font->desc = NULL;
53 if (font->name) {
54 g_free (font->name);
55 font->name = NULL;
58 G_OBJECT_CLASS (swfdec_font_parent_class)->dispose (object);
61 static void
62 swfdec_font_class_init (SwfdecFontClass * g_class)
64 GObjectClass *object_class = G_OBJECT_CLASS (g_class);
66 object_class->dispose = swfdec_font_dispose;
69 static void
70 swfdec_font_init (SwfdecFont * font)
72 font->glyphs = g_array_new (FALSE, TRUE, sizeof (SwfdecFontEntry));
75 /**
76 * swfdec_font_get_glyph:
77 * @font: a #SwfdecFont
78 * @glyph: id of glyph to render
80 * Tries to get the shape associated with the given glyph id. It is valid to
81 * call this function with any glyph id. If no such glyph exists, this function
82 * returns %NULL.
84 * Returns: the shape of the requested glyph or %NULL if no such glyph exists.
85 **/
86 SwfdecShape *
87 swfdec_font_get_glyph (SwfdecFont * font, guint glyph)
89 g_return_val_if_fail (SWFDEC_IS_FONT (font), NULL);
91 if (glyph >= font->glyphs->len)
92 return NULL;
94 return g_array_index (font->glyphs, SwfdecFontEntry, glyph).shape;
97 #if 0
98 static char *
99 convert_from_language (const char *s, SwfdecLanguage language)
101 char *ret;
102 const char *langcode;
104 switch (language) {
105 case SWFDEC_LANGUAGE_LATIN:
106 langcode = "LATIN1";
107 break;
108 case SWFDEC_LANGUAGE_JAPANESE:
109 langcode = "SHIFT_JIS";
110 break;
111 /* FIXME! */
112 case SWFDEC_LANGUAGE_KOREAN:
113 case SWFDEC_LANGUAGE_CHINESE:
114 case SWFDEC_LANGUAGE_CHINESE_TRADITIONAL:
115 default:
116 SWFDEC_ERROR ("can't convert given text from language %u", language);
117 return NULL;
119 SWFDEC_LOG ("converting text from %s", langcode);
120 ret = g_convert (s, -1, "UTF-8", langcode, NULL, NULL, NULL);
121 if (ret == NULL)
122 SWFDEC_ERROR ("given text is not in language %s", langcode);
123 return ret;
125 #endif
128 tag_func_define_font_info (SwfdecSwfDecoder *s, guint tag)
130 SwfdecFont *font;
131 guint id, len, i;
132 int reserved, wide, ansi, jis;
133 char *name;
134 /* we just assume Latin1 (FIXME: option to change this?) */
135 SwfdecLanguage language = SWFDEC_LANGUAGE_LATIN;
137 id = swfdec_bits_get_u16 (&s->b);
138 font = swfdec_swf_decoder_get_character (s, id);
139 if (!SWFDEC_IS_FONT (font)) {
140 SWFDEC_WARNING ("didn't find a font with id %u", id);
141 return SWFDEC_STATUS_OK;
143 len = swfdec_bits_get_u8 (&s->b);
144 /* this string is locale specific */
145 name = swfdec_bits_get_string_length (&s->b, len);
146 reserved = swfdec_bits_getbits (&s->b, 2);
147 font->small = swfdec_bits_getbit (&s->b);
148 jis = swfdec_bits_getbit (&s->b);
149 ansi = swfdec_bits_getbit (&s->b);
150 if (jis != 0 || ansi != 0) {
151 SWFDEC_LOG ("ansi = %d, jis = %d", ansi, jis);
152 if (tag == SWFDEC_TAG_DEFINEFONTINFO2)
153 SWFDEC_INFO ("ANSI and JIS flags are supposed to be 0 in DefineFontInfo");
154 if (jis)
155 language = SWFDEC_LANGUAGE_JAPANESE;
157 font->italic = swfdec_bits_getbit (&s->b);
158 font->bold = swfdec_bits_getbit (&s->b);
159 wide = swfdec_bits_getbit (&s->b);
160 if (tag == SWFDEC_TAG_DEFINEFONTINFO2)
161 language = swfdec_bits_get_u8 (&s->b);
162 g_free (name);
163 if (font->name) {
164 SWFDEC_LOG ("Creating font description for font %d", id);
165 font->desc = pango_font_description_new ();
166 pango_font_description_set_family_static (font->desc, font->name);
167 if (font->bold)
168 pango_font_description_set_weight (font->desc, PANGO_WEIGHT_BOLD);
169 if (font->italic)
170 pango_font_description_set_style (font->desc, PANGO_STYLE_ITALIC);
172 for (i = 0; i < font->glyphs->len; i++) {
173 g_array_index (font->glyphs, SwfdecFontEntry, i).value =
174 wide ? swfdec_bits_get_u16 (&s->b) : swfdec_bits_get_u8 (&s->b);
177 return SWFDEC_STATUS_OK;
180 static void
181 swfdec_font_parse_shape (SwfdecSwfDecoder *s, SwfdecFontEntry *entry, guint size)
183 SwfdecBits save_bits = s->b;
184 SwfdecShape *shape = g_object_new (SWFDEC_TYPE_SHAPE, NULL);
185 entry->shape = shape;
187 g_ptr_array_add (shape->fills, swfdec_pattern_new_color (0xFFFFFFFF));
188 g_ptr_array_add (shape->lines, swfdec_stroke_new (20, 0xFFFFFFFF));
190 swfdec_bits_init_bits (&s->b, &save_bits, size);
192 shape->n_fill_bits = swfdec_bits_getbits (&s->b, 4);
193 SWFDEC_LOG ("n_fill_bits = %d", shape->n_fill_bits);
194 shape->n_line_bits = swfdec_bits_getbits (&s->b, 4);
195 SWFDEC_LOG ("n_line_bits = %d", shape->n_line_bits);
196 swfdec_shape_get_recs (s, shape, swfdec_pattern_parse, swfdec_stroke_parse);
198 swfdec_bits_syncbits (&s->b);
199 if (swfdec_bits_left (&s->b)) {
200 SWFDEC_WARNING ("parsing shape didn't use %d bytes",
201 swfdec_bits_left (&s->b) / 8);
203 s->b = save_bits;
207 tag_func_define_font (SwfdecSwfDecoder * s, guint tag)
209 guint i, id, n_glyphs, offset, next_offset;
210 SwfdecFont *font;
211 SwfdecBits offsets;
213 id = swfdec_bits_get_u16 (&s->b);
214 font = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_FONT);
215 if (!font)
216 return SWFDEC_STATUS_OK;
217 font->scale_factor = SWFDEC_TEXT_SCALE_FACTOR;
219 offsets = s->b;
220 n_glyphs = swfdec_bits_get_u16 (&s->b);
221 if (n_glyphs % 2) {
222 SWFDEC_ERROR ("first offset is odd?!");
224 n_glyphs /= 2;
225 if (swfdec_bits_skip_bytes (&s->b, n_glyphs * 2 - 2) != n_glyphs * 2 - 2) {
226 SWFDEC_ERROR ("invalid glyph offsets");
227 return SWFDEC_STATUS_OK;
230 g_array_set_size (font->glyphs, n_glyphs);
231 offset = swfdec_bits_get_u16 (&offsets);
232 for (i = 0; i < n_glyphs && swfdec_bits_left (&s->b); i++) {
233 SwfdecFontEntry *entry = &g_array_index (font->glyphs, SwfdecFontEntry, i);
234 if (i + 1 == n_glyphs)
235 next_offset = offset + swfdec_bits_left (&s->b) / 8;
236 else
237 next_offset = swfdec_bits_get_u16 (&offsets);
238 swfdec_font_parse_shape (s, entry, next_offset - offset);
239 offset = next_offset;
241 if (i < n_glyphs) {
242 SWFDEC_ERROR ("data was only enough for %u glyphs, not %u", i, n_glyphs);
243 g_array_set_size (font->glyphs, i);
246 return SWFDEC_STATUS_OK;
249 static void
250 swfdec_font_parse_kerning_table (SwfdecSwfDecoder *s, SwfdecFont *font, gboolean wide_codes)
252 SwfdecBits *bits = &s->b;
253 guint n_kernings, i;
255 n_kernings = swfdec_bits_get_u16 (bits);
256 for (i = 0; i < n_kernings; i++) {
257 if (wide_codes) {
258 swfdec_bits_get_u16 (bits);
259 swfdec_bits_get_u16 (bits);
260 } else {
261 swfdec_bits_get_u8 (bits);
262 swfdec_bits_get_u8 (bits);
264 swfdec_bits_get_s16 (bits);
269 tag_func_define_font_2 (SwfdecSwfDecoder * s, guint tag)
271 SwfdecBits *bits = &s->b;
272 guint id;
273 SwfdecShape *shape;
274 SwfdecFont *font;
275 SwfdecRect rect;
277 int has_layout;
278 int shift_jis;
279 int reserved;
280 int ansi;
281 int wide_offsets;
282 int wide_codes;
283 int italic;
284 int bold;
285 int langcode;
286 int font_name_len;
287 int n_glyphs;
288 int code_table_offset;
289 int font_ascent;
290 int font_descent;
291 int font_leading;
292 int i;
293 guint skip;
295 id = swfdec_bits_get_u16 (bits);
296 font = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_FONT);
297 if (!font)
298 return SWFDEC_STATUS_OK;
299 font->scale_factor = SWFDEC_TEXT_SCALE_FACTOR;
301 has_layout = swfdec_bits_getbit (bits);
302 shift_jis = swfdec_bits_getbit (bits);
303 reserved = swfdec_bits_getbit (bits);
304 ansi = swfdec_bits_getbit (bits);
305 wide_offsets = swfdec_bits_getbit (bits);
306 wide_codes = swfdec_bits_getbit (bits);
307 italic = swfdec_bits_getbit (bits);
308 bold = swfdec_bits_getbit (bits);
310 langcode = swfdec_bits_get_u8 (bits);
311 SWFDEC_DEBUG("langcode %d", langcode);
313 font_name_len = swfdec_bits_get_u8 (bits);
314 font->name = swfdec_bits_get_string_length (bits, font_name_len);
315 if (font->name == NULL) {
316 SWFDEC_ERROR ("error reading font name");
317 } else {
318 SWFDEC_LOG (" font name = %s", font->name);
321 n_glyphs = swfdec_bits_get_u16 (bits);
322 if (wide_offsets) {
323 skip = 4 * n_glyphs;
324 if (swfdec_bits_skip_bytes (bits, skip) != skip) {
325 SWFDEC_ERROR ("could not skip %u bytes", skip);
326 return SWFDEC_STATUS_OK;
328 code_table_offset = swfdec_bits_get_u32 (bits);
329 } else {
330 skip = 2 * n_glyphs;
331 if (swfdec_bits_skip_bytes (bits, skip) != skip) {
332 SWFDEC_ERROR ("could not skip %u bytes", skip);
333 return SWFDEC_STATUS_OK;
335 code_table_offset = swfdec_bits_get_u16 (bits);
338 g_array_set_size (font->glyphs, n_glyphs);
340 for (i = 0; i < n_glyphs && swfdec_bits_left (&s->b); i++) {
341 SwfdecFontEntry *entry = &g_array_index (font->glyphs, SwfdecFontEntry, i);
342 shape = g_object_new (SWFDEC_TYPE_SHAPE, NULL);
343 entry->shape = shape;
345 g_ptr_array_add (shape->fills, swfdec_pattern_new_color (0xFFFFFFFF));
346 g_ptr_array_add (shape->lines, swfdec_stroke_new (20, 0xFFFFFFFF));
348 shape->n_fill_bits = swfdec_bits_getbits (&s->b, 4);
349 SWFDEC_LOG ("n_fill_bits = %d", shape->n_fill_bits);
350 shape->n_line_bits = swfdec_bits_getbits (&s->b, 4);
351 SWFDEC_LOG ("n_line_bits = %d", shape->n_line_bits);
353 swfdec_shape_get_recs (s, shape, swfdec_pattern_parse, swfdec_stroke_parse);
354 swfdec_bits_syncbits (&s->b);
356 if (i < n_glyphs) {
357 SWFDEC_ERROR ("data was only enough for %u glyphs, not %u", i, n_glyphs);
358 g_array_set_size (font->glyphs, i);
359 n_glyphs = i;
361 if (wide_codes) {
362 swfdec_bits_skip_bytes (bits, 2 * n_glyphs);
363 } else {
364 swfdec_bits_skip_bytes (bits, 1 * n_glyphs);
366 if (has_layout) {
367 font_ascent = swfdec_bits_get_s16 (bits);
368 font_descent = swfdec_bits_get_s16 (bits);
369 font_leading = swfdec_bits_get_s16 (bits);
370 //font_advance_table = swfdec_bits_get_s16(bits);
371 swfdec_bits_skip_bytes (bits, 2 * n_glyphs);
372 for (i = 0; i < n_glyphs && swfdec_bits_left (bits); i++) {
373 swfdec_bits_get_rect (bits, &rect);
375 swfdec_font_parse_kerning_table (s, font, wide_codes);
378 return SWFDEC_STATUS_OK;
382 tag_func_define_font_3 (SwfdecSwfDecoder * s, guint tag)
384 SwfdecBits offsets, *bits = &s->b;
385 SwfdecFont *font;
386 SwfdecLanguage language;
387 guint i, id, len, n_glyphs, offset, next_offset;
388 gboolean layout, shift_jis, ansi, wide_offsets, wide_codes;
390 id = swfdec_bits_get_u16 (bits);
391 font = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_FONT);
392 if (!font)
393 return SWFDEC_STATUS_OK;
394 SWFDEC_LOG (" id = %u", id);
395 font->scale_factor = 20 * SWFDEC_TEXT_SCALE_FACTOR;
397 layout = swfdec_bits_getbit (bits);
398 SWFDEC_LOG (" layout = %d", layout);
399 shift_jis = swfdec_bits_getbit (bits);
400 SWFDEC_LOG (" JIS = %d", shift_jis);
401 font->small = swfdec_bits_getbit (bits);
402 SWFDEC_LOG (" small = %d", font->small);
403 ansi = swfdec_bits_getbit (bits);
404 SWFDEC_LOG (" ansi = %d", ansi);
405 wide_offsets = swfdec_bits_getbit (bits);
406 SWFDEC_LOG (" wide offsets = %d", wide_offsets);
407 wide_codes = swfdec_bits_getbit (bits);
408 SWFDEC_LOG (" wide codes = %d", wide_codes);
409 if (wide_codes == 0) {
410 SWFDEC_ERROR (" wide codes should be set in DefineFont3");
412 font->italic = swfdec_bits_getbit (bits);
413 SWFDEC_LOG (" italic = %d", font->small);
414 font->bold = swfdec_bits_getbit (bits);
415 SWFDEC_LOG (" bold = %d", font->small);
416 language = swfdec_bits_get_u8 (&s->b);
417 SWFDEC_LOG (" language = %u", (guint) language);
418 len = swfdec_bits_get_u8 (&s->b);
419 font->name = swfdec_bits_get_string_length (&s->b, len);
420 if (font->name == NULL) {
421 SWFDEC_ERROR ("error reading font name");
422 } else {
423 SWFDEC_LOG (" font name = %s", font->name);
425 n_glyphs = swfdec_bits_get_u16 (&s->b);
426 SWFDEC_LOG (" n_glyphs = %u", n_glyphs);
428 offsets = *bits;
429 if (wide_offsets) {
430 if (swfdec_bits_skip_bytes (bits, n_glyphs * 4 + 4) != n_glyphs * 4 + 4) {
431 SWFDEC_ERROR ("DefineFont3 too short");
432 return SWFDEC_STATUS_OK;
434 offset = swfdec_bits_get_u32 (&offsets);
435 } else {
436 if (swfdec_bits_skip_bytes (bits, n_glyphs * 2 + 2) != n_glyphs * 2 + 2) {
437 SWFDEC_ERROR ("DefineFont3 too short");
438 return SWFDEC_STATUS_OK;
440 offset = swfdec_bits_get_u16 (&offsets);
442 g_array_set_size (font->glyphs, n_glyphs);
443 for (i = 0; i < n_glyphs && swfdec_bits_left (&s->b); i++) {
444 SwfdecFontEntry *entry = &g_array_index (font->glyphs, SwfdecFontEntry, i);
445 if (wide_offsets)
446 next_offset = swfdec_bits_get_u32 (&offsets);
447 else
448 next_offset = swfdec_bits_get_u16 (&offsets);
449 swfdec_font_parse_shape (s, entry, next_offset - offset);
450 offset = next_offset;
452 if (i < n_glyphs) {
453 SWFDEC_ERROR ("data was only enough for %u glyphs, not %u", i, n_glyphs);
454 g_array_set_size (font->glyphs, i);
455 n_glyphs = i;
457 for (i = 0; i < n_glyphs && swfdec_bits_left (bits); i++) {
458 SwfdecFontEntry *entry = &g_array_index (font->glyphs, SwfdecFontEntry, i);
459 if (wide_codes)
460 entry->value = swfdec_bits_get_u16 (bits);
461 else
462 entry->value = swfdec_bits_get_u8 (bits);
464 if (layout) {
465 guint ascent, descent, leading;
467 ascent = swfdec_bits_get_u16 (bits);
468 descent = swfdec_bits_get_u16 (bits);
469 leading = swfdec_bits_get_u16 (bits);
470 for (i = 0; i < n_glyphs && swfdec_bits_left (bits); i++) {
471 /* guint advance = */ swfdec_bits_get_u16 (bits);
473 for (i = 0; i < n_glyphs && swfdec_bits_left (bits); i++) {
474 SwfdecRect rect;
475 swfdec_bits_get_rect (bits, &rect);
477 swfdec_font_parse_kerning_table (s, font, wide_codes);
480 return SWFDEC_STATUS_OK;