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
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
)
37 swfdec_button_init (SwfdecButton
* button
)
42 swfdec_button_dispose (GObject
*object
)
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
));
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
;
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
}
92 for (i
= 0; i
<= G_N_ELEMENTS (events
); i
++) {
93 if (conditions
& (1 << i
))
94 ret
|= events
[i
][menu
? 1 : 0];
100 tag_func_define_button_2 (SwfdecSwfDecoder
* s
, guint tag
)
105 SwfdecButton
*button
;
108 id
= swfdec_bits_get_u16 (&s
->b
);
109 button
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_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
);
124 swfdec_bits_init_bits (&bits
, &s
->b
, length
> 2 ? length
- 2 : 0);
126 swfdec_bits_init_bits (&bits
, &s
->b
, swfdec_bits_left (&s
->b
) / 8);
127 while (swfdec_bits_peek_u8 (&bits
)) {
129 SwfdecBuffer
*buffer
;
130 cairo_matrix_t trans
;
131 SwfdecColorTransform ctrans
;
133 gboolean has_blend_mode
, has_filters
;
135 /* we parse the placement info into buffers each containing one palcement */
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
);
146 reserved
= swfdec_bits_getbits (&bits
, 4);
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",
166 swfdec_bits_get_color_transform (&bits
, &ctrans
);
169 GSList
*list
= swfdec_filter_parse (&bits
);
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);
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
)) {
185 swfdec_rect_transform (&rect
, &graphic
->extents
, &trans
);
186 swfdec_rect_union (&SWFDEC_GRAPHIC (button
)->extents
, &SWFDEC_GRAPHIC (button
)->extents
, &rect
);
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
);
204 swfdec_bits_init_bits (&bits
, &s
->b
, length
> 2 ? length
- 2 : 0);
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;
210 condition
= swfdec_button_translate_conditions (condition
, button
->menubutton
);
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
,
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
)
234 SwfdecButton
*button
;
236 id
= swfdec_bits_get_u16 (&s
->b
);
237 button
= swfdec_swf_decoder_create_character (s
, id
, SWFDEC_TYPE_BUTTON
);
239 return SWFDEC_STATUS_OK
;
241 SWFDEC_LOG (" ID: %d", id
);
243 while (swfdec_bits_peek_u8 (&s
->b
)) {
245 SwfdecBuffer
*buffer
;
246 cairo_matrix_t matrix
;
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);
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
)) {
263 swfdec_rect_transform (&rect
, &graphic
->extents
, &matrix
);
264 swfdec_rect_union (&SWFDEC_GRAPHIC (button
)->extents
, &SWFDEC_GRAPHIC (button
)->extents
, &rect
);
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
,
280 g_free (script_name
);
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
;