📄 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 <string.h>#include <math.h>#include <js/jsapi.h>#include "swfdec_movie.h"#include "swfdec_debug.h"#include "swfdec_debugger.h"#include "swfdec_event.h"#include "swfdec_graphic.h"#include "swfdec_js.h"#include "swfdec_player_internal.h"#include "swfdec_root_movie.h"#include "swfdec_sprite.h"/*** MOVIE ***/static const SwfdecContent default_content = SWFDEC_CONTENT_DEFAULT;G_DEFINE_ABSTRACT_TYPE (SwfdecMovie, swfdec_movie, SWFDEC_TYPE_SCRIPTABLE)static voidswfdec_movie_init (SwfdecMovie * movie){ movie->content = &default_content; movie->xscale = 100; movie->yscale = 100; cairo_matrix_init_identity (&movie->matrix); cairo_matrix_init_identity (&movie->inverse_matrix); swfdec_color_transform_init_identity (&movie->color_transform); movie->visible = TRUE; movie->n_frames = 1; 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_ROOT_MOVIE (movie)->player, &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, SwfdecMovieState 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; movie->matrix.xx = movie->content->transform.xx; movie->matrix.xy = movie->content->transform.xy; movie->matrix.yx = movie->content->transform.yx; movie->matrix.yy = movie->content->transform.yy; d = movie->xscale / swfdec_matrix_get_xscale (&movie->content->transform); e = movie->yscale / swfdec_matrix_get_yscale (&movie->content->transform); cairo_matrix_scale (&movie->matrix, d, e); d = movie->rotation - swfdec_matrix_get_rotation (&movie->content->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); }}/** * swfdec_movie_set_content: * @movie: a #SwfdecMovie * @content: #SwfdecContent to set for this movie or NULL to unset * * Sets new contents for @movie. Note that name and graphic of @content must * be identical to the current content of @movie. **/voidswfdec_movie_set_content (SwfdecMovie *movie, const SwfdecContent *content){ const SwfdecContent *old_content; SwfdecMovieClass *klass; g_return_if_fail (SWFDEC_IS_MOVIE (movie)); if (movie->content == content) return; if (content == NULL) { content = &default_content; } else if (movie->content != &default_content) { g_return_if_fail (movie->depth == content->depth); g_return_if_fail (movie->content->graphic == content->graphic); if (content->name) { g_return_if_fail (movie->content->name != NULL); g_return_if_fail (g_str_equal (content->name, movie->content->name)); } else { g_return_if_fail (movie->content->name == NULL); } } SWFDEC_LOG ("setting content of movie %s from %p to %p", movie->name, movie->content, content); old_content = movie->content; klass = SWFDEC_MOVIE_GET_CLASS (movie); if (klass->content_changed) klass->content_changed (movie, content); movie->content = content; if (!movie->modified) { movie->matrix = content->transform; movie->xscale = swfdec_matrix_get_xscale (&movie->matrix); movie->yscale = swfdec_matrix_get_yscale (&movie->matrix); movie->rotation = swfdec_matrix_get_rotation (&movie->matrix); swfdec_movie_queue_update (movie, SWFDEC_MOVIE_INVALID_MATRIX); }}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 *movie = walk->data; if (movie->depth < depth) continue; if (movie->depth == depth) return movie; break; } return NULL;}typedef void (* SwfdecMovieRemoveFunc) (SwfdecMovie *, gpointer);static voidswfdec_movie_do_remove (SwfdecMovie *movie, gpointer child_remove){ movie->will_be_removed = TRUE; /* remove all children */ while (movie->list) { (*(SwfdecMovieRemoveFunc) child_remove) (movie->list->data, child_remove); } if (SWFDEC_ROOT_MOVIE (movie->root)->player->mouse_grab == movie) SWFDEC_ROOT_MOVIE (movie->root)->player->mouse_grab = NULL; if (SWFDEC_ROOT_MOVIE (movie->root)->player->mouse_drag == movie) SWFDEC_ROOT_MOVIE (movie->root)->player->mouse_drag = NULL; swfdec_movie_invalidate (movie); if (movie->parent) { SwfdecPlayer *player = SWFDEC_ROOT_MOVIE (movie->root)->player; if (SWFDEC_IS_DEBUGGER (player) && g_list_find (movie->parent->list, movie)) { movie->parent->list = g_list_remove (movie->parent->list, movie); g_signal_emit_by_name (player, "movie-removed", movie); } else { movie->parent->list = g_list_remove (movie->parent->list, movie); } } else { SwfdecPlayer *player = SWFDEC_ROOT_MOVIE (movie)->player; if (SWFDEC_IS_DEBUGGER (player) && g_list_find (player->roots, movie)) { player->roots = g_list_remove (player->roots, movie); g_signal_emit_by_name (player, "movie-removed", movie); } else { player->roots = g_list_remove (player->roots, 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_ROOT_MOVIE (movie->root)->player; SWFDEC_LOG ("destroying movie %s", movie->name); swfdec_movie_do_remove (movie, swfdec_movie_destroy); swfdec_movie_set_content (movie, NULL); if (klass->finish_movie) klass->finish_movie (movie); swfdec_js_movie_remove_jsobject (movie); player->movies = g_list_remove (player->movies, movie); g_object_unref (movie);}/** * 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){ g_return_if_fail (SWFDEC_IS_MOVIE (movie)); SWFDEC_LOG ("removing %s %s", G_OBJECT_TYPE_NAME (movie), movie->name); swfdec_movie_do_remove (movie, swfdec_movie_remove); if (!swfdec_movie_queue_script (movie, SWFDEC_EVENT_UNLOAD)) swfdec_movie_destroy (movie);}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->content->events) { swfdec_event_list_execute (movie->content->events, SWFDEC_SCRIPTABLE (movie), condition, 0); } name = swfdec_event_type_get_name (condition); if (name != NULL) swfdec_scriptable_execute (SWFDEC_SCRIPTABLE (movie), name, 0, 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->content->events) { if (!swfdec_event_list_has_conditions (movie->content->events, SWFDEC_SCRIPTABLE (movie), condition, 0)) return FALSE; } else { const char *name = swfdec_event_type_get_name (condition); if (name == NULL || !swfdec_scriptable_can_execute (SWFDEC_SCRIPTABLE (movie), name)) return FALSE; } player = SWFDEC_ROOT_MOVIE (movie->root)->player; swfdec_player_add_action (player, movie, swfdec_movie_do_execute_script, GUINT_TO_POINTER (condition)); return TRUE;}/* NB: coordinates are in movie's coordiante system. Use swfdec_movie_get_mouse * if you have global coordinates */static gbooleanswfdec_movie_mouse_in (SwfdecMovie *movie, double x, double y){ SwfdecMovieClass *klass; klass = SWFDEC_MOVIE_GET_CLASS (movie); if (klass->mouse_in == NULL) return FALSE; return klass->mouse_in (movie, x, y);}voidswfdec_movie_local_to_global (SwfdecMovie *movie, double *x, double *y){ do { cairo_matrix_transform_point (&movie->matrix, x, y); } while ((movie = movie->parent));}voidswfdec_movie_global_to_local (SwfdecMovie *movie, double *x, double *y){ if (movie->parent) swfdec_movie_global_to_local (movie->parent, x, y); if (movie->cache_state >= SWFDEC_MOVIE_INVALID_MATRIX) swfdec_movie_update (movie); cairo_matrix_transform_point (&movie->inverse_matrix, x, y);}/** * swfdec_movie_get_mouse: * @movie: a #SwfdecMovie * @x: pointer to hold result of X coordinate * @y: pointer to hold result of y coordinate * * Gets the mouse coordinates in the coordinate space of @movie. **/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -