📄 swfdec_movie.c
字号:
voidswfdec_movie_get_mouse (SwfdecMovie *movie, double *x, double *y){ SwfdecPlayer *player; g_return_if_fail (SWFDEC_IS_MOVIE (movie)); g_return_if_fail (x != NULL); g_return_if_fail (y != NULL); player = SWFDEC_ROOT_MOVIE (movie->root)->player; *x = player->mouse_x; *y = player->mouse_y; swfdec_movie_global_to_local (movie, x, y);}voidswfdec_movie_send_mouse_change (SwfdecMovie *movie, gboolean release){ double x, y; gboolean mouse_in; int button; SwfdecMovieClass *klass; swfdec_movie_get_mouse (movie, &x, &y); if (release) { mouse_in = FALSE; button = 0; } else { mouse_in = swfdec_movie_mouse_in (movie, x, y); button = SWFDEC_ROOT_MOVIE (movie->root)->player->mouse_button; } klass = SWFDEC_MOVIE_GET_CLASS (movie); g_assert (klass->mouse_change != NULL); klass->mouse_change (movie, x, y, mouse_in, button);}SwfdecMovie *swfdec_movie_get_movie_at (SwfdecMovie *movie, double x, double y){ GList *walk, *clip_walk; int clip_depth = 0; SwfdecMovie *ret; SwfdecMovieClass *klass; SWFDEC_LOG ("%s %p getting mouse at: %g %g", G_OBJECT_TYPE_NAME (movie), movie, x, y); if (!swfdec_rect_contains (&movie->extents, x, y)) { return NULL; } cairo_matrix_transform_point (&movie->inverse_matrix, &x, &y); /* first check if the movie can handle mouse events, and if it can, * ignore its children. * Dunno if that's correct */ klass = SWFDEC_MOVIE_GET_CLASS (movie); if (klass->mouse_change) { if (swfdec_movie_mouse_in (movie, x, y)) return movie; else return NULL; } for (walk = clip_walk = g_list_last (movie->list); walk; walk = walk->prev) { SwfdecMovie *child = walk->data; if (walk == clip_walk) { clip_depth = 0; for (clip_walk = clip_walk->prev; clip_walk; clip_walk = clip_walk->prev) { SwfdecMovie *clip = walk->data; if (clip->content->clip_depth) { double tmpx = x, tmpy = y; cairo_matrix_transform_point (&clip->inverse_matrix, &tmpx, &tmpy); if (!swfdec_movie_mouse_in (clip, tmpx, tmpy)) { SWFDEC_LOG ("skipping depth %d to %d due to clipping", clip->content->depth, clip->content->clip_depth); clip_depth = child->content->clip_depth; } break; } } } if (child->content->clip_depth) { SWFDEC_LOG ("resetting clip depth"); clip_depth = 0; continue; } if (child->depth <= clip_depth && clip_depth) { SWFDEC_DEBUG ("ignoring depth=%d, it's clipped (clip_depth %d)", child->depth, clip_depth); continue; } if (!child->visible) { SWFDEC_LOG ("child %s %s (depth %d) is invisible, ignoring", G_OBJECT_TYPE_NAME (movie), movie->name, movie->depth); continue; } ret = swfdec_movie_get_movie_at (child, x, y); if (ret) return ret; } return NULL;}voidswfdec_movie_render (SwfdecMovie *movie, cairo_t *cr, const SwfdecColorTransform *color_transform, const SwfdecRect *inval, gboolean fill){ SwfdecMovieClass *klass; GList *g; int clip_depth = 0; SwfdecColorTransform trans; SwfdecRect rect; g_return_if_fail (SWFDEC_IS_MOVIE (movie)); g_return_if_fail (cr != NULL); if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) { g_warning ("%s", cairo_status_to_string (cairo_status (cr))); } g_return_if_fail (color_transform != NULL); g_return_if_fail (inval != NULL); if (!swfdec_rect_intersect (NULL, &movie->extents, inval)) { SWFDEC_LOG ("not rendering %s %s, extents %g %g %g %g are not in invalid area %g %g %g %g", G_OBJECT_TYPE_NAME (movie), movie->name, movie->extents.x0, movie->extents.y0, movie->extents.x1, movie->extents.y1, inval->x0, inval->y0, inval->x1, inval->y1); return; } if (!movie->visible) { SWFDEC_LOG ("not rendering %s %p, movie is invisible", G_OBJECT_TYPE_NAME (movie), movie->name); return; } cairo_save (cr); SWFDEC_LOG ("transforming movie, transform: %g %g %g %g %g %g", movie->matrix.xx, movie->matrix.yy, movie->matrix.xy, movie->matrix.yx, movie->matrix.x0, movie->matrix.y0); cairo_transform (cr, &movie->matrix); swfdec_rect_transform (&rect, inval, &movie->inverse_matrix); SWFDEC_LOG ("%sinvalid area is now: %g %g %g %g", movie->parent ? " " : "", rect.x0, rect.y0, rect.x1, rect.y1); swfdec_color_transform_chain (&trans, &movie->content->color_transform, color_transform); swfdec_color_transform_chain (&trans, &movie->color_transform, &trans); for (g = movie->list; g; g = g_list_next (g)) { SwfdecMovie *child = g->data; if (child->content->clip_depth) { if (clip_depth) { /* FIXME: is clipping additive? */ SWFDEC_INFO ("unsetting clip depth %d for new clip depth", clip_depth); cairo_restore (cr); clip_depth = 0; } if (fill == FALSE) { SWFDEC_WARNING ("clipping inside clipping not implemented"); } else { /* FIXME FIXME FIXME: overlapping objects in the clip movie cause problems * due to them being accumulated with CAIRO_FILL_RULE_EVEN_ODD */ SWFDEC_INFO ("clipping up to depth %d by using %p with depth %d", child->content->clip_depth, child, child->depth); clip_depth = child->content->clip_depth; cairo_save (cr); swfdec_movie_render (child, cr, &trans, &rect, FALSE); cairo_clip (cr); continue; } } if (clip_depth && child->depth > clip_depth) { SWFDEC_INFO ("unsetting clip depth %d for depth %d", clip_depth, child->depth); clip_depth = 0; cairo_restore (cr); } SWFDEC_LOG ("rendering %p with depth %d", child, child->depth); swfdec_movie_render (child, cr, &trans, &rect, fill); } if (clip_depth) { SWFDEC_INFO ("unsetting clip depth %d after rendering", clip_depth); clip_depth = 0; cairo_restore (cr); } klass = SWFDEC_MOVIE_GET_CLASS (movie); if (klass->render) klass->render (movie, cr, &trans, &rect, fill);#if 0 /* code to draw a red rectangle around the area occupied by this movie clip */ { double x = 1.0, y = 0.0; cairo_transform (cr, &movie->inverse_transform); cairo_user_to_device_distance (cr, &x, &y); cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); cairo_set_line_width (cr, 1 / sqrt (x * x + y * y)); cairo_rectangle (cr, object->extents.x0 + 10, object->extents.y0 + 10, object->extents.x1 - object->extents.x0 - 20, object->extents.y1 - object->extents.y0 - 20); cairo_stroke (cr); }#endif if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) { g_warning ("error rendering with cairo: %s", cairo_status_to_string (cairo_status (cr))); } cairo_restore (cr);}static voidswfdec_movie_dispose (GObject *object){ SwfdecMovie * movie = SWFDEC_MOVIE (object); g_assert (movie->list == NULL); g_assert (movie->content == &default_content); SWFDEC_LOG ("disposing movie %s", movie->name); g_free (movie->name); if (movie->parent) g_object_unref (movie->parent); G_OBJECT_CLASS (swfdec_movie_parent_class)->dispose (G_OBJECT (movie));}static gbooleanswfdec_movie_iterate_end (SwfdecMovie *movie){ return movie->parent == NULL || g_list_find (movie->parent->list, movie) != NULL;}static JSObject *swfdec_movie_create_js_object (SwfdecScriptable *script){ /* we create the objects manually and ensure persistence */ g_assert_not_reached ();}extern const JSClass movieclip_class;static voidswfdec_movie_class_init (SwfdecMovieClass * movie_class){ GObjectClass *object_class = G_OBJECT_CLASS (movie_class); SwfdecScriptableClass *script_class = SWFDEC_SCRIPTABLE_CLASS (movie_class); object_class->dispose = swfdec_movie_dispose; script_class->jsclass = &movieclip_class; script_class->create_js_object = swfdec_movie_create_js_object; movie_class->iterate_end = swfdec_movie_iterate_end;}static voidswfdec_movie_set_name (SwfdecMovie *movie){ /* FIXME: implement this function in a smarter way, not if (IS_FOO_MOVIE (x)) */ g_assert (movie->name == NULL); if (movie->content->name) { movie->name = g_strdup (movie->content->name); movie->has_name = TRUE; } else if (SWFDEC_IS_SPRITE_MOVIE (movie)) { /* FIXME: figure out if it's relative to root or player or something else * entirely */ SwfdecRootMovie *root = SWFDEC_ROOT_MOVIE (movie->root); movie->name = g_strdup_printf ("instance%u", ++root->unnamed_count); movie->has_name = FALSE; } else { movie->name = g_strdup (G_OBJECT_TYPE_NAME (movie)); movie->has_name = FALSE; } SWFDEC_LOG ("created movie %s", movie->name);}static voidswfdec_movie_set_parent (SwfdecMovie *movie){ SwfdecMovie *parent = movie->parent; SwfdecPlayer *player = SWFDEC_ROOT_MOVIE (movie->root)->player; SwfdecMovieClass *klass; g_return_if_fail (SWFDEC_IS_MOVIE (movie)); if (parent) { parent->list = g_list_insert_sorted (parent->list, movie, swfdec_movie_compare_depths); SWFDEC_DEBUG ("inserting %s %p (depth %d) into %s %p", G_OBJECT_TYPE_NAME (movie), movie, movie->depth, G_OBJECT_TYPE_NAME (parent), parent); } else { player->roots = g_list_insert_sorted (player->roots, movie, swfdec_movie_compare_depths); } swfdec_movie_set_name (movie); klass = SWFDEC_MOVIE_GET_CLASS (movie); /* NB: adding to the movies list happens before setting the parent. * Setting the parent does a gotoAndPlay(0) for Sprites which can cause * new movies to be created (and added to this list) */ player->movies = g_list_prepend (player->movies, movie); /* we have to create the JSObject here to get actions queued before init_movie executes */ swfdec_js_movie_create_jsobject (movie); /* queue init and construct events for non-root movies */ if (movie != movie->root) { g_queue_push_tail (player->init_queue, movie); g_queue_push_tail (player->construct_queue, movie); } if (SWFDEC_IS_DEBUGGER (player)) g_signal_emit_by_name (player, "movie-added", movie); swfdec_movie_queue_script (movie, SWFDEC_EVENT_LOAD); if (klass->init_movie) klass->init_movie (movie);}static voidswfdec_movie_initialize (SwfdecMovie *movie, const SwfdecContent *content){ const SwfdecContent *old; old = movie->content; movie->content = content; movie->depth = content->depth; swfdec_movie_set_parent (movie); movie->content = old; swfdec_movie_set_content (movie, content);}/** * swfdec_movie_new: * @parent: the parent movie that will contain this movie * @content: the content to display * * Creates a new #SwfdecMovie as a child of @parent with the given content. * @parent must not contain a movie clip at the depth specified by @content. * * Returns: a new #SwfdecMovie **/SwfdecMovie *swfdec_movie_new (SwfdecMovie *parent, const SwfdecContent *content){ SwfdecGraphicClass *klass; SwfdecMovie *ret; g_return_val_if_fail (SWFDEC_IS_MOVIE (parent), NULL); g_return_val_if_fail (SWFDEC_IS_GRAPHIC (content->graphic), NULL); g_return_val_if_fail (swfdec_movie_find (parent, content->depth) == NULL, NULL); SWFDEC_DEBUG ("new movie for parent %p", parent); klass = SWFDEC_GRAPHIC_GET_CLASS (content->graphic); g_return_val_if_fail (klass->create_movie != NULL, NULL); ret = klass->create_movie (content->graphic); ret->parent = parent; SWFDEC_SCRIPTABLE (ret)->jscx = SWFDEC_SCRIPTABLE (parent)->jscx; g_object_ref (parent); ret->root = parent->root; swfdec_movie_initialize (ret, content); return ret;}SwfdecMovie *swfdec_movie_new_for_player (SwfdecPlayer *player, guint depth){ SwfdecMovie *ret; SwfdecContent *content; g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL); content = swfdec_content_new ((int) depth - 16384); content->name = g_strdup_printf ("_level%u", depth); ret = g_object_new (SWFDEC_TYPE_ROOT_MOVIE, NULL); g_object_weak_ref (G_OBJECT (ret), (GWeakNotify) swfdec_content_free, content); SWFDEC_ROOT_MOVIE (ret)->player = player; SWFDEC_SCRIPTABLE (ret)->jscx = player->jscx; ret->root = ret; swfdec_movie_initialize (ret, content); ret->has_name = FALSE; return ret;}voidswfdec_movie_goto (SwfdecMovie *movie, guint frame){ SwfdecMovieClass *klass; g_return_if_fail (SWFDEC_IS_MOVIE (movie)); g_return_if_fail (frame < movie->n_frames); klass = SWFDEC_MOVIE_GET_CLASS (movie); if (klass->goto_frame) klass->goto_frame (movie, frame);}char *swfdec_movie_get_path (SwfdecMovie *movie){ GString *s; g_return_val_if_fail (SWFDEC_IS_MOVIE (movie), NULL); s = g_string_new (""); do { if (movie->parent) { g_string_prepend (s, movie->name); g_string_prepend_c (s, '.'); } else { char *ret = g_strdup_printf ("_level%u%s", movie->depth + 16384, s->str); g_string_free (s, TRUE); return ret; } movie = movie->parent; } while (TRUE); g_assert_not_reached (); return NULL;}intswfdec_movie_compare_depths (gconstpointer a, gconstpointer b){ if (SWFDEC_MOVIE (a)->depth < SWFDEC_MOVIE (b)->depth) return -1; if (SWFDEC_MOVIE (a)->depth > SWFDEC_MOVIE (b)->depth) return 1; return 0;}/** * swfdec_depth_classify: * @depth: the depth to classify * * Classifies a depth. This classification is mostly used when deciding if * certain operations are valid in ActionScript. * * Returns: the classification of the depth. **/SwfdecDepthClassswfdec_depth_classify (int depth){ if (depth < -16384) return SWFDEC_DEPTH_CLASS_EMPTY; if (depth < 0) return SWFDEC_DEPTH_CLASS_TIMELINE; if (depth < 1048576) return SWFDEC_DEPTH_CLASS_DYNAMIC; if (depth < 2130690046) return SWFDEC_DEPTH_CLASS_RESERVED; return SWFDEC_DEPTH_CLASS_EMPTY;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -