add blend mode tests
[swfdec.git] / swfdec / swfdec_font.c
blob545a8768b3686832f151b43a6b7bd177d2e0d3f8
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_parser.h"
30 #include "swfdec_swf_decoder.h"
31 #include "swfdec_tag.h"
33 G_DEFINE_TYPE (SwfdecFont, swfdec_font, SWFDEC_TYPE_CHARACTER)
35 static void
36 swfdec_font_dispose (GObject *object)
38 SwfdecFont * font = SWFDEC_FONT (object);
39 guint i;
41 if (font->glyphs) {
42 for (i = 0; i < font->glyphs->len; i++) {
43 SwfdecDraw *draw = g_array_index (font->glyphs, SwfdecFontEntry, i).draw;
44 if (draw)
45 g_object_unref (draw);
47 g_array_free (font->glyphs, TRUE);
48 font->glyphs = NULL;
50 if (font->desc) {
51 pango_font_description_free (font->desc);
52 font->desc = NULL;
54 g_free (font->name);
55 font->name = NULL;
56 g_free (font->display_name);
57 font->display_name = NULL;
58 g_free (font->copyright);
59 font->copyright = NULL;
61 G_OBJECT_CLASS (swfdec_font_parent_class)->dispose (object);
64 static void
65 swfdec_font_class_init (SwfdecFontClass * g_class)
67 GObjectClass *object_class = G_OBJECT_CLASS (g_class);
69 object_class->dispose = swfdec_font_dispose;
72 static void
73 swfdec_font_init (SwfdecFont * font)
75 font->glyphs = g_array_new (FALSE, TRUE, sizeof (SwfdecFontEntry));
78 /**
79 * swfdec_font_get_glyph:
80 * @font: a #SwfdecFont
81 * @glyph: id of glyph to render
83 * Tries to get the shape associated with the given glyph id. It is valid to
84 * call this function with any glyph id. If no such glyph exists, this function
85 * returns %NULL.
87 * Returns: the shape of the requested glyph or %NULL if no such glyph exists.
88 **/
89 SwfdecDraw *
90 swfdec_font_get_glyph (SwfdecFont * font, guint glyph)
92 g_return_val_if_fail (SWFDEC_IS_FONT (font), NULL);
94 if (glyph >= font->glyphs->len)
95 return NULL;
97 return g_array_index (font->glyphs, SwfdecFontEntry, glyph).draw;
100 #if 0
101 static char *
102 convert_from_language (const char *s, SwfdecLanguage language)
104 char *ret;
105 const char *langcode;
107 switch (language) {
108 case SWFDEC_LANGUAGE_LATIN:
109 langcode = "LATIN1";
110 break;
111 case SWFDEC_LANGUAGE_JAPANESE:
112 langcode = "SHIFT_JIS";
113 break;
114 /* FIXME! */
115 case SWFDEC_LANGUAGE_KOREAN:
116 case SWFDEC_LANGUAGE_CHINESE:
117 case SWFDEC_LANGUAGE_CHINESE_TRADITIONAL:
118 default:
119 SWFDEC_ERROR ("can't convert given text from language %u", language);
120 return NULL;
122 SWFDEC_LOG ("converting text from %s", langcode);
123 ret = g_convert (s, -1, "UTF-8", langcode, NULL, NULL, NULL);
124 if (ret == NULL)
125 SWFDEC_ERROR ("given text is not in language %s", langcode);
126 return ret;
128 #endif
131 tag_func_define_font_info (SwfdecSwfDecoder *s, guint tag)
133 SwfdecFont *font;
134 guint id, len, i;
135 int reserved, wide, ansi, jis;
136 char *name;
137 /* we just assume Latin1 (FIXME: option to change this?) */
138 SwfdecLanguage language = SWFDEC_LANGUAGE_LATIN;
140 id = swfdec_bits_get_u16 (&s->b);
141 font = swfdec_swf_decoder_get_character (s, id);
142 if (!SWFDEC_IS_FONT (font)) {
143 SWFDEC_WARNING ("didn't find a font with id %u", id);
144 return SWFDEC_STATUS_OK;
146 len = swfdec_bits_get_u8 (&s->b);
147 /* this string is locale specific */
148 name = swfdec_bits_get_string_length (&s->b, len, s->version);
149 reserved = swfdec_bits_getbits (&s->b, 2);
150 font->small = swfdec_bits_getbit (&s->b);
151 jis = swfdec_bits_getbit (&s->b);
152 ansi = swfdec_bits_getbit (&s->b);
153 if (jis != 0 || ansi != 0) {
154 SWFDEC_LOG ("ansi = %d, jis = %d", ansi, jis);
155 if (tag == SWFDEC_TAG_DEFINEFONTINFO2)
156 SWFDEC_INFO ("ANSI and JIS flags are supposed to be 0 in DefineFontInfo");
157 if (jis)
158 language = SWFDEC_LANGUAGE_JAPANESE;
160 font->italic = swfdec_bits_getbit (&s->b);
161 font->bold = swfdec_bits_getbit (&s->b);
162 wide = swfdec_bits_getbit (&s->b);
163 if (tag == SWFDEC_TAG_DEFINEFONTINFO2)
164 language = swfdec_bits_get_u8 (&s->b);
165 g_free (name);
166 if (font->name) {
167 SWFDEC_LOG ("Creating font description for font %d", id);
168 font->desc = pango_font_description_new ();
169 pango_font_description_set_family_static (font->desc, font->name);
170 if (font->bold)
171 pango_font_description_set_weight (font->desc, PANGO_WEIGHT_BOLD);
172 if (font->italic)
173 pango_font_description_set_style (font->desc, PANGO_STYLE_ITALIC);
175 for (i = 0; i < font->glyphs->len; i++) {
176 g_array_index (font->glyphs, SwfdecFontEntry, i).value =
177 wide ? swfdec_bits_get_u16 (&s->b) : swfdec_bits_get_u8 (&s->b);
180 return SWFDEC_STATUS_OK;
183 static void
184 swfdec_font_parse_shape (SwfdecSwfDecoder *s, SwfdecFontEntry *entry, guint size)
186 SwfdecBits bits;
187 SwfdecShapeParser *parser;
188 GSList *list;
190 swfdec_bits_init_bits (&bits, &s->b, size);
191 parser = swfdec_shape_parser_new (NULL, NULL, NULL);
192 swfdec_shape_parser_parse (parser, &bits);
193 list = swfdec_shape_parser_free (parser);
194 if (list) {
195 entry->draw = g_object_ref (list->data);
196 g_slist_foreach (list, (GFunc) g_object_unref, NULL);
197 g_slist_free (list);
198 } else {
199 entry->draw = NULL;
202 if (swfdec_bits_left (&bits)) {
203 SWFDEC_WARNING ("parsing shape didn't use %d bytes",
204 swfdec_bits_left (&bits) / 8);
209 tag_func_define_font (SwfdecSwfDecoder * s, guint tag)
211 guint i, id, n_glyphs, offset, next_offset;
212 SwfdecFont *font;
213 SwfdecBits offsets;
215 id = swfdec_bits_get_u16 (&s->b);
216 font = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_FONT);
217 if (!font)
218 return SWFDEC_STATUS_OK;
219 font->scale_factor = SWFDEC_TEXT_SCALE_FACTOR;
221 offset = swfdec_bits_get_u16 (&s->b);
222 if (offset % 2) {
223 SWFDEC_ERROR ("first offset is odd?!");
225 n_glyphs = offset / 2;
226 if (n_glyphs == 0)
227 return SWFDEC_STATUS_OK;
228 swfdec_bits_init_bits (&offsets, &s->b, offset - 2);
230 g_array_set_size (font->glyphs, n_glyphs);
231 for (i = 0; i < n_glyphs && swfdec_bits_left (&s->b); i++) {
232 SwfdecFontEntry *entry = &g_array_index (font->glyphs, SwfdecFontEntry, i);
233 if (i + 1 == n_glyphs)
234 next_offset = offset + swfdec_bits_left (&s->b) / 8;
235 else
236 next_offset = swfdec_bits_get_u16 (&offsets);
237 swfdec_font_parse_shape (s, entry, next_offset - offset);
238 offset = next_offset;
240 if (i < n_glyphs) {
241 SWFDEC_ERROR ("data was only enough for %u glyphs, not %u", i, n_glyphs);
242 g_array_set_size (font->glyphs, i);
245 return SWFDEC_STATUS_OK;
248 static void
249 swfdec_font_parse_kerning_table (SwfdecSwfDecoder *s, SwfdecFont *font, gboolean wide_codes)
251 SwfdecBits *bits = &s->b;
252 guint n_kernings, i;
254 n_kernings = swfdec_bits_get_u16 (bits);
255 for (i = 0; i < n_kernings; i++) {
256 if (wide_codes) {
257 swfdec_bits_get_u16 (bits);
258 swfdec_bits_get_u16 (bits);
259 } else {
260 swfdec_bits_get_u8 (bits);
261 swfdec_bits_get_u8 (bits);
263 swfdec_bits_get_s16 (bits);
268 tag_func_define_font_2 (SwfdecSwfDecoder * s, guint tag)
270 SwfdecBits offsets, *bits = &s->b;
271 SwfdecFont *font;
272 SwfdecLanguage language;
273 guint i, id, len, n_glyphs, offset, next_offset;
274 gboolean layout, shift_jis, ansi, wide_offsets, wide_codes;
276 id = swfdec_bits_get_u16 (bits);
277 font = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_FONT);
278 if (!font)
279 return SWFDEC_STATUS_OK;
280 SWFDEC_LOG (" id = %u", id);
281 font->scale_factor = SWFDEC_TEXT_SCALE_FACTOR * (tag == SWFDEC_TAG_DEFINEFONT3 ? 20 : 1);
283 layout = swfdec_bits_getbit (bits);
284 SWFDEC_LOG (" layout = %d", layout);
285 shift_jis = swfdec_bits_getbit (bits);
286 SWFDEC_LOG (" JIS = %d", shift_jis);
287 font->small = swfdec_bits_getbit (bits);
288 SWFDEC_LOG (" small = %d", font->small);
289 ansi = swfdec_bits_getbit (bits);
290 SWFDEC_LOG (" ansi = %d", ansi);
291 wide_offsets = swfdec_bits_getbit (bits);
292 SWFDEC_LOG (" wide offsets = %d", wide_offsets);
293 wide_codes = swfdec_bits_getbit (bits);
294 SWFDEC_LOG (" wide codes = %d", wide_codes);
295 font->italic = swfdec_bits_getbit (bits);
296 SWFDEC_LOG (" italic = %d", font->italic);
297 font->bold = swfdec_bits_getbit (bits);
298 SWFDEC_LOG (" bold = %d", font->bold);
299 language = swfdec_bits_get_u8 (&s->b);
300 SWFDEC_LOG (" language = %u", (guint) language);
301 len = swfdec_bits_get_u8 (&s->b);
302 font->name = swfdec_bits_get_string_length (&s->b, len, s->version);
303 if (font->name == NULL) {
304 SWFDEC_ERROR ("error reading font name");
305 } else {
306 SWFDEC_LOG (" font name = %s", font->name);
308 n_glyphs = swfdec_bits_get_u16 (&s->b);
309 SWFDEC_LOG (" n_glyphs = %u", n_glyphs);
311 if (wide_offsets) {
312 offset = swfdec_bits_get_u32 (bits);
313 swfdec_bits_init_bits (&offsets, bits, n_glyphs * 4);
314 } else {
315 offset = swfdec_bits_get_u16 (bits);
316 swfdec_bits_init_bits (&offsets, bits, n_glyphs * 2);
318 g_array_set_size (font->glyphs, n_glyphs);
319 for (i = 0; i < n_glyphs && swfdec_bits_left (bits); i++) {
320 SwfdecFontEntry *entry = &g_array_index (font->glyphs, SwfdecFontEntry, i);
321 if (wide_offsets)
322 next_offset = swfdec_bits_get_u32 (&offsets);
323 else
324 next_offset = swfdec_bits_get_u16 (&offsets);
325 swfdec_font_parse_shape (s, entry, next_offset - offset);
326 offset = next_offset;
328 if (i < n_glyphs) {
329 SWFDEC_ERROR ("data was only enough for %u glyphs, not %u", i, n_glyphs);
330 g_array_set_size (font->glyphs, i);
331 n_glyphs = i;
333 for (i = 0; i < n_glyphs && swfdec_bits_left (bits); i++) {
334 SwfdecFontEntry *entry = &g_array_index (font->glyphs, SwfdecFontEntry, i);
335 if (wide_codes)
336 entry->value = swfdec_bits_get_u16 (bits);
337 else
338 entry->value = swfdec_bits_get_u8 (bits);
340 if (layout) {
341 font->ascent = swfdec_bits_get_u16 (bits);
342 font->descent = swfdec_bits_get_u16 (bits);
343 font->leading = swfdec_bits_get_u16 (bits);
344 for (i = 0; i < n_glyphs && swfdec_bits_left (bits); i++) {
345 SwfdecFontEntry *entry = &g_array_index (font->glyphs, SwfdecFontEntry, i);
346 entry->advance = swfdec_bits_get_u16 (bits);
348 for (i = 0; i < n_glyphs && swfdec_bits_left (bits); i++) {
349 SwfdecFontEntry *entry = &g_array_index (font->glyphs, SwfdecFontEntry, i);
350 swfdec_bits_get_rect (bits, &entry->extents);
352 swfdec_font_parse_kerning_table (s, font, wide_codes);
353 } else {
354 font->ascent = font->scale_factor;
355 font->descent = 0;
356 font->leading = 0;
357 for (i = 0; i < n_glyphs && swfdec_bits_left (bits); i++) {
358 SwfdecFontEntry *entry = &g_array_index (font->glyphs, SwfdecFontEntry, i);
359 entry->advance = font->scale_factor;
360 entry->extents.x0 = entry->extents.y0 = 0;
361 entry->extents.x1 = entry->extents.y1 = font->scale_factor;
365 return SWFDEC_STATUS_OK;
369 tag_func_define_font_name (SwfdecSwfDecoder * s, guint tag)
371 guint id;
372 SwfdecFont *font;
374 id = swfdec_bits_get_u16 (&s->b);
375 font = swfdec_swf_decoder_get_character (s, id);
377 if (!SWFDEC_IS_FONT (font)) {
378 SWFDEC_ERROR ("didn't find a font with id %u", id);
379 return SWFDEC_STATUS_OK;
382 font->display_name = swfdec_bits_get_string (&s->b, s->version);
383 font->copyright = swfdec_bits_get_string (&s->b, s->version);
385 return SWFDEC_STATUS_OK;