translate conditions differently for menu buttons and normal ones
[swfdec.git] / libswfdec / swfdec_button.c
blob3cbfb7ab4c1d67889b591de8fe6ecf7c4c77df0e
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 SwfdecMovie *
65 swfdec_button_create_movie (SwfdecGraphic *graphic, gsize *size)
67 SwfdecButton *button = SWFDEC_BUTTON (graphic);
68 SwfdecButtonMovie *movie = g_object_new (SWFDEC_TYPE_BUTTON_MOVIE, NULL);
70 movie->button = g_object_ref (button);
71 *size = sizeof (SwfdecButtonMovie);
72 if (button->events)
73 SWFDEC_MOVIE (movie)->events = swfdec_event_list_copy (button->events);
75 return SWFDEC_MOVIE (movie);
78 static void
79 swfdec_button_class_init (SwfdecButtonClass * g_class)
81 GObjectClass *object_class = G_OBJECT_CLASS (g_class);
82 SwfdecGraphicClass *graphic_class = SWFDEC_GRAPHIC_CLASS (g_class);
84 object_class->dispose = swfdec_button_dispose;
86 graphic_class->create_movie = swfdec_button_create_movie;
89 static guint
90 swfdec_button_translate_conditions (guint conditions, gboolean menu)
92 static const guint events[][2] = {
93 /* idle => over up */ { 1 << SWFDEC_EVENT_ROLL_OVER, 1 << SWFDEC_EVENT_ROLL_OVER },
94 /* over up => idle */ { 1 << SWFDEC_EVENT_ROLL_OUT, 1 << SWFDEC_EVENT_ROLL_OUT },
95 /* over up => over down */ { 1 << SWFDEC_EVENT_PRESS, 1 << SWFDEC_EVENT_PRESS },
96 /* over down => over up */ { 1 << SWFDEC_EVENT_RELEASE, 1 << SWFDEC_EVENT_RELEASE },
97 /* over down => out down */ { 1 << SWFDEC_EVENT_DRAG_OUT, 0 },
98 /* out down => over down */ { 1 << SWFDEC_EVENT_DRAG_OVER, 0 },
99 /* out down => idle */ { 1 << SWFDEC_EVENT_RELEASE_OUTSIDE, 1 << SWFDEC_EVENT_RELEASE_OUTSIDE },
100 /* idle => over down */ { 0, 1 << SWFDEC_EVENT_DRAG_OVER },
101 /* over down => idle */ { 0, 1 << SWFDEC_EVENT_DRAG_OUT }
103 guint i, ret;
105 ret = 0;
106 for (i = 0; i <= G_N_ELEMENTS (events); i++) {
107 if (conditions & (1 << i))
108 ret |= events[i][menu ? 1 : 0];
110 return ret;
114 tag_func_define_button_2 (SwfdecSwfDecoder * s, guint tag)
116 SwfdecBits bits;
117 int id, reserved;
118 guint length;
119 SwfdecButton *button;
120 char *script_name;
122 id = swfdec_bits_get_u16 (&s->b);
123 button = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_BUTTON);
124 if (!button)
125 return SWFDEC_STATUS_OK;
127 SWFDEC_LOG (" ID: %d", id);
129 reserved = swfdec_bits_getbits (&s->b, 7);
130 button->menubutton = swfdec_bits_getbit (&s->b) ? TRUE : FALSE;
131 length = swfdec_bits_get_u16 (&s->b);
133 SWFDEC_LOG (" reserved = %d", reserved);
134 SWFDEC_LOG (" menu = %d", button->menubutton);
135 SWFDEC_LOG (" length of region = %d", length);
137 if (length)
138 swfdec_bits_init_bits (&bits, &s->b, length > 2 ? length - 2 : 0);
139 else
140 swfdec_bits_init_bits (&bits, &s->b, swfdec_bits_left (&s->b) / 8);
141 while (swfdec_bits_peek_u8 (&bits)) {
142 SwfdecBits tmp;
143 SwfdecBuffer *buffer;
144 cairo_matrix_t trans;
145 SwfdecColorTransform ctrans;
146 guint states;
147 gboolean has_blend_mode, has_filters;
149 /* we parse the placement info into buffers each containing one palcement */
150 tmp = bits;
152 if (s->version >= 8) {
153 reserved = swfdec_bits_getbits (&bits, 2);
154 has_blend_mode = swfdec_bits_getbit (&bits);
155 has_filters = swfdec_bits_getbit (&bits);
156 SWFDEC_LOG (" reserved = %d", reserved);
157 SWFDEC_LOG (" has_blend_mode = %d", has_blend_mode);
158 SWFDEC_LOG (" has_filters = %d", has_filters);
159 } else {
160 reserved = swfdec_bits_getbits (&bits, 4);
161 has_blend_mode = 0;
162 has_filters = 0;
163 SWFDEC_LOG (" reserved = %d", reserved);
165 states = swfdec_bits_getbits (&bits, 4);
166 swfdec_bits_skip_bytes (&bits, 4);
168 SWFDEC_LOG (" states: %s%s%s%s",
169 states & (1 << SWFDEC_BUTTON_HIT) ? "HIT " : "",
170 states & (1 << SWFDEC_BUTTON_DOWN) ? "DOWN " : "",
171 states & (1 << SWFDEC_BUTTON_OVER) ? "OVER " : "",
172 states & (1 << SWFDEC_BUTTON_UP) ? "UP " : "");
174 swfdec_bits_get_matrix (&bits, &trans, NULL);
175 SWFDEC_LOG ("matrix: %g %g %g %g %g %g",
176 trans.xx, trans.yy,
177 trans.xy, trans.yx,
178 trans.x0, trans.y0);
179 swfdec_bits_get_color_transform (&bits, &ctrans);
181 if (has_filters) {
182 GSList *list = swfdec_filter_parse (SWFDEC_DECODER (s)->player, &bits);
183 g_slist_free (list);
185 if (has_blend_mode) {
186 guint blend_mode = swfdec_bits_get_u8 (&bits);
187 SWFDEC_LOG (" blend mode = %u", blend_mode);
189 buffer = swfdec_bits_get_buffer (&tmp, (swfdec_bits_left (&tmp) - swfdec_bits_left (&bits)) / 8);
190 g_assert (buffer);
191 button->records = g_slist_prepend (button->records, buffer);
193 swfdec_bits_get_u8 (&bits);
194 if (swfdec_bits_left (&bits)) {
195 SWFDEC_WARNING ("%u bytes left when parsing button records", swfdec_bits_left (&bits) / 8);
197 button->records = g_slist_reverse (button->records);
199 script_name = g_strdup_printf ("Button%u", SWFDEC_CHARACTER (button)->id);
200 while (length != 0) {
201 guint condition, key;
203 length = swfdec_bits_get_u16 (&s->b);
204 if (length)
205 swfdec_bits_init_bits (&bits, &s->b, length > 2 ? length - 2 : 0);
206 else
207 swfdec_bits_init_bits (&bits, &s->b, swfdec_bits_left (&s->b) / 8);
208 condition = swfdec_bits_get_u16 (&bits);
209 key = condition >> 9;
210 condition &= 0x1FF;
211 condition = swfdec_button_translate_conditions (condition, button->menubutton);
213 SWFDEC_LOG (" length = %d", length);
215 if (button->events == NULL)
216 button->events = swfdec_event_list_new (SWFDEC_DECODER (s)->player);
217 SWFDEC_LOG (" new event for condition %u (key %u)", condition, key);
218 swfdec_event_list_parse (button->events, &bits, s->version, condition, key,
219 script_name);
220 if (swfdec_bits_left (&bits)) {
221 SWFDEC_WARNING ("%u bytes left after parsing script", swfdec_bits_left (&bits) / 8);
224 g_free (script_name);
226 return SWFDEC_STATUS_OK;
230 tag_func_define_button (SwfdecSwfDecoder * s, guint tag)
232 SWFDEC_ERROR ("implement DefineButton again");
234 return SWFDEC_STATUS_OK;