static void svg_finalize_sort(DrawableContext *ctx, SVG_TextStack *st, GF_TraverseState * tr_state) { #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { gf_font_spans_draw_3d(st->spans, tr_state, &ctx->aspect, 0, GF_FALSE); drawable_check_focus_highlight(ctx->drawable->node, tr_state, &st->bounds); ctx->drawable = NULL; return; } #endif /*if text selection mode, we must force redraw of the entire text span because we don't if glyphs have been (un)selected*/ if (!tr_state->immediate_draw && /*text selection on*/ (tr_state->visual->compositor->text_selection /*text sel release*/ || (tr_state->visual->compositor->store_text_state==GF_SC_TSEL_RELEASED)) ) { GF_TextSpan *span; u32 i = 0; Bool unselect = (tr_state->visual->compositor->store_text_state==GF_SC_TSEL_RELEASED) ? GF_TRUE : GF_FALSE; while ((span = (GF_TextSpan*)gf_list_enum(st->spans, &i))) { if (span->flags & GF_TEXT_SPAN_SELECTED) { if (unselect) span->flags &= ~GF_TEXT_SPAN_SELECTED; ctx->flags |= CTX_APP_DIRTY; } } } drawable_finalize_sort(ctx, tr_state, &st->bounds); }
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 svg_traverse_resource(GF_Node *node, void *rs, Bool is_destroy, Bool is_foreign_object) { GF_Matrix2D backup_matrix; GF_Matrix mx_3d; GF_Matrix2D translate; SVGPropertiesPointers backup_props; u32 backup_flags, dirty; Bool is_fragment; GF_Node *used_node; GF_TraverseState *tr_state = (GF_TraverseState *)rs; SVGAllAttributes all_atts; SVGlinkStack *stack = gf_node_get_private(node); SFVec2f prev_vp; SVG_Number *prev_opacity; if (is_destroy) { if (stack->resource) gf_mo_unload_xlink_resource(node, stack->resource); gf_free(stack); return; } gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); if (!all_atts.xlink_href) return; if (!compositor_svg_traverse_base(node, &all_atts, tr_state, &backup_props, &backup_flags)) return; dirty = gf_node_dirty_get(node); if (dirty & GF_SG_CHILD_DIRTY) drawable_reset_group_highlight(tr_state, node); if (dirty & GF_SG_SVG_XLINK_HREF_DIRTY) { stack->fragment_id = NULL; stack->inline_sg = NULL; if (all_atts.xlink_href->string && (all_atts.xlink_href->string[0]=='#')) { stack->fragment_id = all_atts.xlink_href->string; stack->inline_sg = gf_node_get_graph(node); } else { GF_MediaObject *new_res = gf_mo_load_xlink_resource(node, is_foreign_object, 0, -1); if (new_res != stack->resource) { if (stack->resource) gf_mo_unload_xlink_resource(node, stack->resource); stack->resource = new_res; } } } gf_node_dirty_clear(node, 0); /*locate the used node - this is done at each step to handle progressive loading*/ is_fragment = 0; used_node = NULL; if (!stack->inline_sg && !stack->fragment_id && all_atts.xlink_href) { if (all_atts.xlink_href->type == XMLRI_ELEMENTID) { used_node = all_atts.xlink_href->target; is_fragment = 1; } else if (stack->resource) { stack->inline_sg = gf_mo_get_scenegraph(stack->resource); if (!is_foreign_object) { stack->fragment_id = strchr(all_atts.xlink_href->string, '#'); } } } if (!used_node && stack->inline_sg) { if (stack->fragment_id) { used_node = gf_sg_find_node_by_name(stack->inline_sg, (char *) stack->fragment_id+1); is_fragment = 1; } else if (is_foreign_object) { used_node = gf_sg_get_root_node(stack->inline_sg); } } if (!used_node) goto end; /*stack use nodes for picking*/ gf_list_add(tr_state->use_stack, used_node); gf_list_add(tr_state->use_stack, node); gf_mx2d_init(translate); translate.m[2] = (all_atts.x ? all_atts.x->value : 0); translate.m[5] = (all_atts.y ? all_atts.y->value : 0); /*update VP size (SVG 1.1)*/ prev_vp = tr_state->vp_size; if (all_atts.width && all_atts.height) { tr_state->vp_size.x = gf_sc_svg_convert_length_to_display(tr_state->visual->compositor, all_atts.width); tr_state->vp_size.y = gf_sc_svg_convert_length_to_display(tr_state->visual->compositor, all_atts.height); } prev_opacity = tr_state->parent_use_opacity; tr_state->parent_use_opacity = all_atts.opacity; if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); if (!compositor_svg_is_display_off(tr_state->svg_props)) { gf_node_traverse(used_node, tr_state); gf_mx2d_apply_rect(&translate, &tr_state->bounds); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } /*SORT mode and visible, traverse*/ else if (!compositor_svg_is_display_off(tr_state->svg_props) && (*(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN)) { compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { gf_mx_add_matrix_2d(&tr_state->model_matrix, &translate); if (tr_state->traversing_mode==TRAVERSE_SORT) { GF_Matrix tmp; gf_mx_from_mx2d(&tmp, &translate); visual_3d_matrix_add(tr_state->visual, tmp.m); } } else #endif gf_mx2d_pre_multiply(&tr_state->transform, &translate); drawable_check_focus_highlight(node, tr_state, NULL); if (is_fragment) { gf_node_traverse(used_node, tr_state); } else { gf_sc_traverse_subscene(tr_state->visual->compositor, node, stack->inline_sg, tr_state); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); } gf_list_rem_last(tr_state->use_stack); gf_list_rem_last(tr_state->use_stack); tr_state->vp_size = prev_vp; tr_state->parent_use_opacity = prev_opacity; end: memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); tr_state->svg_flags = backup_flags; }
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; }