add a test for just-fixed crasher
[swfdec.git] / swfdec / swfdec_button.c
blobaa3a8c1b2df9c632ab15f1848181474c8af1fc9d
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
25 #include <string.h>
26 #include "swfdec_button.h"
27 #include "swfdec_button_movie.h"
28 #include "swfdec_debug.h"
29 #include "swfdec_filter.h"
30 #include "swfdec_sound.h"
31 #include "swfdec_sprite.h"
34 G_DEFINE_TYPE (SwfdecButton, swfdec_button, SWFDEC_TYPE_GRAPHIC)
36 static void
37 swfdec_button_init (SwfdecButton * button)
41 static void
42 swfdec_button_dispose (GObject *object)
44 guint i;
45 SwfdecButton *button = SWFDEC_BUTTON (object);
47 g_slist_foreach (button->records, (GFunc) swfdec_buffer_unref, NULL);
48 g_slist_free (button->records);
49 button->records = NULL;
50 if (button->events != NULL) {
51 swfdec_event_list_free (button->events);
52 button->events = NULL;
54 for (i = 0; i < 4; i++) {
55 if (button->sounds[i]) {
56 swfdec_sound_chunk_free (button->sounds[i]);
57 button->sounds[i] = NULL;
61 G_OBJECT_CLASS (swfdec_button_parent_class)->dispose (G_OBJECT (button));
64 static void
65 swfdec_button_class_init (SwfdecButtonClass * g_class)
67 GObjectClass *object_class = G_OBJECT_CLASS (g_class);
68 SwfdecGraphicClass *graphic_class = SWFDEC_GRAPHIC_CLASS (g_class);
70 object_class->dispose = swfdec_button_dispose;
72 graphic_class->movie_type = SWFDEC_TYPE_BUTTON_MOVIE;
75 static guint
76 swfdec_button_translate_conditions (guint conditions, gboolean menu)
78 static const guint events[][2] = {
79 /* idle => over up */ { 1 << SWFDEC_EVENT_ROLL_OVER, 1 << SWFDEC_EVENT_ROLL_OVER },
80 /* over up => idle */ { 1 << SWFDEC_EVENT_ROLL_OUT, 1 << SWFDEC_EVENT_ROLL_OUT },
81 /* over up => over down */ { 1 << SWFDEC_EVENT_PRESS, 1 << SWFDEC_EVENT_PRESS },
82 /* over down => over up */ { 1 << SWFDEC_EVENT_RELEASE, 1 << SWFDEC_EVENT_RELEASE },
83 /* over down => out down */ { 1 << SWFDEC_EVENT_DRAG_OUT, 0 },
84 /* out down => over down */ { 1 << SWFDEC_EVENT_DRAG_OVER, 0 },
85 /* out down => idle */ { 1 << SWFDEC_EVENT_RELEASE_OUTSIDE, 1 << SWFDEC_EVENT_RELEASE_OUTSIDE },
86 /* idle => over down */ { 0, 1 << SWFDEC_EVENT_DRAG_OVER },
87 /* over down => idle */ { 0, 1 << SWFDEC_EVENT_DRAG_OUT }
89 guint i, ret;
91 ret = 0;
92 for (i = 0; i <= G_N_ELEMENTS (events); i++) {
93 if (conditions & (1 << i))
94 ret |= events[i][menu ? 1 : 0];
96 return ret;
99 int
100 tag_func_define_button_2 (SwfdecSwfDecoder * s, guint tag)
102 SwfdecBits bits;
103 int id, reserved;
104 guint length;
105 SwfdecButton *button;
106 char *script_name;
108 id = swfdec_bits_get_u16 (&s->b);
109 button = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_BUTTON);
110 if (!button)
111 return SWFDEC_STATUS_OK;
113 SWFDEC_LOG (" ID: %d", id);
115 reserved = swfdec_bits_getbits (&s->b, 7);
116 button->menubutton = swfdec_bits_getbit (&s->b) ? TRUE : FALSE;
117 length = swfdec_bits_get_u16 (&s->b);
119 SWFDEC_LOG (" reserved = %d", reserved);
120 SWFDEC_LOG (" menu = %d", button->menubutton);
121 SWFDEC_LOG (" length of region = %d", length);
123 if (length)
124 swfdec_bits_init_bits (&bits, &s->b, length > 2 ? length - 2 : 0);
125 else
126 swfdec_bits_init_bits (&bits, &s->b, swfdec_bits_left (&s->b) / 8);
127 while (swfdec_bits_peek_u8 (&bits)) {
128 SwfdecBits tmp;
129 SwfdecBuffer *buffer;
130 cairo_matrix_t trans;
131 SwfdecColorTransform ctrans;
132 guint states, gid;
133 gboolean has_blend_mode, has_filters;
135 /* we parse the placement info into buffers each containing one palcement */
136 tmp = bits;
138 if (s->version >= 8) {
139 reserved = swfdec_bits_getbits (&bits, 2);
140 has_blend_mode = swfdec_bits_getbit (&bits);
141 has_filters = swfdec_bits_getbit (&bits);
142 SWFDEC_LOG (" reserved = %d", reserved);
143 SWFDEC_LOG (" has_blend_mode = %d", has_blend_mode);
144 SWFDEC_LOG (" has_filters = %d", has_filters);
145 } else {
146 reserved = swfdec_bits_getbits (&bits, 4);
147 has_blend_mode = 0;
148 has_filters = 0;
149 SWFDEC_LOG (" reserved = %d", reserved);
151 states = swfdec_bits_getbits (&bits, 4);
152 gid = swfdec_bits_get_u16 (&bits);
153 swfdec_bits_get_u16 (&bits);
155 SWFDEC_LOG (" states: %s%s%s%s",
156 states & (1 << SWFDEC_BUTTON_HIT) ? "HIT " : "",
157 states & (1 << SWFDEC_BUTTON_DOWN) ? "DOWN " : "",
158 states & (1 << SWFDEC_BUTTON_OVER) ? "OVER " : "",
159 states & (1 << SWFDEC_BUTTON_UP) ? "UP " : "");
161 swfdec_bits_get_matrix (&bits, &trans, NULL);
162 SWFDEC_LOG ("matrix: %g %g %g %g %g %g",
163 trans.xx, trans.yy,
164 trans.xy, trans.yx,
165 trans.x0, trans.y0);
166 swfdec_bits_get_color_transform (&bits, &ctrans);
168 if (has_filters) {
169 GSList *list = swfdec_filter_parse (&bits);
170 g_slist_free (list);
172 if (has_blend_mode) {
173 guint blend_mode = swfdec_bits_get_u8 (&bits);
174 SWFDEC_LOG (" blend mode = %u", blend_mode);
176 buffer = swfdec_bits_get_buffer (&tmp, (swfdec_bits_left (&tmp) - swfdec_bits_left (&bits)) / 8);
177 if (buffer == NULL)
178 break;
179 button->records = g_slist_prepend (button->records, buffer);
180 /* add hit state movies to button's extents */
181 if (states & (1 << SWFDEC_BUTTON_HIT)) {
182 SwfdecGraphic *graphic = swfdec_swf_decoder_get_character (s, gid);
183 if (SWFDEC_IS_GRAPHIC (graphic)) {
184 SwfdecRect rect;
185 swfdec_rect_transform (&rect, &graphic->extents, &trans);
186 swfdec_rect_union (&SWFDEC_GRAPHIC (button)->extents, &SWFDEC_GRAPHIC (button)->extents, &rect);
187 } else {
188 SWFDEC_ERROR ("graphic for id %u not found", gid);
192 swfdec_bits_get_u8 (&bits);
193 if (swfdec_bits_left (&bits)) {
194 SWFDEC_WARNING ("%u bytes left when parsing button records", swfdec_bits_left (&bits) / 8);
196 button->records = g_slist_reverse (button->records);
198 script_name = g_strdup_printf ("Button%u", SWFDEC_CHARACTER (button)->id);
199 while (length != 0) {
200 guint condition, key;
202 length = swfdec_bits_get_u16 (&s->b);
203 if (length)
204 swfdec_bits_init_bits (&bits, &s->b, length > 2 ? length - 2 : 0);
205 else
206 swfdec_bits_init_bits (&bits, &s->b, swfdec_bits_left (&s->b) / 8);
207 condition = swfdec_bits_get_u16 (&bits);
208 key = condition >> 9;
209 condition &= 0x1FF;
210 condition = swfdec_button_translate_conditions (condition, button->menubutton);
211 if (key)
212 condition |= 1 << SWFDEC_EVENT_KEY_DOWN;
214 SWFDEC_LOG (" length = %d", length);
216 if (button->events == NULL)
217 button->events = swfdec_event_list_new ();
218 SWFDEC_LOG (" new event for condition %u (key %u)", condition, key);
219 swfdec_event_list_parse (button->events, &bits, s->version, condition, key,
220 script_name);
221 if (swfdec_bits_left (&bits)) {
222 SWFDEC_WARNING ("%u bytes left after parsing script", swfdec_bits_left (&bits) / 8);
225 g_free (script_name);
227 return SWFDEC_STATUS_OK;
231 tag_func_define_button (SwfdecSwfDecoder * s, guint tag)
233 guint id, flags;
234 SwfdecButton *button;
236 id = swfdec_bits_get_u16 (&s->b);
237 button = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_BUTTON);
238 if (!button)
239 return SWFDEC_STATUS_OK;
241 SWFDEC_LOG (" ID: %d", id);
243 while (swfdec_bits_peek_u8 (&s->b)) {
244 SwfdecBits tmp;
245 SwfdecBuffer *buffer;
246 cairo_matrix_t matrix;
247 guint gid;
249 tmp = s->b;
250 flags = swfdec_bits_get_u8 (&tmp);
251 gid = swfdec_bits_get_u16 (&tmp);
252 swfdec_bits_get_u16 (&tmp);
253 swfdec_bits_get_matrix (&tmp, &matrix, NULL);
254 buffer = swfdec_bits_get_buffer (&s->b, (swfdec_bits_left (&s->b) - swfdec_bits_left (&tmp)) / 8);
255 if (buffer == NULL)
256 break;
257 button->records = g_slist_prepend (button->records, buffer);
258 /* add hit state movies to button's extents */
259 if (flags & (1 << SWFDEC_BUTTON_HIT)) {
260 SwfdecGraphic *graphic = swfdec_swf_decoder_get_character (s, gid);
261 if (SWFDEC_IS_GRAPHIC (graphic)) {
262 SwfdecRect rect;
263 swfdec_rect_transform (&rect, &graphic->extents, &matrix);
264 swfdec_rect_union (&SWFDEC_GRAPHIC (button)->extents, &SWFDEC_GRAPHIC (button)->extents, &rect);
265 } else {
266 SWFDEC_ERROR ("graphic for id %u not found", gid);
271 swfdec_bits_get_u8 (&s->b);
272 button->records = g_slist_reverse (button->records);
274 if (swfdec_bits_peek_u8 (&s->b)) {
275 char *script_name = g_strdup_printf ("Button%u", id);
276 button->events = swfdec_event_list_new ();
277 SWFDEC_LOG (" event for button press");
278 swfdec_event_list_parse (button->events, &s->b, s->version, 1 << SWFDEC_EVENT_RELEASE,
279 0, script_name);
280 g_free (script_name);
281 } else {
282 swfdec_bits_get_u8 (&s->b);
284 if (swfdec_bits_left (&s->b)) {
285 SWFDEC_WARNING ("%u bytes left after parsing script", swfdec_bits_left (&s->b) / 8);
288 return SWFDEC_STATUS_OK;