make swfdec_as_object_mark() only mark if not marked yet
[swfdec.git] / swfdec / swfdec_button_movie.c
blobaa154aed6fdea3f39d2f0f262565a6cd7cda93e5
1 /* Swfdec
2 * Copyright (C) 2006-2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include "swfdec_button_movie.h"
25 #include "swfdec_as_strings.h"
26 #include "swfdec_audio_event.h"
27 #include "swfdec_debug.h"
28 #include "swfdec_event.h"
29 #include "swfdec_filter.h"
30 #include "swfdec_player_internal.h"
31 #include "swfdec_resource.h"
33 G_DEFINE_TYPE (SwfdecButtonMovie, swfdec_button_movie, SWFDEC_TYPE_ACTOR)
35 static void
36 swfdec_button_movie_update_extents (SwfdecMovie *movie,
37 SwfdecRect *extents)
39 swfdec_rect_union (extents, extents, &movie->graphic->extents);
42 static void
43 swfdec_button_movie_perform_place (SwfdecButtonMovie *button, SwfdecBits *bits)
45 SwfdecMovie *movie = SWFDEC_MOVIE (button);
46 gboolean has_blend_mode, has_filters, v2;
47 SwfdecColorTransform ctrans;
48 SwfdecGraphic *graphic;
49 SwfdecPlayer *player;
50 cairo_matrix_t trans;
51 guint id, blend_mode;
52 SwfdecMovie *new;
53 int depth;
55 swfdec_bits_getbits (bits, 2); /* reserved */
56 has_blend_mode = swfdec_bits_getbit (bits);
57 has_filters = swfdec_bits_getbit (bits);
58 SWFDEC_LOG (" has_blend_mode = %d", has_blend_mode);
59 SWFDEC_LOG (" has_filters = %d", has_filters);
60 swfdec_bits_getbits (bits, 4); /* states */
61 id = swfdec_bits_get_u16 (bits);
62 depth = swfdec_bits_get_u16 (bits);
63 depth -= 16384;
64 if (swfdec_movie_find (movie, depth)) {
65 SWFDEC_WARNING ("depth %d already occupied, skipping placement.", depth + 16384);
66 return;
68 graphic = swfdec_swf_decoder_get_character (SWFDEC_SWF_DECODER (movie->resource->decoder), id);
69 if (!SWFDEC_IS_GRAPHIC (graphic)) {
70 SWFDEC_ERROR ("id %u does not specify a graphic", id);
71 return;
74 player = SWFDEC_PLAYER (swfdec_gc_object_get_context (movie));
75 new = swfdec_movie_new (player, depth, movie, movie->resource, graphic, NULL);
76 swfdec_bits_get_matrix (bits, &trans, NULL);
77 if (swfdec_bits_left (bits)) {
78 v2 = TRUE;
79 swfdec_bits_get_color_transform (bits, &ctrans);
80 if (has_blend_mode) {
81 blend_mode = swfdec_bits_get_u8 (bits);
82 SWFDEC_LOG (" blend mode = %u", blend_mode);
83 } else {
84 blend_mode = 0;
86 if (has_filters)
87 new->filters = swfdec_filter_parse (player, bits);
88 } else {
89 /* DefineButton1 record */
90 v2 = FALSE;
91 if (has_blend_mode || has_filters) {
92 SWFDEC_ERROR ("cool, a DefineButton1 with filters or blend mode");
94 blend_mode = 0;
96 swfdec_movie_set_static_properties (new, &trans, v2 ? &ctrans : NULL, 0, 0, blend_mode, NULL);
97 if (SWFDEC_IS_ACTOR (new)) {
98 SwfdecActor *actor = SWFDEC_ACTOR (new);
99 swfdec_actor_queue_script (actor, SWFDEC_EVENT_INITIALIZE);
100 swfdec_actor_queue_script (actor, SWFDEC_EVENT_CONSTRUCT);
101 swfdec_actor_queue_script (actor, SWFDEC_EVENT_LOAD);
103 swfdec_movie_initialize (new);
104 if (swfdec_bits_left (bits)) {
105 SWFDEC_WARNING ("button record for id %u has %u bytes left", id,
106 swfdec_bits_left (bits) / 8);
110 static void
111 swfdec_button_movie_set_state (SwfdecButtonMovie *button, SwfdecButtonState state)
113 SwfdecMovie *movie = SWFDEC_MOVIE (button);
114 SwfdecMovie *child;
115 SwfdecBits bits;
116 GSList *walk;
117 guint old, new, i;
118 int depth;
119 SwfdecButton *but;
121 if (button->state == state) {
122 SWFDEC_LOG ("not changing state, it's already in %d", state);
123 return;
125 SWFDEC_DEBUG ("changing state from %d to %d", button->state, state);
126 but = SWFDEC_BUTTON (movie->graphic);
127 /* remove all movies that aren't in the new state */
128 new = 1 << state;
129 if (button->state >= 0) {
130 old = 1 << button->state;
131 for (walk = but->records; walk; walk = walk->next) {
132 swfdec_bits_init (&bits, walk->data);
133 i = swfdec_bits_get_u8 (&bits);
134 if ((i & old) && !(i & new)) {
135 swfdec_bits_get_u16 (&bits);
136 depth = swfdec_bits_get_u16 (&bits);
137 child = swfdec_movie_find (movie, depth - 16384);
138 if (child) {
139 swfdec_movie_remove (child);
140 } else {
141 SWFDEC_WARNING ("no child at depth %d, none removed", depth);
145 } else {
146 /* to make sure that this never triggers when initializing */
147 old = 0;
149 button->state = state;
150 /* add all movies that are in the new state */
151 for (walk = but->records; walk; walk = walk->next) {
152 swfdec_bits_init (&bits, walk->data);
153 i = swfdec_bits_peek_u8 (&bits);
154 if ((i & old) || !(i & new))
155 continue;
156 swfdec_button_movie_perform_place (button, &bits);
160 static gboolean
161 swfdec_button_movie_mouse_events (SwfdecActor *actor)
163 return TRUE;
166 static void
167 swfdec_button_movie_mouse_in (SwfdecActor *actor)
169 if (swfdec_player_is_mouse_pressed (SWFDEC_PLAYER (swfdec_gc_object_get_context (actor))))
170 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor), SWFDEC_BUTTON_DOWN);
171 else
172 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor), SWFDEC_BUTTON_OVER);
174 SWFDEC_ACTOR_CLASS (swfdec_button_movie_parent_class)->mouse_in (actor);
177 static void
178 swfdec_button_movie_mouse_out (SwfdecActor *actor)
180 SwfdecButtonMovie *button = SWFDEC_BUTTON_MOVIE (actor);
182 if (swfdec_player_is_mouse_pressed (SWFDEC_PLAYER (swfdec_gc_object_get_context (button)))) {
183 if (SWFDEC_BUTTON (SWFDEC_MOVIE (actor)->graphic)->menubutton) {
184 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor), SWFDEC_BUTTON_UP);
185 } else {
186 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor), SWFDEC_BUTTON_OVER);
188 } else {
189 swfdec_button_movie_set_state (button, SWFDEC_BUTTON_UP);
192 SWFDEC_ACTOR_CLASS (swfdec_button_movie_parent_class)->mouse_out (actor);
195 static void
196 swfdec_button_movie_mouse_press (SwfdecActor *actor, guint button)
198 if (button != 0)
199 return;
200 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor), SWFDEC_BUTTON_DOWN);
202 SWFDEC_ACTOR_CLASS (swfdec_button_movie_parent_class)->mouse_press (actor, button);
205 static void
206 swfdec_button_movie_mouse_release (SwfdecActor *actor, guint button)
208 SwfdecPlayer *player;
210 if (button != 0)
211 return;
212 player = SWFDEC_PLAYER (swfdec_gc_object_get_context (actor));
213 if (player->priv->mouse_below == actor) {
214 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor), SWFDEC_BUTTON_OVER);
216 SWFDEC_ACTOR_CLASS (swfdec_button_movie_parent_class)->mouse_release (actor, button);
217 } else {
218 swfdec_button_movie_set_state (SWFDEC_BUTTON_MOVIE (actor), SWFDEC_BUTTON_UP);
220 /* NB: We don't chain to parent here for menubuttons*/
221 if (!SWFDEC_BUTTON (SWFDEC_MOVIE (actor)->graphic)->menubutton) {
222 SWFDEC_ACTOR_CLASS (swfdec_button_movie_parent_class)->mouse_release (actor, button);
223 } else {
224 SWFDEC_FIXME ("use mouse_below as recipient for mouse_release events?");
229 static void
230 swfdec_button_movie_init_movie (SwfdecMovie *mov)
232 SwfdecButtonMovie *movie = SWFDEC_BUTTON_MOVIE (mov);
234 swfdec_button_movie_set_state (movie, SWFDEC_BUTTON_UP);
237 static gboolean
238 swfdec_button_movie_hit_test (SwfdecButtonMovie *button, double x, double y)
240 SwfdecSwfDecoder *dec;
241 GSList *walk;
242 double tmpx, tmpy;
244 dec = SWFDEC_SWF_DECODER (SWFDEC_MOVIE (button)->resource->decoder);
245 for (walk = SWFDEC_BUTTON (SWFDEC_MOVIE (button)->graphic)->records; walk; walk = walk->next) {
246 SwfdecGraphic *graphic;
247 SwfdecBits bits;
248 cairo_matrix_t matrix, inverse;
249 guint id;
251 swfdec_bits_init (&bits, walk->data);
253 if ((swfdec_bits_get_u8 (&bits) & (1 << SWFDEC_BUTTON_HIT)) == 0)
254 continue;
256 id = swfdec_bits_get_u16 (&bits);
257 swfdec_bits_get_u16 (&bits); /* depth */
258 graphic = swfdec_swf_decoder_get_character (dec, id);
259 if (!SWFDEC_IS_GRAPHIC (graphic)) {
260 SWFDEC_ERROR ("id %u is no graphic", id);
261 continue;
263 tmpx = x;
264 tmpy = y;
265 swfdec_bits_get_matrix (&bits, &matrix, &inverse);
266 cairo_matrix_transform_point (&inverse, &tmpx, &tmpy);
268 SWFDEC_LOG ("Checking button contents at %g %g (transformed from %g %g)", tmpx, tmpy, x, y);
269 if (swfdec_graphic_mouse_in (graphic, tmpx, tmpy))
270 return TRUE;
271 SWFDEC_LOG (" missed");
273 return FALSE;
276 static SwfdecMovie *
277 swfdec_button_movie_contains (SwfdecMovie *movie, double x, double y, gboolean events)
279 if (events) {
280 /* check for movies in a higher layer that react to events */
281 SwfdecMovie *ret;
282 ret = SWFDEC_MOVIE_CLASS (swfdec_button_movie_parent_class)->contains (movie, x, y, TRUE);
283 if (ret && ret != movie && SWFDEC_IS_ACTOR (ret) && swfdec_actor_get_mouse_events (SWFDEC_ACTOR (ret)))
284 return ret;
287 return swfdec_button_movie_hit_test (SWFDEC_BUTTON_MOVIE (movie), x, y) ? movie : NULL;
290 static GObject *
291 swfdec_button_movie_constructor (GType type, guint n_construct_properties,
292 GObjectConstructParam *construct_properties)
294 SwfdecMovie *movie;
295 GObject *object;
297 object = G_OBJECT_CLASS (swfdec_button_movie_parent_class)->constructor (type,
298 n_construct_properties, construct_properties);
300 movie = SWFDEC_MOVIE (object);
301 g_assert (movie->graphic);
302 if (SWFDEC_BUTTON (movie->graphic)->events) {
303 SWFDEC_ACTOR (movie)->events = swfdec_event_list_copy (
304 SWFDEC_BUTTON (movie->graphic)->events);
307 return object;
310 static void
311 swfdec_button_movie_class_init (SwfdecButtonMovieClass * g_class)
313 GObjectClass *object_class = G_OBJECT_CLASS (g_class);
314 SwfdecMovieClass *movie_class = SWFDEC_MOVIE_CLASS (g_class);
315 SwfdecActorClass *actor_class = SWFDEC_ACTOR_CLASS (g_class);
317 object_class->constructor = swfdec_button_movie_constructor;
319 movie_class->init_movie = swfdec_button_movie_init_movie;
320 movie_class->update_extents = swfdec_button_movie_update_extents;
321 movie_class->contains = swfdec_button_movie_contains;
323 actor_class->mouse_events = swfdec_button_movie_mouse_events;
324 actor_class->mouse_in = swfdec_button_movie_mouse_in;
325 actor_class->mouse_out = swfdec_button_movie_mouse_out;
326 actor_class->mouse_press = swfdec_button_movie_mouse_press;
327 actor_class->mouse_release = swfdec_button_movie_mouse_release;
330 static void
331 swfdec_button_movie_init (SwfdecButtonMovie *movie)
333 movie->state = SWFDEC_BUTTON_INIT;