/*TransformMatrix2D*/ static void TraverseTransformMatrix2D(GF_Node *node, void *rs, Bool is_destroy) { Transform2DStack *ptr = (Transform2DStack *) gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { gf_sc_check_focus_upon_destroy(node); group_2d_destroy(node, (GroupingNode2D*)ptr); gf_free(ptr); return; } if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) { M_TransformMatrix2D *tr = (M_TransformMatrix2D*)node; tr_mx2d_get_matrix(node, &ptr->mat); if ((tr->mxx==FIX_ONE) && (tr->mxy==0) && (tr->tx==0) && (tr->myx==0) && (tr->myy==FIX_ONE) && (tr->ty==0) ) ptr->is_identity = 1; else ptr->is_identity = 0; ptr->is_null = ( (!ptr->mat.m[0] && !ptr->mat.m[1]) || (!ptr->mat.m[3] && !ptr->mat.m[4]) ) ? 1 : 0; gf_node_dirty_clear(node, GF_SG_NODE_DIRTY); } traverse_transform(node, ptr, tr_state); }
static void svg_traverse_defs(GF_Node *node, void *rs, Bool is_destroy) { SVGPropertiesPointers backup_props; u32 prev_flags, backup_flags; u32 styling_size = sizeof(SVGPropertiesPointers); GF_TraverseState *tr_state = (GF_TraverseState *) rs; SVGAllAttributes all_atts; if (is_destroy) { gf_sc_check_focus_upon_destroy(node); return; } gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!compositor_svg_traverse_base(node, &all_atts, tr_state, &backup_props, &backup_flags)) return; prev_flags = tr_state->switched_off; tr_state->switched_off = 1; compositor_svg_traverse_children(((SVG_Element *)node)->children, tr_state); tr_state->switched_off = prev_flags; memcpy(tr_state->svg_props, &backup_props, styling_size); tr_state->svg_flags = backup_flags; }
static void TraverseTransform2D(GF_Node *node, void *rs, Bool is_destroy) { M_Transform2D *tr = (M_Transform2D *)node; Transform2DStack *ptr = (Transform2DStack *)gf_node_get_private(node); GF_TraverseState *tr_state; if (is_destroy) { gf_sc_check_focus_upon_destroy(node); group_2d_destroy(node, (GroupingNode2D*)ptr); gf_free(ptr); return; } tr_state = (GF_TraverseState *) rs; if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) { gf_mx2d_init(ptr->mat); ptr->is_identity = 1; if ((tr->scale.x != FIX_ONE) || (tr->scale.y != FIX_ONE)) { gf_mx2d_add_scale_at(&ptr->mat, tr->scale.x, tr->scale.y, 0, 0, tr->scaleOrientation); ptr->is_identity = 0; } if (tr->rotationAngle) { gf_mx2d_add_rotation(&ptr->mat, tr->center.x, tr->center.y, tr->rotationAngle); ptr->is_identity = 0; } if (tr->translation.x || tr->translation.y) { ptr->is_identity = 0; gf_mx2d_add_translation(&ptr->mat, tr->translation.x, tr->translation.y); } gf_node_dirty_clear(node, GF_SG_NODE_DIRTY); ptr->is_null = (!tr->scale.x || !tr->scale.y) ? 1 : 0; } traverse_transform(node, ptr, tr_state); }
static void TraverseGroup(GF_Node *node, void *rs, Bool is_destroy) { GroupingNode *group = (GroupingNode *) gf_node_get_private(node); if (is_destroy) { gf_sc_check_focus_upon_destroy(node); group_3d_delete(node); } else { group_3d_traverse(node, group, (GF_TraverseState*)rs); } }
/*ColorTransform*/ static void TraverseColorTransform(GF_Node *node, void *rs, Bool is_destroy) { Bool c_changed; M_ColorTransform *tr = (M_ColorTransform *)node; ColorTransformStack *ptr = (ColorTransformStack *)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *) rs; Bool prev_inv; if (is_destroy) { gf_sc_check_focus_upon_destroy(node); group_2d_destroy(node, (GroupingNode2D*)ptr); gf_free(ptr); return; } if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) { group_2d_traverse(node, (GroupingNode2D *) ptr, tr_state); return; } prev_inv = tr_state->invalidate_all; c_changed = 0; if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) { gf_cmx_set(&ptr->cmat, tr->mrr , tr->mrg, tr->mrb, tr->mra, tr->tr, tr->mgr , tr->mgg, tr->mgb, tr->mga, tr->tg, tr->mbr, tr->mbg, tr->mbb, tr->mba, tr->tb, tr->mar, tr->mag, tr->mab, tr->maa, tr->ta); c_changed = 1; gf_node_dirty_clear(node, GF_SG_NODE_DIRTY); } if ((tr_state->traversing_mode==TRAVERSE_SORT) && !tr->maa && !tr->mar && !tr->mag && !tr->mab && !tr->ta) return; /*if modified redraw all nodes*/ if (c_changed) tr_state->invalidate_all = 1; /*note we don't clear dirty flag, this is done in traversing*/ if (ptr->cmat.identity) { group_2d_traverse(node, (GroupingNode2D *) ptr, tr_state); } else { GF_ColorMatrix gf_cmx_bck; gf_cmx_copy(&gf_cmx_bck, &tr_state->color_mat); gf_cmx_multiply(&tr_state->color_mat, &ptr->cmat); group_2d_traverse(node, (GroupingNode2D *) ptr, tr_state); /*restore traversing state*/ gf_cmx_copy(&tr_state->color_mat, &gf_cmx_bck); } tr_state->invalidate_all = prev_inv; }
void TraverseCollision(GF_Node *node, void *rs, Bool is_destroy) { u32 collide_flags; SFVec3f last_point; Fixed last_dist; M_Collision *col = (M_Collision *)node; GF_TraverseState *tr_state = (GF_TraverseState *)rs; GroupingNode *group = (GroupingNode *) gf_node_get_private(node); if (is_destroy) { gf_sc_check_focus_upon_destroy(node); group_3d_delete(node); return; } if (tr_state->traversing_mode != TRAVERSE_COLLIDE) { group_3d_traverse(node, group, tr_state); } else if (col->collide) { collide_flags = tr_state->camera->collide_flags; last_dist = tr_state->camera->collide_dist; tr_state->camera->collide_flags &= 0; tr_state->camera->collide_dist = FIX_MAX; last_point = tr_state->camera->collide_point; if (col->proxy) { /*always check bounds to update any dirty node*/ tr_state->traversing_mode = TRAVERSE_GET_BOUNDS; gf_node_traverse(col->proxy, rs); tr_state->traversing_mode = TRAVERSE_COLLIDE; gf_node_traverse(col->proxy, rs); } else { group_3d_traverse(node, group, (GF_TraverseState*)rs); } if (tr_state->camera->collide_flags & CF_COLLISION) { col->collideTime = gf_node_get_scene_time(node); gf_node_event_out(node, 5/*"collideTime"*/); /*if not closer restore*/ if (collide_flags && (last_dist<tr_state->camera->collide_dist)) { tr_state->camera->collide_flags = collide_flags; tr_state->camera->collide_dist = last_dist; tr_state->camera->collide_point = last_point; } } else { tr_state->camera->collide_flags = collide_flags; tr_state->camera->collide_dist = last_dist; } } }
static void TraverseOrderedGroup(GF_Node *node, void *rs, Bool is_destroy) { u32 i, count; struct og_pos *priorities; Bool invalidate_backup; OrderedGroupStack *stack = (OrderedGroupStack *) gf_node_get_private(node); M_OrderedGroup *og = (M_OrderedGroup *) node; GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { gf_sc_check_focus_upon_destroy(node); group_2d_destroy(node, (GroupingNode2D*)stack); if (stack->positions) gf_free(stack->positions); gf_free(stack); return; } if (!og->order.count || (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) ) { gf_node_dirty_clear(node, GF_SG_NODE_DIRTY); group_2d_traverse(node, (GroupingNode2D*)stack, tr_state); return; } invalidate_backup = tr_state->invalidate_all; /*check whether the OrderedGroup node has changed*/ if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) { if (stack->positions) gf_free(stack->positions); count = gf_node_list_get_count(og->children); priorities = (struct og_pos*)gf_malloc(sizeof(struct og_pos)*count); for (i=0; i<count; i++) { priorities[i].position = i; priorities[i].priority = (i<og->order.count) ? og->order.vals[i] : 0; } qsort(priorities, count, sizeof(struct og_pos), compare_priority); stack->positions = (u32*)gf_malloc(sizeof(u32) * count); for (i=0; i<count; i++) stack->positions[i] = priorities[i].position; gf_free(priorities); tr_state->invalidate_all = 1; gf_node_dirty_clear(node, GF_SG_NODE_DIRTY); } group_2d_traverse_with_order(node, (GroupingNode2D*)stack, tr_state, stack->positions); tr_state->invalidate_all = invalidate_backup; }
static void svg_traverse_a(GF_Node *node, void *rs, Bool is_destroy) { GF_Matrix2D backup_matrix; GF_Matrix mx_3d; SVGPropertiesPointers backup_props; u32 styling_size = sizeof(SVGPropertiesPointers); u32 backup_flags; GF_TraverseState *tr_state = (GF_TraverseState *)rs; SVGAllAttributes all_atts; if (is_destroy) { gf_sc_check_focus_upon_destroy(node); return; } gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!compositor_svg_traverse_base(node, &all_atts, tr_state, &backup_props, &backup_flags)) return; if (compositor_svg_is_display_off(tr_state->svg_props)) { /*u32 prev_flags = tr_state->switched_off; tr_state->switched_off = 1; compositor_svg_traverse_children(((SVG_Element *)node)->children, tr_state); tr_state->switched_off = prev_flags;*/ memcpy(tr_state->svg_props, &backup_props, styling_size); tr_state->svg_flags = backup_flags; return; } compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { gf_sc_get_nodes_bounds(node, ((SVG_Element *)node)->children, tr_state, NULL); } else { compositor_svg_traverse_children(((SVG_Element *)node)->children, tr_state); if (tr_state->traversing_mode==TRAVERSE_SORT) drawable_check_focus_highlight(node, tr_state, NULL); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); memcpy(tr_state->svg_props, &backup_props, styling_size); tr_state->svg_flags = backup_flags; }
static void TraverseAnchor(GF_Node *node, void *rs, Bool is_destroy) { AnchorStack *st = (AnchorStack *) gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; if (is_destroy) { mpeg4_sensor_deleted(node, &st->hdl); gf_sc_check_focus_upon_destroy(node); if (st->sensors) gf_list_del(st->sensors); gf_free(st); return; } if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) { MFURL *url = NULL; switch (gf_node_get_tag(node)) { case TAG_MPEG4_Anchor: url = & ((M_Anchor *)node)->url; break; #ifndef GPAC_DISABLE_X3D case TAG_X3D_Anchor: url = & ((X_Anchor *)node)->url; break; #endif } st->enabled = 0; if (url && url->count && url->vals[0].url && strlen(url->vals[0].url) ) st->enabled = 1; if (!tr_state->visual->compositor->user->EventProc) { st->enabled = 0; } gf_node_dirty_clear(node, GF_SG_NODE_DIRTY); } group_2d_traverse(node, (GroupingNode2D*)st, tr_state); }
static void TraverseLOD(GF_Node *node, void *rs, Bool is_destroy) { GF_ChildNodeItem *children; MFFloat *ranges; SFVec3f pos, usr; u32 which_child, nb_children; Fixed dist; Bool do_all; GF_Matrix mx; SFVec3f center; GF_TraverseState *tr_state = (GF_TraverseState *)rs; s32 *prev_child = (s32 *)gf_node_get_private(node); if (is_destroy) { gf_free(prev_child); gf_sc_check_focus_upon_destroy(node); return; } /*WARNING: X3D/MPEG4 NOT COMPATIBLE*/ if (gf_node_get_tag(node) == TAG_MPEG4_LOD) { children = ((M_LOD *) node)->level; ranges = &((M_LOD *) node)->range; center = ((M_LOD *) node)->center; #ifndef GPAC_DISABLE_X3D } else { children = ((X_LOD *) node)->children; ranges = &((X_LOD *) node)->range; center = ((X_LOD *) node)->center; #endif } if (!children) return; nb_children = gf_node_list_get_count(children); if (!tr_state->camera) { do_all = 1; which_child = 0; } else { /*can't cache the matrix here*/ usr = tr_state->camera->position; pos = center; gf_mx_copy(mx, tr_state->model_matrix); gf_mx_inverse(&mx); gf_mx_apply_vec(&mx, &usr); gf_vec_diff(pos, pos, usr); dist = gf_vec_len(pos); for (which_child=0; which_child<ranges->count; which_child++) { if (dist<ranges->vals[which_child]) break; } if (which_child>=nb_children) which_child = nb_children-1; /*check if we're traversing the same child or not for audio rendering*/ do_all = 0; if (gf_node_dirty_get(node)) { gf_node_dirty_clear(node, 0); do_all = 1; } else if ((s32) which_child != *prev_child) { *prev_child = which_child; do_all = 1; } } if (do_all) { u32 i; Bool prev_switch = tr_state->switched_off; GF_ChildNodeItem *l = children; tr_state->switched_off = 1; i=0; while (l) { if (i!=which_child) gf_node_traverse(l->node, rs); l = l->next; } tr_state->switched_off = prev_switch; } gf_node_traverse(gf_node_list_get_child(children, which_child), rs); }
static void DestroyTransform(GF_Node *n) { TransformStack *ptr = (TransformStack *)gf_node_get_private(n); gf_sc_check_focus_upon_destroy(n); gf_free(ptr); }
static void TraverseSwitch(GF_Node *node, void *rs, Bool is_destroy) { GF_ChildNodeItem *l; u32 i; Bool prev_switch; GF_ChildNodeItem *children; s32 whichChoice; GF_Node *child; SwitchStack *st = (SwitchStack *)gf_node_get_private(node); GF_TraverseState *tr_state; tr_state = (GF_TraverseState *)rs; children = NULL; /* souchay : be sure to be initialized, -1 seems reasonable since we check if (whichChoice>=0) */ whichChoice = -1; if (is_destroy) { gf_sc_check_focus_upon_destroy(node); gf_free(st); return; } /*WARNING: X3D/MPEG4 NOT COMPATIBLE*/ switch (gf_node_get_tag(node)) { case TAG_MPEG4_Switch: children = ((M_Switch *)node)->choice; whichChoice = ((M_Switch *)node)->whichChoice; break; #ifndef GPAC_DISABLE_X3D case TAG_X3D_Switch: children = ((X_Switch *)node)->children; whichChoice = ((X_Switch *)node)->whichChoice; break; #endif } if (tr_state->traversing_mode!=TRAVERSE_GET_BOUNDS) { prev_switch = tr_state->switched_off; /*check changes in choice field*/ if ((gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) || (st->last_switch != whichChoice) ) { tr_state->switched_off = 1; i=0; l = children; while (l) { // if ((s32) i!=whichChoice) gf_node_traverse(l->node, tr_state); if ((s32) i == st->last_switch) gf_node_traverse(l->node, tr_state); l = l->next; i++; } tr_state->switched_off = 0; st->last_switch = whichChoice; } gf_node_dirty_clear(node, 0); /*no need to check for sensors since a sensor is active for the whole parent group, that is for switch itself CSQ: switch cannot be used to switch sensors, too bad...*/ tr_state->switched_off = prev_switch; } if (!children) return; if (whichChoice==-2) { #ifndef GPAC_DISABLE_3D if (tr_state->visual->autostereo_type) { u32 idx; u32 count = gf_node_list_get_count(children); /*this should be a bit more subtle (reusing views if missing, ...)...*/ idx = tr_state->visual->current_view % count; child = (GF_Node*)gf_node_list_get_child(children, idx); gf_node_traverse(child, tr_state); return; } else #endif //GPAC_DISABLE_3D { /*fallback to first view*/ whichChoice=0; } } if (whichChoice>=0) { child = (GF_Node*)gf_node_list_get_child(children, whichChoice); gf_node_traverse(child, tr_state); } }
static void svg_traverse_switch(GF_Node *node, void *rs, Bool is_destroy) { GF_Matrix2D backup_matrix; GF_Matrix mx_3d; SVGPropertiesPointers backup_props; u32 backup_flags; s32 *selected_idx = gf_node_get_private(node); u32 styling_size = sizeof(SVGPropertiesPointers); SVGAllAttributes all_atts; GF_TraverseState *tr_state = (GF_TraverseState *) rs; if (is_destroy) { gf_free(selected_idx); gf_sc_check_focus_upon_destroy(node); return; } gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (gf_node_dirty_get(node)) { u32 pos = 0; GF_ChildNodeItem *child = ((SVG_Element*)node)->children; *selected_idx = -1; while (child) { SVGAllAttributes atts; gf_svg_flatten_attributes((SVG_Element *)child->node, &atts); if (compositor_svg_evaluate_conditional(tr_state->visual->compositor, &atts)) { *selected_idx = pos; break; } pos++; child = child->next; } drawable_reset_group_highlight(tr_state, node); gf_node_dirty_clear(node, 0); } if (!compositor_svg_traverse_base(node, &all_atts, tr_state, &backup_props, &backup_flags)) return; if (compositor_svg_is_display_off(tr_state->svg_props)) { memcpy(tr_state->svg_props, &backup_props, styling_size); tr_state->svg_flags = backup_flags; return; } if (*selected_idx >= 0) { compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { gf_sc_get_nodes_bounds(node, ((SVG_Element *)node)->children, tr_state, selected_idx); } else if (*selected_idx >= 0) { GF_Node *child = gf_node_list_get_child(((SVG_Element *)node)->children, *selected_idx); gf_node_traverse(child, tr_state); drawable_check_focus_highlight(node, tr_state, NULL); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } memcpy(tr_state->svg_props, &backup_props, styling_size); tr_state->svg_flags = backup_flags; }
static void svg_traverse_g(GF_Node *node, void *rs, Bool is_destroy) { GF_Matrix2D backup_matrix; GF_Matrix mx_3d; SVGPropertiesPointers backup_props; u32 backup_flags; u32 styling_size = sizeof(SVGPropertiesPointers); GF_TraverseState *tr_state = (GF_TraverseState *) rs; SVGAllAttributes all_atts; if (is_destroy) { SVGgStack *group = gf_node_get_private(node); #ifdef GF_SR_USE_VIDEO_CACHE group_2d_destroy_svg(node, group); #else if (group->cache) group_cache_del(group->cache); #endif gf_free(group); gf_sc_check_focus_upon_destroy(node); return; } /*group cache traverse routine*/ else if (tr_state->traversing_mode == TRAVERSE_DRAW_2D) { SVGgStack *group = gf_node_get_private(node); group_cache_draw(group->cache, tr_state); return; } gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!compositor_svg_traverse_base(node, &all_atts, tr_state, &backup_props, &backup_flags)) return; if (compositor_svg_is_display_off(tr_state->svg_props)) { /* u32 prev_flags = tr_state->switched_off; tr_state->switched_off = 1; compositor_svg_traverse_children(((SVG_Element *)node)->children, tr_state); tr_state->switched_off = prev_flags;*/ memcpy(tr_state->svg_props, &backup_props, styling_size); tr_state->svg_flags = backup_flags; return; } compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { gf_sc_get_nodes_bounds(node, ((SVG_Element *)node)->children, tr_state, NULL); } else if (tr_state->traversing_mode == TRAVERSE_SORT) { #ifdef GF_SR_USE_DEPTH Fixed scale, offset, dscale, doffset; #endif Fixed opacity = FIX_ONE; Bool clear = 0; SVGgStack *group; if (!tr_state->in_svg_filter && all_atts.filter && all_atts.filter->iri.target) { svg_draw_filter(all_atts.filter->iri.target, node, tr_state); return; } group = gf_node_get_private(node); if (tr_state->parent_use_opacity) { opacity = tr_state->parent_use_opacity->value; tr_state->parent_use_opacity = NULL; } if (all_atts.opacity) { opacity = gf_mulfix(opacity, all_atts.opacity->value); } if (gf_node_dirty_get(node)&GF_SG_CHILD_DIRTY) { drawable_reset_group_highlight(tr_state, node); clear=1; } #ifdef GF_SR_USE_DEPTH dscale = FIX_ONE; doffset=0; if (all_atts.gpac_depthGain && all_atts.gpac_depthGain->type==SVG_NUMBER_VALUE) dscale = all_atts.gpac_depthGain->value; if (all_atts.gpac_depthOffset && all_atts.gpac_depthOffset->type==SVG_NUMBER_VALUE) doffset = all_atts.gpac_depthOffset->value; scale = tr_state->depth_gain; offset = tr_state->depth_offset; // new offset is multiplied by parent gain and added to parent offset tr_state->depth_offset = gf_mulfix(doffset, scale) + offset; // gain is multiplied by parent gain tr_state->depth_gain = gf_mulfix(scale, dscale); #endif if (opacity < FIX_ONE) { if (!group->cache) { group->cache = group_cache_new(tr_state->visual->compositor, node); group->cache->force_recompute = 1; } group->cache->opacity = opacity; if (tr_state->visual->compositor->zoom_changed) group->cache->force_recompute = 1; group->flags |= GROUP_IS_CACHED | GROUP_PERMANENT_CACHE; #ifdef GF_SR_USE_VIDEO_CACHE group_2d_cache_traverse(node, group, tr_state); #else group_cache_traverse(node, group->cache, tr_state, group->cache->force_recompute, 0, 0); #endif } else { #ifdef GF_SR_USE_VIDEO_CACHE Bool group_cached; group_cached = group_2d_cache_traverse(node, group, tr_state); gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY); /*group is not cached, traverse the children*/ if (!group_cached) { GF_ChildNodeItem *child; DrawableContext *first_ctx = tr_state->visual->cur_context; u32 cache_too_small = 0; Bool skip_first_ctx = (first_ctx && first_ctx->drawable) ? 1 : 0; u32 traverse_time = gf_sys_clock(); u32 last_cache_idx = gf_list_count(tr_state->visual->compositor->cached_groups_queue); tr_state->cache_too_small = 0; child = ((GF_ParentNode *)node)->children; while (child) { gf_node_traverse(child->node, tr_state); child = child->next; if (tr_state->cache_too_small) cache_too_small++; } if (cache_too_small) { tr_state->cache_too_small = 1; } else { /*get the traversal time for each group*/ traverse_time = gf_sys_clock() - traverse_time; group->traverse_time += traverse_time; /*record the traversal information and turn cache on if possible*/ group_2d_cache_evaluate(node, group, tr_state, first_ctx, skip_first_ctx, last_cache_idx); } } #else compositor_svg_traverse_children(((SVG_Element *)node)->children, tr_state); #endif } if (clear) gf_node_dirty_clear(node, 0); drawable_check_focus_highlight(node, tr_state, NULL); #ifdef GF_SR_USE_DEPTH tr_state->depth_gain = scale; tr_state->depth_offset = offset; #endif } else { compositor_svg_traverse_children(((SVG_Element *)node)->children, tr_state); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); memcpy(tr_state->svg_props, &backup_props, styling_size); tr_state->svg_flags = backup_flags; }
static void svg_traverse_svg(GF_Node *node, void *rs, Bool is_destroy) { Bool rootmost_svg, send_resize; u32 viewport_color; SVGsvgStack *stack; GF_Matrix2D backup_matrix, vb_bck; #ifndef GPAC_DISABLE_3D GF_Matrix bck_mx; #endif Bool is_dirty; GF_IRect top_clip; SFVec2f prev_vp; SVGPropertiesPointers backup_props, *prev_props; u32 backup_flags; Bool invalidate_flag; u32 styling_size = sizeof(SVGPropertiesPointers); GF_TraverseState *tr_state = (GF_TraverseState *) rs; SVGAllAttributes all_atts; stack = gf_node_get_private(node); if (is_destroy) { if (stack->svg_props) { gf_svg_properties_reset_pointers(stack->svg_props); gf_free(stack->svg_props); } gf_sc_check_focus_upon_destroy(node); if (stack->vp_fill) drawable_del(stack->vp_fill); gf_free(stack); return; } prev_props = tr_state->svg_props; /*SVG props not set: we are either the root-most <svg> of the compositor or an <svg> inside an <animation>*/ if (!tr_state->svg_props) { tr_state->svg_props = stack->svg_props; if (!tr_state->svg_props) return; } gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!compositor_svg_traverse_base(node, &all_atts, tr_state, &backup_props, &backup_flags)) { tr_state->svg_props = prev_props; return; } /*enable or disable navigation*/ tr_state->visual->compositor->navigation_disabled = (all_atts.zoomAndPan && *all_atts.zoomAndPan == SVG_ZOOMANDPAN_DISABLE) ? 1 : 0; if (compositor_svg_is_display_off(tr_state->svg_props)) { memcpy(tr_state->svg_props, &backup_props, styling_size); tr_state->svg_flags = backup_flags; return; } top_clip = tr_state->visual->top_clipper; gf_mx2d_copy(backup_matrix, tr_state->transform); gf_mx2d_copy(vb_bck, tr_state->vb_transform); #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) gf_mx_copy(bck_mx, tr_state->model_matrix); #endif invalidate_flag = tr_state->invalidate_all; is_dirty = gf_node_dirty_get(node); if (is_dirty & GF_SG_CHILD_DIRTY) drawable_reset_group_highlight(tr_state, node); gf_node_dirty_clear(node, 0); send_resize = 0; if ((stack->parent_vp.x != tr_state->vp_size.x) || (stack->parent_vp.y != tr_state->vp_size.y)) { is_dirty = 1; send_resize = 1; } if (is_dirty || tr_state->visual->compositor->recompute_ar) { svg_recompute_viewport_transformation(node, stack, tr_state, &all_atts); } gf_mx2d_copy(tr_state->vb_transform, stack->viewbox_mx); rootmost_svg = (stack->root_svg && !tr_state->parent_anim_atts) ? 1 : 0; if (tr_state->traversing_mode == TRAVERSE_SORT) { SVG_Paint *vp_fill = NULL; Fixed vp_opacity; if (tr_state->parent_anim_atts) { vp_fill = tr_state->parent_anim_atts->viewport_fill; vp_opacity = tr_state->parent_anim_atts->viewport_fill_opacity ? tr_state->parent_anim_atts->viewport_fill_opacity->value : FIX_ONE; } else { vp_fill = tr_state->svg_props->viewport_fill; vp_opacity = tr_state->svg_props->viewport_fill_opacity ? tr_state->svg_props->viewport_fill_opacity->value : FIX_ONE; } if (vp_fill && (vp_fill->type != SVG_PAINT_NONE) && vp_opacity) { Bool col_dirty = 0; viewport_color = GF_COL_ARGB_FIXED(vp_opacity, vp_fill->color.red, vp_fill->color.green, vp_fill->color.blue); if (stack->prev_color != viewport_color) { stack->prev_color = viewport_color; col_dirty = 1; } if (!rootmost_svg) { DrawableContext *ctx; Fixed width = tr_state->parent_anim_atts->width->value; Fixed height = tr_state->parent_anim_atts->height->value; if (!stack->vp_fill) { stack->vp_fill = drawable_new(); stack->vp_fill->node = node; } if ((width != stack->vp_fill->path->bbox.width) || (height != stack->vp_fill->path->bbox.height)) { drawable_reset_path(stack->vp_fill); gf_path_add_rect(stack->vp_fill->path, 0, 0, width, -height); } ctx = drawable_init_context_svg(stack->vp_fill, tr_state); if (ctx) { ctx->flags &= ~CTX_IS_TRANSPARENT; ctx->aspect.pen_props.width = 0; ctx->aspect.fill_color = viewport_color; ctx->aspect.fill_texture = NULL; if (col_dirty) ctx->flags |= CTX_APP_DIRTY; drawable_finalize_sort(ctx, tr_state, NULL); } } else if (col_dirty) { tr_state->visual->compositor->back_color = viewport_color; /*invalidate the entire visual*/ tr_state->invalidate_all = 1; } } } if (!stack->root_svg && (all_atts.x || all_atts.y)) gf_mx2d_add_translation(&tr_state->vb_transform, all_atts.x->value, all_atts.y->value); #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { if (tr_state->traversing_mode==TRAVERSE_SORT) { GF_Matrix tmp; visual_3d_matrix_push(tr_state->visual); gf_mx_from_mx2d(&tmp, &tr_state->vb_transform); visual_3d_matrix_add(tr_state->visual, tmp.m); } else { gf_mx_add_matrix_2d(&tr_state->model_matrix, &tr_state->vb_transform); } } else #endif { gf_mx2d_pre_multiply(&tr_state->transform, &tr_state->vb_transform); } /*store VP and move it to current VP (eg, the one used to compute the vb_transform)*/ prev_vp = tr_state->vp_size; tr_state->vp_size = stack->vp; /*the event may trigger scripts which may delete nodes / modify the scene. We therefore send the resize event before traversing the scene*/ if (send_resize) { GF_DOM_Event evt; memset(&evt, 0, sizeof(GF_DOM_Event)); evt.bubbles = 1; evt.type = GF_EVENT_RESIZE; gf_dom_event_fire(node, &evt); } if ((stack->vp.x != prev_vp.x) || (stack->vp.y != prev_vp.y)) { GF_Scene *scene = node->sgprivate->scenegraph->userpriv; if (scene) { GF_DOM_Event evt; memset(&evt, 0, sizeof(GF_DOM_Event)); evt.bubbles = 0; evt.screen_rect.width = stack->vpw; evt.screen_rect.height = stack->vph; evt.screen_rect.x = stack->dx; evt.screen_rect.y = stack->dy; evt.prev_translate.x = stack->vp.x; evt.prev_translate.y = stack->vp.y; evt.type = GF_EVENT_VP_RESIZE; gf_scene_notify_event(scene, 0, NULL, &evt, GF_OK); } } if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { gf_sc_get_nodes_bounds(node, ((SVG_Element *)node)->children, tr_state, NULL); } else { compositor_svg_traverse_children(((SVG_Element *)node)->children, tr_state); } tr_state->vp_size = prev_vp; #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { if (tr_state->traversing_mode==TRAVERSE_SORT) visual_3d_matrix_pop(tr_state->visual); gf_mx_copy(tr_state->model_matrix, bck_mx); } #endif gf_mx2d_copy(tr_state->transform, backup_matrix); gf_mx2d_copy(tr_state->vb_transform, vb_bck); memcpy(tr_state->svg_props, &backup_props, styling_size); tr_state->svg_flags = backup_flags; tr_state->visual->top_clipper = top_clip; if (!stack->root_svg) { tr_state->invalidate_all = invalidate_flag; } tr_state->svg_props = prev_props; }