Example #1
0
static void DestroyLayer3D(GF_Node *node)
{
	Layer3DStack *st = (Layer3DStack *) gf_node_get_private(node);
	GF_Compositor *compositor = st->visual->compositor;

	drawable_del(st->drawable);

#ifdef GPAC_USE_TINYGL
	if (st->tgl_ctx) ostgl_delete_context(st->tgl_ctx);
#endif

	if (st->txh.data) gf_free(st->txh.data);
	/*destroy texture*/
	gf_sc_texture_destroy(&st->txh);

	BindableStackDelete(st->visual->back_stack);
	st->visual->back_stack = NULL;
	BindableStackDelete(st->visual->view_stack);
	st->visual->view_stack = NULL;
	BindableStackDelete(st->visual->navigation_stack);
	st->visual->navigation_stack = NULL;
	BindableStackDelete(st->visual->fog_stack);
	st->visual->fog_stack = NULL;
	visual_del(st->visual);


	if (compositor && compositor->active_layer == node) compositor->active_layer = NULL;
	gf_free(st);
}
Example #2
0
void group_cache_del(GroupCache *cache)
{
	drawable_del(cache->drawable);
	if (cache->txh.data) gf_free(cache->txh.data);
	gf_sc_texture_release(&cache->txh);
	gf_sc_texture_destroy(&cache->txh);
	gf_free(cache);
}
Example #3
0
static void svg_sani_destroy_path(GF_Node *node)
{
	Drawable *dr = gf_node_get_private(node);
#if USE_GF_PATH
	/* The path is the same as the one in the SVG node, don't delete it here */
	dr->path = NULL;
#endif
	drawable_del(dr);
}
Example #4
0
static void svg_traverse_filter(GF_Node *node, void *rs, Bool is_destroy)
{
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	GF_FilterStack *st = gf_node_get_private(node);
	if (is_destroy) {
		drawable_del(st->drawable);
		if (st->data) gf_free(st->data);
		st->txh.data = NULL;
		gf_sc_texture_release(&st->txh);
		gf_sc_texture_destroy(&st->txh);
		gf_free(st);
		return;
	}

	if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) {
		if (! tr_state->visual->DrawBitmap(tr_state->visual, tr_state, tr_state->ctx, NULL)) {
			visual_2d_texture_path(tr_state->visual, st->drawable->path, tr_state->ctx, tr_state);
		}
	}
}
Example #5
0
static void DestroyBackground2D(GF_Node *node)
{
	Background2DStack *stack = (Background2DStack *) gf_node_get_private(node);

	PreDestroyBindable(node, stack->reg_stacks);
	gf_list_del(stack->reg_stacks);

	while (gf_list_count(stack->status_stack)) {
		BackgroundStatus *status = (BackgroundStatus *)gf_list_get(stack->status_stack, 0);
		gf_list_rem(stack->status_stack, 0);
		gf_free(status);
	}
	gf_list_del(stack->status_stack);

	drawable_del(stack->drawable);
	gf_sc_texture_destroy(&stack->txh);
#ifndef GPAC_DISABLE_3D
	if (stack->mesh) mesh_free(stack->mesh);
#endif
	gf_free(stack);
}
Example #6
0
static void Text_Traverse(GF_Node *n, void *rs, Bool is_destroy)
{
	DrawableContext *ctx;
	M_Text *txt = (M_Text *) n;
	TextStack *st = (TextStack *) gf_node_get_private(n);
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;

	if (is_destroy) {
		text_clean_paths(gf_sc_get_compositor(n), st);
		drawable_del(st->graph);
		gf_list_del(st->spans);
		gf_free(st);
		return;
	}

	if (!txt->string.count) return;

	if (tr_state->text_split_mode) {
		gf_node_dirty_clear(n, 0);
		text_clean_paths(tr_state->visual->compositor, st);
		build_text_split(st, txt, tr_state);
		return;
	}

	text_check_changes(n, st, tr_state);

	switch (tr_state->traversing_mode) {
	case TRAVERSE_DRAW_2D:
		text_draw_2d(n, tr_state);
		return;
#ifndef GPAC_DISABLE_3D
	case TRAVERSE_DRAW_3D:
		text_draw_3d(tr_state, n, st);
		return;
#endif
	case TRAVERSE_PICK:
		tr_state->text_parent = n;
		gf_font_spans_pick(n, st->spans, tr_state, &st->bounds, 0, NULL);
		tr_state->text_parent = NULL;
		return;
	case TRAVERSE_GET_BOUNDS:
		tr_state->bounds = st->bounds;
		return;
	case TRAVERSE_GET_TEXT:
		tr_state->text_parent = n;
		gf_font_spans_get_selection(n, st->spans, tr_state);
		tr_state->text_parent = NULL;
		return;
	case TRAVERSE_SORT:
		break;
	default:
		return;
	}

#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) return;
#endif

	ctx = drawable_init_context_mpeg4(st->graph, tr_state);
	if (!ctx) return;
	ctx->sub_path_index = tr_state->text_split_idx;

	ctx->flags |= CTX_IS_TEXT;
	if (!GF_COL_A(ctx->aspect.fill_color)) {
		/*override line join*/
		ctx->aspect.pen_props.join = GF_LINE_JOIN_MITER;
		ctx->aspect.pen_props.cap = GF_LINE_CAP_FLAT;
	}

	/*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) ? 1 : 0;
		while ((span = 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;
			}
		}
	}

	if (ctx->sub_path_index) {
		GF_TextSpan *span = (GF_TextSpan *)gf_list_get(st->spans, ctx->sub_path_index-1);
		if (span) drawable_finalize_sort(ctx, tr_state, &span->bounds);
	} else {
		drawable_finalize_sort(ctx, tr_state, &st->bounds);
	}
}
Example #7
0
static void fs_traverse(GF_Node *node, void *rs, Bool is_destroy)
{
	u32 i;
	DrawableContext *ctx;
	FSStack *st = (FSStack *) gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState*)rs;

	if (is_destroy) {
		clean_paths(st);
		drawable_del(st->drawable);
		gf_list_del(st->items);
		gf_free(st);
		return;
	}
	/*check for geometry change*/
	if (gf_node_dirty_get(node)) {
		gf_node_dirty_clear(node, 0);
		/*build*/
		clean_paths(st);
		build_shape(st, node);
	}

	switch (tr_state->traversing_mode) {
	case TRAVERSE_DRAW_2D:
		ctx = tr_state->ctx;
		for (i=0; i<gf_list_count(st->items); i++) {
			FSItem *item = gf_list_get(st->items, i);
			ctx->flags &= ~(CTX_PATH_FILLED | CTX_PATH_STROKE);
			memset(&ctx->aspect, 0, sizeof(DrawAspect2D));
			if (item->fill_col) {
				ctx->aspect.fill_color = item->fill_col;
			}
			if (item->width) {
				ctx->aspect.line_color = item->line_col;
				ctx->aspect.pen_props.width = item->width;
			}
			visual_2d_draw_path(tr_state->visual, item->path, ctx, NULL, NULL, tr_state);
		}
		return;

#ifndef GPAC_DISABLE_3D
	case TRAVERSE_DRAW_3D:
		ctx = tr_state->ctx;
		for (i=0; i<gf_list_count(st->items); i++) {
			FSItem *item = gf_list_get(st->items, i);
			memset(&ctx->aspect, 0, sizeof(DrawAspect2D));
			if (item->fill_col) {
				ctx->aspect.fill_color = item->fill_col;
			}
			if (item->width) {
				ctx->aspect.line_color = item->line_col;
				ctx->aspect.pen_props.width = item->width;
			}
			if (!item->mesh) {
				item->mesh = new_mesh();
				mesh_from_path(item->mesh, item->path);
			}
			st->drawable->mesh = item->mesh;
			visual_3d_draw_2d_with_aspect(st->drawable, tr_state, &ctx->aspect);
			st->drawable->mesh = NULL;
		}
		return;
#endif
	case TRAVERSE_PICK:
		/*todo*/
		return;
	case TRAVERSE_GET_BOUNDS:
		tr_state->bounds = st->bounds;
		return;
	case TRAVERSE_SORT:
#ifndef GPAC_DISABLE_3D
		if (tr_state->visual->type_3d) return;
#endif
		/*finalize*/
		ctx = drawable_init_context_mpeg4(st->drawable, tr_state);
		if (!ctx) return;

		/*force width to max width used for clipper compute*/
		if (st->max_width) {
			ctx->aspect.pen_props.width = st->max_width;
		}
		drawable_finalize_sort(ctx, tr_state, &st->bounds);
		break;
	}
}
Example #8
0
static void svg_traverse_text(GF_Node *node, void *rs, Bool is_destroy)
{
	SVGPropertiesPointers backup_props;
	u32 backup_flags;
	GF_Matrix2D backup_matrix;
	GF_Matrix mx3d;
	GF_ChildNodeItem *child;
	DrawableContext *ctx;
	SVG_TextStack *st = (SVG_TextStack *)gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	SVG_Element *text = (SVG_Element *)node;
	SVGAllAttributes atts;
	u32 i,imax;
	Fixed * lw;

	if (is_destroy) {
		drawable_del(st->drawable);
		svg_reset_text_stack(st);
		gf_list_del(st->spans);
		gf_free(st);
		return;
	}

	if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) {
		svg_text_draw_2d(st, tr_state);
		return;
	}
	else if (tr_state->traversing_mode==TRAVERSE_GET_TEXT) {
		tr_state->text_parent = node;
		gf_font_spans_get_selection(node, st->spans, tr_state);
		/*and browse children*/
		child = ((GF_ParentNode *) text)->children;
		while (child) {
			switch  (gf_node_get_tag(child->node)) {
			case TAG_SVG_tspan:
				gf_node_traverse(child->node, tr_state);
				break;
			}
			child = child->next;
		}
		tr_state->text_parent = NULL;
		return;
	}

	gf_svg_flatten_attributes(text, &atts);
	if (!compositor_svg_traverse_base(node, &atts, tr_state, &backup_props, &backup_flags))
		return;

	tr_state->in_svg_text++;
	tr_state->text_parent = node;

	if (tr_state->traversing_mode==TRAVERSE_PICK) {
		compositor_svg_apply_local_transformation(tr_state, &atts, &backup_matrix, &mx3d);
		if (*tr_state->svg_props->pointer_events!=SVG_POINTEREVENTS_NONE)
			gf_font_spans_pick(node, st->spans, tr_state, &st->bounds, 1, st->drawable);

		/*and browse children*/
		child = ((GF_ParentNode *) text)->children;
		while (child) {
			switch  (gf_node_get_tag(child->node)) {
			case TAG_SVG_tspan:
				gf_node_traverse(child->node, tr_state);
				break;
			}
			child = child->next;
		}
		memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
		compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx3d);
		tr_state->svg_flags = backup_flags;
		tr_state->text_parent = NULL;
		tr_state->in_svg_text--;
		return;
	}
	else if (tr_state->traversing_mode==TRAVERSE_GET_TEXT) {
		gf_font_spans_get_selection(node, st->spans, tr_state);
		memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
		tr_state->svg_flags = backup_flags;
		tr_state->text_parent = NULL;
		tr_state->in_svg_text--;
		return;
	}

	compositor_svg_apply_local_transformation(tr_state, &atts, &backup_matrix, &mx3d);

	if ( (st->prev_size != tr_state->svg_props->font_size->value) ||
	        (st->prev_flags != *tr_state->svg_props->font_style) ||
	        (st->prev_anchor != *tr_state->svg_props->text_anchor) ||
	        (gf_node_dirty_get(node) & (GF_SG_SVG_GEOMETRY_DIRTY | GF_SG_CHILD_DIRTY) )
	        || tr_state->visual->compositor->reset_fonts
	   ) {
		u32 mode;
		child = ((GF_ParentNode *) text)->children;

		svg_reset_text_stack(st);
		tr_state->text_end_x = 0;
		tr_state->text_end_y = 0;
		/*init the xml:space algo*/
		tr_state->last_char_type = 0;

		/*initialize x and y counters - stored at the traverse level for handling tspan & co*/
		if (atts.text_x) tr_state->count_x = gf_list_count(*atts.text_x);
		else tr_state->count_x=0;
		if (atts.text_y) tr_state->count_y = gf_list_count(*atts.text_y);
		else tr_state->count_y=0;
		if (atts.text_rotate) tr_state->count_rotate = gf_list_count(*atts.text_rotate);
		else tr_state->count_rotate=0;

		/*horizontal justifiers container*/
		tr_state->x_anchors = gf_list_new();

		/*compute length of all text blocks*/
		while (child) {
			svg_compute_text_width(child->node, &atts, tr_state);
			child=child->next;
		}

		/*apply justification of all blocks*/
		imax=gf_list_count(tr_state->x_anchors);
		for (i=0; i<imax; i++) {
			lw=gf_list_get(tr_state->x_anchors, i);
			svg_apply_text_anchor(tr_state, lw);
		}

		/*re-initialize x and y counters for final compute*/
		if (atts.text_x) tr_state->count_x = gf_list_count(*atts.text_x);
		else tr_state->count_x=0;
		if (atts.text_y) tr_state->count_y = gf_list_count(*atts.text_y);
		else tr_state->count_y=0;
		if (atts.text_rotate) tr_state->count_rotate = gf_list_count(*atts.text_rotate);
		else tr_state->count_rotate=0;
		tr_state->idx_rotate = 0;
		tr_state->chunk_index = 0;

		/*initialize current text position*/
		if (!tr_state->text_end_x) {
			SVG_Coordinate *xc = (atts.text_x ? (SVG_Coordinate *) gf_list_get(*atts.text_x, 0) : NULL);
			tr_state->text_end_x = (xc ? xc->value : 0);
		}
		if (!tr_state->text_end_y) {
			SVG_Coordinate *yc = (atts.text_y ? (SVG_Coordinate *) gf_list_get(*atts.text_y, 0) : NULL);
			tr_state->text_end_y = (yc ? yc->value : 0);
		}

		/*pass x and y to children*/
		tr_state->text_x = atts.text_x;
		tr_state->text_y = atts.text_y;
		tr_state->text_rotate = atts.text_rotate;

		drawable_reset_path(st->drawable);

		/*switch to bounds mode, and recompute children*/
		mode = tr_state->traversing_mode;
		tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
		tr_state->last_char_type = 0;

		child = ((GF_ParentNode *) text)->children;
		while (child) {
			svg_traverse_text_block(child->node, &atts, tr_state, st->spans);
			child = child->next;
		}
		tr_state->traversing_mode = mode;
		gf_node_dirty_clear(node, 0);
		drawable_mark_modified(st->drawable, tr_state);
		st->prev_size = tr_state->svg_props->font_size->value;
		st->prev_flags = *tr_state->svg_props->font_style;
		st->prev_anchor = *tr_state->svg_props->text_anchor;

		while (gf_list_count(tr_state->x_anchors)) {
			Fixed *f = gf_list_last(tr_state->x_anchors);
			gf_list_rem_last(tr_state->x_anchors);
			gf_free(f);
		}
		gf_list_del(tr_state->x_anchors);
		tr_state->x_anchors = NULL;

		svg_update_bounds(st);
	}

	if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
		if (!compositor_svg_is_display_off(tr_state->svg_props))
			tr_state->bounds = st->bounds;

	} else if ((tr_state->traversing_mode == TRAVERSE_SORT)
	           && !compositor_svg_is_display_off(tr_state->svg_props)
	           && (*(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN)
	          ) {
		ctx = drawable_init_context_svg(st->drawable, tr_state);
		if (ctx) svg_finalize_sort(ctx, st, tr_state);

		/*and browse children*/
		child = ((GF_ParentNode *) text)->children;
		while (child) {
			switch  (gf_node_get_tag(child->node)) {
			case TAG_SVG_tspan:
				gf_node_traverse(child->node, tr_state);
				break;
			case TAG_SVG_switch:
				gf_node_traverse(child->node, tr_state);
				break;
			}
			child = child->next;
		}
	}
	tr_state->in_svg_text--;
	tr_state->text_parent = NULL;

	compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx3d);
	memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
	tr_state->svg_flags = backup_flags;
}
Example #9
0
static void svg_traverse_textArea(GF_Node *node, void *rs, Bool is_destroy)
{
	SVGPropertiesPointers backup_props;
	u32 backup_flags;
	GF_Matrix mx3d;
	GF_Matrix2D backup_matrix;
	DrawableContext *ctx = NULL;
	GF_ChildNodeItem *child;
	SVG_TextStack *st = (SVG_TextStack *)gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	SVG_Element *text = (SVG_Element *)node;
	SVGAllAttributes atts;

	if (is_destroy) {
		drawable_del(st->drawable);
		svg_reset_text_stack(st);
		gf_list_del(st->spans);
		gf_free(st);
		return;
	}

	if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) {
		svg_text_draw_2d(st, tr_state);
		return;
	}
	else if (tr_state->traversing_mode==TRAVERSE_GET_TEXT) {
		tr_state->text_parent = node;
		gf_font_spans_get_selection(node, st->spans, tr_state);
		/*and browse children*/
		child = ((GF_ParentNode *) text)->children;
		while (child) {
			switch  (gf_node_get_tag(child->node)) {
			case TAG_SVG_tspan:
			case TAG_SVG_a:
				gf_node_traverse(child->node, tr_state);
				break;
			}
			child = child->next;
		}
		tr_state->text_parent = NULL;
		return;
	}


	gf_svg_flatten_attributes(text, &atts);
	if (!compositor_svg_traverse_base(node, &atts, tr_state, &backup_props, &backup_flags))
		return;

	tr_state->text_parent = node;
	tr_state->in_svg_text_area++;

	if (tr_state->traversing_mode==TRAVERSE_PICK) {
		if (*tr_state->svg_props->pointer_events!=SVG_POINTEREVENTS_NONE) {
			compositor_svg_apply_local_transformation(tr_state, &atts, &backup_matrix, &mx3d);
			gf_font_spans_pick(node, st->spans, tr_state, &st->bounds, GF_TRUE, st->drawable);

			/*and browse children*/
			child = ((GF_ParentNode *) node)->children;
			while (child) {
				gf_node_traverse(child->node, tr_state);
				child = child->next;
			}
			compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx3d);
			memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
			tr_state->svg_flags = backup_flags;
		}
		tr_state->in_svg_text_area--;
		tr_state->text_parent = NULL;
		return;
	}

	compositor_svg_apply_local_transformation(tr_state, &atts, &backup_matrix, &mx3d);

	if ( (st->prev_size != tr_state->svg_props->font_size->value) ||
	        (st->prev_flags != *tr_state->svg_props->font_style) ||
	        (st->prev_anchor != *tr_state->svg_props->text_anchor) ||
	        (gf_node_dirty_get(node) & (GF_SG_SVG_GEOMETRY_DIRTY | GF_SG_CHILD_DIRTY) )
	        || tr_state->visual->compositor->reset_fonts
	   ) {
		u32 mode;

		child = ((GF_ParentNode *) text)->children;

		svg_reset_text_stack(st);
		gf_node_dirty_clear(node, 0);
		drawable_mark_modified(st->drawable, tr_state);
		drawable_reset_path(st->drawable);

		tr_state->max_length = (atts.width ? (atts.width->type == SVG_NUMBER_AUTO ? FIX_MAX : atts.width->value) : FIX_MAX);
		tr_state->max_height = (atts.height ? (atts.height->type == SVG_NUMBER_AUTO ? FIX_MAX : atts.height->value) : FIX_MAX);
		tr_state->base_x = (atts.x ? atts.x->value : 0);
		tr_state->base_y = (atts.y ? atts.y->value : 0);
		/*init the xml:space algo*/
		tr_state->last_char_type = 0;
		/*let it initialize from first font*/
		tr_state->line_spacing = 0;
		tr_state->text_end_x = 0;
		tr_state->text_end_y = (tr_state->svg_props->line_increment->type == SVG_NUMBER_AUTO ? 0 : tr_state->svg_props->line_increment->value);

		tr_state->x_anchors = gf_list_new();

		if (tr_state->svg_props->font_size && (tr_state->svg_props->font_size->value <= tr_state->max_height)) {
			Fixed remain;
			u32 c, refresh_to_idx, prev_refresh;
			/*switch to bounds mode, and recompute children*/
			mode = tr_state->traversing_mode;
			tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;

			prev_refresh = tr_state->refresh_children_bounds;
			tr_state->refresh_children_bounds = 0;
			c = refresh_to_idx = 0;
			child = ((GF_ParentNode *) text)->children;
			while (child) {
				c++;
				switch  (gf_node_get_tag(child->node)) {
				case TAG_DOMText:
					svg_traverse_dom_text_area(child->node, &atts, tr_state, st->spans);
					break;
				case TAG_SVG_tspan:
					/*mark tspan as dirty to force rebuild*/
					gf_node_dirty_set(child->node, 0, GF_FALSE);
					gf_node_traverse(child->node, tr_state);
					break;
				case TAG_SVG_switch:
				case TAG_SVG_a:
				case TAG_SVG_tbreak:
					gf_node_traverse(child->node, tr_state);
					break;
				default:
					break;
				}
				if (tr_state->refresh_children_bounds) {
					tr_state->refresh_children_bounds=0;
					refresh_to_idx=c;
				}

				child=child->next;
			}
			st->prev_size = tr_state->svg_props->font_size->value;
			st->prev_flags = *tr_state->svg_props->font_style;
			st->prev_anchor = *tr_state->svg_props->text_anchor;

			svg_text_area_reset_state(tr_state);
			gf_list_del(tr_state->x_anchors);
			tr_state->x_anchors = NULL;

			remain = 0;
			if (tr_state->refresh_children_bounds) {
				refresh_to_idx = (u32) -1;
				tr_state->base_shift = 0;
			}
			if (tr_state->svg_props->display_align) {
				switch (*tr_state->svg_props->display_align) {
				case SVG_DISPLAYALIGN_CENTER:
					remain = (tr_state->max_height-tr_state->text_end_y) / 2;
					break;
				case SVG_DISPLAYALIGN_AFTER:
					remain = tr_state->max_height - tr_state->text_end_y;
					break;
				default:
					remain = 0;
					break;
				}
				if (remain<0) remain=0;
				if (remain) {
					refresh_to_idx = (u32) -1;
					tr_state->base_shift = remain;
					svg_text_area_shift_bounds(st, tr_state);
				}
			}

			if (refresh_to_idx) {
				tr_state->refresh_children_bounds=1;
				/*and retraverse in case of bounds adjustements*/
				child = ((GF_ParentNode *) text)->children;
				while (child) {
					switch (gf_node_get_tag(child->node)) {
					case TAG_DOMText:
						break;
					case TAG_SVG_tspan:
					case TAG_SVG_switch:
					case TAG_SVG_a:
						gf_node_traverse(child->node, tr_state);
						break;
					default:
						break;
					}
					child=child->next;
					refresh_to_idx--;
					if (!refresh_to_idx) break;
				}
				tr_state->base_shift = 0;
			}
			tr_state->traversing_mode = mode;
			tr_state->refresh_children_bounds = prev_refresh;
		}
		svg_update_bounds(st);
	}

	if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
		if (!compositor_svg_is_display_off(tr_state->svg_props))
			tr_state->bounds = st->bounds;
	} else if ( (tr_state->traversing_mode == TRAVERSE_SORT)
	            && !compositor_svg_is_display_off(tr_state->svg_props)
	            && (*(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN)
	          ) {

		ctx = drawable_init_context_svg(st->drawable, tr_state);
		if (ctx) svg_finalize_sort(ctx, st, tr_state);

		child = ((GF_ParentNode *) text)->children;
		while (child) {
			switch  (gf_node_get_tag(child->node)) {
			case TAG_DOMText:
				break;
			case TAG_SVG_tspan:
			case TAG_SVG_switch:
			case TAG_SVG_a:
				gf_node_traverse(child->node, tr_state);
				break;
			default:
				break;
			}
			child = child->next;
		}
	}
	tr_state->in_svg_text_area--;
	tr_state->text_parent = NULL;


	compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx3d);
	memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
	tr_state->svg_flags = backup_flags;
}
Example #10
0
static void svg_traverse_tspan(GF_Node *node, void *rs, Bool is_destroy)
{
	SVGPropertiesPointers backup_props;
	u32 backup_flags;
	GF_Matrix2D backup_matrix;
	GF_Matrix mx3d;
	DrawableContext *ctx;
	SVG_TextStack *st = (SVG_TextStack *)gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	SVG_Element *tspan = (SVG_Element *)node;
	SVGAllAttributes atts;
	GF_ChildNodeItem *child;

	if (is_destroy) {
		drawable_del(st->drawable);
		svg_reset_text_stack(st);
		gf_list_del(st->spans);
		gf_free(st);
		return;
	}
	if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) {
		svg_text_draw_2d(st, tr_state);
		return;
	}
	else if (tr_state->traversing_mode==TRAVERSE_GET_TEXT) {
		gf_font_spans_get_selection(node, st->spans, tr_state);
		/*and browse children*/
		child = ((GF_ParentNode *) tspan)->children;
		while (child) {
			switch  (gf_node_get_tag(child->node)) {
			case TAG_SVG_tspan:
				gf_node_traverse(child->node, tr_state);
				break;
			}
			child = child->next;
		}
		return;
	}

	if (!tr_state->in_svg_text && !tr_state->in_svg_text_area) return;

	gf_svg_flatten_attributes(tspan, &atts);
	if (!compositor_svg_traverse_base(node, &atts, tr_state, &backup_props, &backup_flags))
		return;

	if (tr_state->traversing_mode==TRAVERSE_PICK) {
		if (*tr_state->svg_props->pointer_events!=SVG_POINTEREVENTS_NONE)
			gf_font_spans_pick(node, st->spans, tr_state, &st->bounds, GF_TRUE, st->drawable);

		/*and browse children*/
		child = ((GF_ParentNode *) tspan)->children;
		while (child) {
			switch  (gf_node_get_tag(child->node)) {
			case TAG_SVG_tspan:
				gf_node_traverse(child->node, tr_state);
				break;
			}
			child = child->next;
		}
		memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
		tr_state->svg_flags = backup_flags;
		return;
	}

	compositor_svg_apply_local_transformation(tr_state, &atts, &backup_matrix, &mx3d);

	if ( (st->prev_size != tr_state->svg_props->font_size->value) ||
	        (st->prev_flags != *tr_state->svg_props->font_style) ||
	        (st->prev_anchor != *tr_state->svg_props->text_anchor) ||
	        (gf_node_dirty_get(node) & (GF_SG_SVG_GEOMETRY_DIRTY | GF_SG_CHILD_DIRTY) )
	   ) {
		u32 mode;

		/*tspan has been modified in the SORT stage, which means that an anim local to tspan has modified the node.
		The result of the parent (text, textArea) will thus be wrong if we try to update the tspan. We therefore
		keep the previous computed drawable, and invalidate the parent for next frame*/
		if (tr_state->traversing_mode==TRAVERSE_SORT) {
			gf_node_dirty_set(node, 0, GF_TRUE);
			goto skip_changes;
		}

		/*switch to bounds mode, and recompute children*/
		mode = tr_state->traversing_mode;
		tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;

		svg_reset_text_stack(st);
		child = ((GF_ParentNode *) tspan)->children;

		while (child) {
			switch  (gf_node_get_tag(child->node)) {
			case TAG_DOMText:
				svg_traverse_domtext(child->node, &atts, tr_state, st->spans, NULL);
				break;
			case TAG_SVG_tspan:
				gf_node_dirty_set(child->node, 0, GF_FALSE);
				gf_node_traverse(child->node, tr_state);
				break;
			case TAG_SVG_switch:
			case TAG_SVG_a:
			case TAG_SVG_tbreak:
				gf_node_traverse(child->node, tr_state);
				break;
			default:
				break;
			}
			child = child->next;
		}
		tr_state->traversing_mode = mode;
		gf_node_dirty_clear(node, 0);
		drawable_mark_modified(st->drawable, tr_state);
		st->prev_size = tr_state->svg_props->font_size->value;
		st->prev_flags = *tr_state->svg_props->font_style;
		st->prev_anchor = *tr_state->svg_props->text_anchor;

		svg_update_bounds(st);
	}
skip_changes:

	if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
		if (tr_state->refresh_children_bounds) {
			if (tr_state->base_shift)
				svg_text_area_shift_bounds(st, tr_state);
			else
				svg_update_bounds(st);
			child = ((GF_ParentNode *) tspan)->children;
			while (child) {
				switch  (gf_node_get_tag(child->node)) {
				case TAG_SVG_tspan:
				case TAG_SVG_switch:
				case TAG_SVG_a:
					gf_node_traverse(child->node, tr_state);
					break;
				default:
					break;
				}
				child = child->next;
			}
		}
		if (!compositor_svg_is_display_off(tr_state->svg_props))
			tr_state->bounds = st->bounds;

	}
	else if (
	    (tr_state->traversing_mode == TRAVERSE_SORT)
	    && !compositor_svg_is_display_off(tr_state->svg_props)
	    && ( *(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN)
	) {
		child = ((GF_ParentNode *) tspan)->children;

		ctx = drawable_init_context_svg(st->drawable, tr_state);
		if (ctx) svg_finalize_sort(ctx, st, tr_state);

		while (child) {
			switch  (gf_node_get_tag(child->node)) {
			case TAG_SVG_tspan:
			case TAG_SVG_switch:
			case TAG_SVG_a:
				gf_node_traverse(child->node, tr_state);
				break;
			default:
				break;
			}
			child = child->next;
		}
	}

	compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx3d);
	memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
	tr_state->svg_flags = backup_flags;
}
Example #11
0
static void svg_traverse_bitmap(GF_Node *node, void *rs, Bool is_destroy)
{
	Fixed cx, cy, angle;
	/*video stack is just an extension of image stack, type-casting is OK*/
	SVG_video_stack *stack = (SVG_video_stack*)gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	SVGPropertiesPointers backup_props;
	u32 backup_flags;
	GF_Matrix2D backup_matrix;
	GF_Matrix mx_3d;
	DrawableContext *ctx;
	SVGAllAttributes all_atts;


	if (is_destroy) {
		gf_sc_texture_destroy(&stack->txh);
		gf_sg_mfurl_del(stack->txurl);

		drawable_del(stack->graph);
		if (stack->audio) {
			gf_node_unregister(stack->audio, NULL);
		}
		gf_free(stack);
		return;
	} 


	/*TRAVERSE_DRAW is NEVER called in 3D mode*/
	if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) {
		SVG_Draw_bitmap(tr_state);
		return;
	}
	else if (tr_state->traversing_mode==TRAVERSE_PICK) {
		svg_drawable_pick(node, stack->graph, tr_state);
		return;
	}

	/*flatten attributes and apply animations + inheritance*/
	gf_svg_flatten_attributes((SVG_Element *)node, &all_atts);
	if (!compositor_svg_traverse_base(node, &all_atts, (GF_TraverseState *)rs, &backup_props, &backup_flags))
		return;

	if (gf_node_dirty_get(node) & GF_SG_SVG_XLINK_HREF_DIRTY) {
		gf_term_get_mfurl_from_xlink(node, &stack->txurl);
		stack->txh.width = stack->txh.height = 0;
		
		/*remove associated audio if any*/
		if (stack->audio) {
			svg_audio_smil_evaluate_ex(NULL, 0, SMIL_TIMING_EVAL_REMOVE, stack->audio, stack->txh.owner);
			gf_node_unregister(stack->audio, NULL);
			stack->audio = NULL;
		}
		stack->audio_dirty = GF_TRUE;
		
		if (stack->txurl.count) svg_play_texture(stack, &all_atts);
		gf_node_dirty_clear(node, GF_SG_SVG_XLINK_HREF_DIRTY);
	}

	if (gf_node_dirty_get(node)) {
		/*do not clear dirty state until the image is loaded*/
		if (stack->txh.width) {
			gf_node_dirty_clear(node, 0);
			SVG_Build_Bitmap_Graph((SVG_video_stack*)gf_node_get_private(node), tr_state);
		}
		
	} 

	if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
		if (!compositor_svg_is_display_off(tr_state->svg_props)) {
			gf_path_get_bounds(stack->graph->path, &tr_state->bounds);
			compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d);

			if (svg_video_get_transform_behavior(tr_state, &all_atts, &cx, &cy, &angle)) {
				GF_Matrix2D mx;
				tr_state->bounds.width = INT2FIX(stack->txh.width);
				tr_state->bounds.height = INT2FIX(stack->txh.height);
				tr_state->bounds.x = cx - tr_state->bounds.width/2;
				tr_state->bounds.y = cy + tr_state->bounds.height/2;
				gf_mx2d_init(mx);
				gf_mx2d_add_rotation(&mx, 0, 0, angle);
				gf_mx2d_apply_rect(&mx, &tr_state->bounds);
			} else {
				gf_mx2d_apply_rect(&tr_state->transform, &tr_state->bounds);
			}

			compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d);
		}
	} else if (tr_state->traversing_mode == TRAVERSE_SORT) {
		if (!compositor_svg_is_display_off(tr_state->svg_props) && ( *(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN) ) {
			GF_Matrix mx_bck;
			Bool restore_mx = GF_FALSE;

			compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d);

			ctx = drawable_init_context_svg(stack->graph, tr_state);
			if (!ctx || !ctx->aspect.fill_texture ) return;

			if (svg_video_get_transform_behavior(tr_state, &all_atts, &cx, &cy, &angle)) {
				drawable_reset_path(stack->graph);
				gf_path_add_rect_center(stack->graph->path, cx, cy, INT2FIX(stack->txh.width), INT2FIX(stack->txh.height));

				gf_mx2d_copy(mx_bck, tr_state->transform);
				restore_mx = GF_TRUE;
				
				gf_mx2d_init(tr_state->transform);
				gf_mx2d_add_rotation(&tr_state->transform, cx, cy, angle);
			}

			/*even if set this is not true*/
			ctx->aspect.pen_props.width = 0;
			ctx->flags |= CTX_NO_ANTIALIAS;

			/*if rotation, transparent*/
			ctx->flags &= ~CTX_IS_TRANSPARENT;
			if (ctx->transform.m[1] || ctx->transform.m[3]) {
				ctx->flags |= CTX_IS_TRANSPARENT;
				ctx->flags &= ~CTX_NO_ANTIALIAS;
			}
			else if (ctx->aspect.fill_texture->transparent) 
				ctx->flags |= CTX_IS_TRANSPARENT;
			else if (tr_state->svg_props->opacity && (tr_state->svg_props->opacity->type==SVG_NUMBER_VALUE) && (tr_state->svg_props->opacity->value!=FIX_ONE)) {
				ctx->flags = CTX_IS_TRANSPARENT;
				ctx->aspect.fill_color = GF_COL_ARGB(FIX2INT(0xFF * tr_state->svg_props->opacity->value), 0, 0, 0);
			}

#ifndef GPAC_DISABLE_3D
			if (tr_state->visual->type_3d) {
				if (!stack->graph->mesh) {
					stack->graph->mesh = new_mesh();
					mesh_from_path(stack->graph->mesh, stack->graph->path);
				}
				compositor_3d_draw_bitmap(stack->graph, &ctx->aspect, tr_state, 0, 0, FIX_ONE, FIX_ONE);
				ctx->drawable = NULL;
			} else 
#endif
			{
				drawable_finalize_sort(ctx, tr_state, NULL);
			}

			if (restore_mx) gf_mx2d_copy(tr_state->transform, mx_bck);
			compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d);
		}
	}
	if (stack->audio) svg_traverse_audio_ex(stack->audio, rs, GF_FALSE, tr_state->svg_props);

	memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
	tr_state->svg_flags = backup_flags;
}
Example #12
0
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;
}