📄 swfdec_movie.c
字号:
/* Swfdec * Copyright (C) 2006-2007 Benjamin Otte <otte@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <math.h>#include <stdlib.h>#include <string.h>#include <strings.h>#include <errno.h>#include "swfdec_movie.h"#include "swfdec_as_context.h"#include "swfdec_as_strings.h"#include "swfdec_button_movie.h"#include "swfdec_debug.h"#include "swfdec_event.h"#include "swfdec_graphic.h"#include "swfdec_loader_internal.h"#include "swfdec_player_internal.h"#include "swfdec_sprite.h"#include "swfdec_sprite_movie.h"#include "swfdec_swf_instance.h"/*** MOVIE ***/enum { PROP_0, PROP_DEPTH};G_DEFINE_ABSTRACT_TYPE (SwfdecMovie, swfdec_movie, SWFDEC_TYPE_AS_OBJECT)static voidswfdec_movie_init (SwfdecMovie * movie){ movie->xscale = 100; movie->yscale = 100; cairo_matrix_init_identity (&movie->original_transform); cairo_matrix_init_identity (&movie->matrix); cairo_matrix_init_identity (&movie->inverse_matrix); swfdec_color_transform_init_identity (&movie->color_transform); swfdec_color_transform_init_identity (&movie->original_ctrans); movie->visible = TRUE; swfdec_rect_init_empty (&movie->extents);}/** * swfdec_movie_invalidate: * @movie: movie to invalidate * * Invalidates the area currently occupied by movie. If the area this movie * occupies has changed, call swfdec_movie_queue_update () instead. **/voidswfdec_movie_invalidate (SwfdecMovie *movie){ SwfdecRect rect = movie->extents; SWFDEC_LOG ("invalidating %g %g %g %g", rect.x0, rect.y0, rect.x1, rect.y1); if (swfdec_rect_is_empty (&rect)) return; while (movie->parent) { movie = movie->parent; if (movie->cache_state > SWFDEC_MOVIE_INVALID_EXTENTS) return; swfdec_rect_transform (&rect, &rect, &movie->matrix); } swfdec_player_invalidate (SWFDEC_PLAYER (SWFDEC_AS_OBJECT (movie)->context), &rect);}/** * swfdec_movie_queue_update: * @movie: a #SwfdecMovie * @state: how much needs to be updated * * Queues an update of all cached values inside @movie and invalidates it. **/voidswfdec_movie_queue_update (SwfdecMovie *movie, SwfdecMovieCacheState state){ g_return_if_fail (SWFDEC_IS_MOVIE (movie)); if (movie->cache_state < SWFDEC_MOVIE_INVALID_EXTENTS && state >= SWFDEC_MOVIE_INVALID_EXTENTS) swfdec_movie_invalidate (movie); while (movie && movie->cache_state < state) { movie->cache_state = state; movie = movie->parent; state = SWFDEC_MOVIE_INVALID_CHILDREN; }}static voidswfdec_movie_update_extents (SwfdecMovie *movie){ SwfdecMovieClass *klass; GList *walk; SwfdecRect *rect = &movie->original_extents; SwfdecRect *extents = &movie->extents; swfdec_rect_init_empty (rect); for (walk = movie->list; walk; walk = walk->next) { swfdec_rect_union (rect, rect, &SWFDEC_MOVIE (walk->data)->extents); } klass = SWFDEC_MOVIE_GET_CLASS (movie); if (klass->update_extents) klass->update_extents (movie, rect); if (swfdec_rect_is_empty (rect)) { *extents = *rect; return; } swfdec_rect_transform (extents, rect, &movie->matrix); if (movie->parent && movie->parent->cache_state < SWFDEC_MOVIE_INVALID_EXTENTS) { /* no need to invalidate here */ movie->parent->cache_state = SWFDEC_MOVIE_INVALID_EXTENTS; }}static voidswfdec_movie_update_matrix (SwfdecMovie *movie){ double d, e; /* we operate on x0 and y0 when setting movie._x and movie._y */ if (movie->modified) { movie->matrix.xx = movie->original_transform.xx; movie->matrix.yx = movie->original_transform.yx; movie->matrix.xy = movie->original_transform.xy; movie->matrix.yy = movie->original_transform.yy; } else { movie->matrix = movie->original_transform; } d = movie->xscale / swfdec_matrix_get_xscale (&movie->original_transform); e = movie->yscale / swfdec_matrix_get_yscale (&movie->original_transform); cairo_matrix_scale (&movie->matrix, d, e); if (isfinite (movie->rotation)) { d = movie->rotation - swfdec_matrix_get_rotation (&movie->original_transform); cairo_matrix_rotate (&movie->matrix, d * G_PI / 180); } swfdec_matrix_ensure_invertible (&movie->matrix, &movie->inverse_matrix); swfdec_movie_update_extents (movie);}static voidswfdec_movie_do_update (SwfdecMovie *movie){ GList *walk; for (walk = movie->list; walk; walk = walk->next) { SwfdecMovie *child = walk->data; if (child->cache_state != SWFDEC_MOVIE_UP_TO_DATE) swfdec_movie_do_update (child); } switch (movie->cache_state) { case SWFDEC_MOVIE_INVALID_CHILDREN: break; case SWFDEC_MOVIE_INVALID_EXTENTS: swfdec_movie_update_extents (movie); break; case SWFDEC_MOVIE_INVALID_MATRIX: swfdec_movie_update_matrix (movie); break; case SWFDEC_MOVIE_UP_TO_DATE: default: g_assert_not_reached (); } if (movie->cache_state > SWFDEC_MOVIE_INVALID_EXTENTS) swfdec_movie_invalidate (movie); movie->cache_state = SWFDEC_MOVIE_UP_TO_DATE;}/** * swfdec_movie_update: * @movie: a #SwfdecMovie * * Brings the cached values of @movie up-to-date if they are not. This includes * transformation matrices and extents. It needs to be called before accessing * the relevant values. **/voidswfdec_movie_update (SwfdecMovie *movie){ g_return_if_fail (SWFDEC_IS_MOVIE (movie)); if (movie->cache_state == SWFDEC_MOVIE_UP_TO_DATE) return; if (movie->parent && movie->parent->cache_state != SWFDEC_MOVIE_UP_TO_DATE) { swfdec_movie_update (movie->parent); } else { swfdec_movie_do_update (movie); }}SwfdecMovie *swfdec_movie_find (SwfdecMovie *movie, int depth){ GList *walk; g_return_val_if_fail (SWFDEC_IS_MOVIE (movie), NULL); for (walk = movie->list; walk; walk = walk->next) { SwfdecMovie *cur= walk->data; if (cur->depth < depth) continue; if (cur->depth == depth) return cur; break; } return NULL;}static gbooleanswfdec_movie_do_remove (SwfdecMovie *movie){ SwfdecPlayer *player; SWFDEC_LOG ("removing %s %s", G_OBJECT_TYPE_NAME (movie), movie->name); player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (movie)->context); movie->will_be_removed = TRUE; while (movie->list) { GList *walk = movie->list; while (walk && SWFDEC_MOVIE (walk->data)->will_be_removed) walk = walk->next; if (walk == NULL) break; swfdec_movie_remove (walk->data); } /* FIXME: all of this here or in destroy callback? */ if (player->mouse_grab == movie) player->mouse_grab = NULL; if (player->mouse_drag == movie) player->mouse_drag = NULL; swfdec_movie_invalidate (movie); swfdec_movie_set_depth (movie, -32769 - movie->depth); /* don't ask me why... */ if (SWFDEC_IS_SPRITE_MOVIE (movie)) return !swfdec_movie_queue_script (movie, SWFDEC_EVENT_UNLOAD); else return TRUE;}/** * swfdec_movie_remove: * @movie: #SwfdecMovie to remove * * Removes this movie from its parent. In contrast to swfdec_movie_destroy (), * it will definitely cause a removal from the display list, but depending on * movie, it might still be possible to reference it from Actionscript. **/voidswfdec_movie_remove (SwfdecMovie *movie){ gboolean result; g_return_if_fail (SWFDEC_IS_MOVIE (movie)); if (movie->state > SWFDEC_MOVIE_STATE_RUNNING) return; result = swfdec_movie_do_remove (movie); movie->state = SWFDEC_MOVIE_STATE_REMOVED; if (result) swfdec_movie_destroy (movie);}/** * swfdec_movie_destroy: * @movie: #SwfdecMovie to destroy * * Removes this movie from its parent. After this it will no longer be present, * neither visually nor via ActionScript. This function will not cause an * unload event. Compare with swfdec_movie_destroy (). **/voidswfdec_movie_destroy (SwfdecMovie *movie){ SwfdecMovieClass *klass = SWFDEC_MOVIE_GET_CLASS (movie); SwfdecPlayer *player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (movie)->context); g_assert (movie->state < SWFDEC_MOVIE_STATE_DESTROYED); if (movie->state < SWFDEC_MOVIE_STATE_REMOVED) { swfdec_movie_do_remove (movie); } SWFDEC_LOG ("destroying movie %s", movie->name); while (movie->list) { swfdec_movie_destroy (movie->list->data); } if (movie->parent) { movie->parent->list = g_list_remove (movie->parent->list, movie); } else { player->roots = g_list_remove (player->roots, movie); } /* FIXME: figure out how to handle destruction pre-init/construct. * This is just a stop-gap measure to avoid dead movies in those queues */ g_queue_remove (player->init_queue, movie); g_queue_remove (player->construct_queue, movie); swfdec_player_remove_all_actions (player, movie); if (klass->finish_movie) klass->finish_movie (movie); player->movies = g_list_remove (player->movies, movie); movie->state = SWFDEC_MOVIE_STATE_DESTROYED; /* unset prototype here, so we don't work in AS anymore */ SWFDEC_AS_OBJECT (movie)->prototype = NULL; g_object_unref (movie);}/** * swfdec_movie_run_init: * @movie: a #SwfdecMovie * * Runs onClipEvent(initialize) on the given @movie. */voidswfdec_movie_run_init (SwfdecMovie *movie){ SwfdecPlayer *player; g_return_if_fail (SWFDEC_IS_MOVIE (movie)); player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (movie)->context); g_queue_remove (player->init_queue, movie); swfdec_movie_execute_script (movie, SWFDEC_EVENT_INITIALIZE);}/** * swfdec_movie_run_construct: * @movie: a #SwfdecMovie * * Runs the constructors for @movie. This is (in the given order) * onClipEvent(construct), movie.onConstruct and the constructor registered * via Object.registerClass. **/voidswfdec_movie_run_construct (SwfdecMovie *movie){ SwfdecPlayer *player; g_return_if_fail (SWFDEC_IS_MOVIE (movie)); player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (movie)->context); g_queue_remove (player->construct_queue, movie); swfdec_movie_execute_script (movie, SWFDEC_EVENT_CONSTRUCT); swfdec_as_object_call (SWFDEC_AS_OBJECT (movie), SWFDEC_AS_STR_constructor, 0, NULL, NULL);}voidswfdec_movie_execute_script (SwfdecMovie *movie, SwfdecEventType condition){ const char *name; g_return_if_fail (SWFDEC_IS_MOVIE (movie)); g_return_if_fail (condition != 0); if (movie->events) { swfdec_event_list_execute (movie->events, SWFDEC_AS_OBJECT (movie), condition, 0); } name = swfdec_event_type_get_name (condition); if (name != NULL) swfdec_as_object_call (SWFDEC_AS_OBJECT (movie), name, 0, NULL, NULL);}static voidswfdec_movie_do_execute_script (gpointer movie, gpointer condition){ swfdec_movie_execute_script (movie, GPOINTER_TO_UINT (condition));}/** * swfdec_movie_queue_script: * @movie: a #SwfdecMovie * @condition: the event that should happen * * Queues execution of all scripts associated with the given event. * * Returns: TRUE if there were any such events **/gbooleanswfdec_movie_queue_script (SwfdecMovie *movie, SwfdecEventType condition){ SwfdecPlayer *player; g_return_val_if_fail (SWFDEC_IS_MOVIE (movie), FALSE); g_return_val_if_fail (condition != 0, FALSE); if (movie->events) { if (!swfdec_event_list_has_conditions (movie->events, SWFDEC_AS_OBJECT (movie), condition, 0)) return FALSE; } else { const char *name = swfdec_event_type_get_name (condition); if (name == NULL || !swfdec_as_object_has_function (SWFDEC_AS_OBJECT (movie), name)) return FALSE; } player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (movie)->context); swfdec_player_add_action (player, movie, swfdec_movie_do_execute_script, GUINT_TO_POINTER (condition)); return TRUE;}/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -