Ejemplo n.º 1
0
void compositor_init_svg_font_face_uri(GF_Compositor *compositor, GF_Node *node)
{
	GF_Node *par;
	GF_Font *font;
	FontURIStack *stack;
	GF_Err e;
	SVGAllAttributes atts;

	/*check parent is a font-face-src*/
	par = gf_node_get_parent(node, 0);
	if (!par || (gf_node_get_tag(par)!=TAG_SVG_font_face_src)) return;
	/*check parent's parent is a font-face*/
	par = gf_node_get_parent(par, 0);
	if (!par || (gf_node_get_tag(par)!=TAG_SVG_font_face)) return;


	gf_svg_flatten_attributes((SVG_Element*)node, &atts);
	if (!atts.xlink_href) return;

	/*get font familly*/
	gf_svg_flatten_attributes((SVG_Element*)par, &atts);
	if (!atts.font_family) return;

	/*if font with the same name exists, don't load*/
	if (gf_compositor_svg_set_font(compositor->font_manager, atts.font_family->value, 0, 1) != NULL)
		return;

	/*register font to font manager*/
	GF_SAFEALLOC(font, GF_Font);
	e = gf_font_manager_register_font(compositor->font_manager, font);
	if (e) {
		gf_free(font);
		return;
	}
	GF_SAFEALLOC(stack, FontURIStack);
	stack->font = font;
	stack->compositor = compositor;

	font->ft_mgr = compositor->font_manager;

	font->get_glyphs = svg_font_uri_get_glyphs;
	font->load_glyph = svg_font_uri_load_glyph;
	font->get_alias = svg_font_uri_get_alias;
	font->udta = node;
	font->name = gf_strdup(atts.font_family->value);
	gf_node_set_private(node, stack);
	gf_node_set_callback_function(node, svg_traverse_font_face_uri);

	font->not_loaded = 1;
	compositor->fonts_pending++;
	svg_font_uri_check(node, stack);
}
Ejemplo n.º 2
0
static Bool svg_font_uri_check(GF_Node *node, FontURIStack *st)
{
	GF_Font *font;
	GF_Node *font_elt;
	SVGAllAttributes atts;
	gf_svg_flatten_attributes((SVG_Element*)node, &atts);
	if (!atts.xlink_href) return 0;

	if (atts.xlink_href->type == XMLRI_ELEMENTID) {
		if (!atts.xlink_href->target) atts.xlink_href->target = gf_sg_find_node_by_name(gf_node_get_graph(node), atts.xlink_href->string+1);
	} else {
		GF_SceneGraph *ext_sg;
		char *font_name = strchr(atts.xlink_href->string, '#');
		if (!font_name) return 0;
		if (!st->mo) {
			st->mo = gf_mo_load_xlink_resource(node, 0, 0, -1);
			if (!st->mo) return 0;
		}
		ext_sg = gf_mo_get_scenegraph(st->mo);
		if (!ext_sg) return 0;
		atts.xlink_href->target = gf_sg_find_node_by_name(ext_sg, font_name+1);
		if (!atts.xlink_href->target) return 0;
	}
	font_elt = atts.xlink_href->target;
	if (gf_node_get_tag(font_elt) != TAG_SVG_font) return 0; 
	font = gf_node_get_private(font_elt);
	if (!font) return 0;
	st->alias = font;

	gf_mo_is_done(st->mo);
	font->not_loaded = 0;
	return 1;
}
Ejemplo n.º 3
0
static void svg_animation_smil_update(GF_Node *node, SVGlinkStack *stack, Fixed normalized_scene_time)
{
	if (stack->init_vis_state == 3) {
		stack->init_vis_state = 4;
		gf_mo_resume(stack->resource);
	} else if (stack->needs_play || (gf_node_dirty_get(node) & GF_SG_SVG_XLINK_HREF_DIRTY )) {
		SVGAllAttributes all_atts;
		Double clipBegin, clipEnd;
		GF_MediaObject *new_res;
		gf_svg_flatten_attributes((SVG_Element *)node, &all_atts);
		clipBegin = all_atts.clipBegin ? *all_atts.clipBegin : 0;
		clipEnd = all_atts.clipEnd ? *all_atts.clipEnd : -1;

		if (stack->needs_play) {
			gf_mo_play(stack->resource, clipBegin, clipEnd, 0);
			stack->needs_play = 0;
		} else {            
            Bool primary = all_atts.gpac_useAsPrimary ? *all_atts.gpac_useAsPrimary : 1;
            new_res = gf_mo_load_xlink_resource(node, primary, clipBegin, clipEnd);
			if (new_res != stack->resource) {
				if (stack->resource) gf_mo_unload_xlink_resource(node, stack->resource);
				if (all_atts.xlink_href) all_atts.xlink_href->target = NULL;
				stack->resource = new_res;
				stack->fragment_id = NULL;
				stack->inline_sg = NULL;
			}
			gf_node_dirty_clear(node, 0);
		}
	}
}
Ejemplo n.º 4
0
static void svg_compute_text_width(GF_Node *node, SVGAllAttributes *atts, GF_TraverseState *tr_state )
{
	GF_ChildNodeItem *child;
	Bool is_switch = GF_FALSE;
	/*compute length of all text blocks*/
	switch  (gf_node_get_tag(node)) {
	case TAG_DOMText:
		get_domtext_width(node, atts, tr_state);
		break;
	case TAG_SVG_tspan:
		get_tspan_width(node, tr_state);
		break;
	case TAG_SVG_switch:
		is_switch = GF_TRUE;
	case TAG_SVG_a:
		child = ((GF_ParentNode *)node)->children;
		while (child) {
			if (is_switch) {
				SVGAllAttributes a_atts;
				gf_svg_flatten_attributes((SVG_Element*)child->node, &a_atts);
				if (compositor_svg_evaluate_conditional(tr_state->visual->compositor, &a_atts)) {
					svg_compute_text_width(child->node, atts, tr_state);
					break;
				}
			} else {
				svg_compute_text_width(child->node, atts, tr_state);
			}
			child = child->next;
		}
		break;
	default:
		break;
	}
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
static void svg_traverse_text_block(GF_Node *node, SVGAllAttributes *atts, GF_TraverseState *tr_state, GF_List *spans)
{
	GF_ChildNodeItem *child;
	Bool is_switch = GF_FALSE;
	switch  (gf_node_get_tag(node)) {
	case TAG_DOMText:
		svg_traverse_domtext(node, atts, tr_state, spans, NULL);
		break;
	case TAG_SVG_tspan:
		/*mark tspan as dirty to force rebuild*/
		gf_node_dirty_set(node, 0, GF_FALSE);
		gf_node_traverse(node, tr_state);
		break;
	case TAG_SVG_switch:
		is_switch = GF_TRUE;
	case TAG_SVG_a:
		child = ((GF_ParentNode *)node)->children;
		while (child) {
			if (is_switch) {
				SVGAllAttributes a_atts;
				gf_svg_flatten_attributes((SVG_Element*)child->node, &a_atts);
				if (compositor_svg_evaluate_conditional(tr_state->visual->compositor, &a_atts)) {
					svg_traverse_text_block(child->node, atts, tr_state, spans);
					break;
				}
			} else if (gf_node_get_tag(child->node)==TAG_DOMText) {
				svg_traverse_domtext(child->node, atts, tr_state, spans, node);
			}
			child = child->next;
		}
		break;
	default:
		break;
	}
}
Ejemplo n.º 7
0
static void svg_traverse_tbreak(GF_Node *node, void *rs, Bool is_destroy)
{
	SVGPropertiesPointers backup_props;
	u32 backup_flags;
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	SVGAllAttributes atts;

	if (is_destroy) return;
	if (tr_state->traversing_mode!=TRAVERSE_GET_BOUNDS) return;

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

	svg_text_area_reset_state(tr_state);
	/*beginning of a line, force a break of current fontSize*/
	if (!tr_state->text_end_x) {
		if (tr_state->svg_props->line_increment->type != SVG_NUMBER_AUTO) {
			tr_state->text_end_y += tr_state->svg_props->line_increment->value;
		} else {
			tr_state->text_end_y += tr_state->svg_props->font_size->value;
		}
	}
	tr_state->line_spacing = 0;
	tr_state->text_end_x = 0;
	tr_state->last_char_type = 0;

	memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
	tr_state->svg_flags = backup_flags;
}
Ejemplo n.º 8
0
static void svg_traverse_updates(GF_Node *node, void *rs, Bool is_destroy)
{
	/*video stack is just an extension of image stack, type-casting is OK*/
	SVG_updates_stack *stack = (SVG_updates_stack*)gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	SVGAllAttributes all_atts;
	SVGPropertiesPointers backup_props;
	u32 backup_flags, dirty_flags;

	if (is_destroy) {
		if (stack->resource) {
			if (stack->is_open) {
				gf_mo_set_flag(stack->resource, GF_MO_DISPLAY_REMOVE, GF_TRUE);
				gf_mo_stop(stack->resource);
			}
			gf_mo_unregister(node, stack->resource);
		}
		gf_free(stack);
		return;
	} 

	if (tr_state->traversing_mode!=TRAVERSE_SORT) 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;

	dirty_flags = gf_node_dirty_get(node);
	if (dirty_flags) {
		stack->clipBegin = all_atts.clipBegin ? *all_atts.clipBegin : 0;
		stack->clipEnd = all_atts.clipEnd ? *all_atts.clipEnd : -1;
		if (dirty_flags & GF_SG_SVG_XLINK_HREF_DIRTY) {
			GF_MediaObject *new_res;
			MFURL url;
			Bool lock_timeline=GF_FALSE;
			url.vals = NULL;
			url.count = 0;

			if (all_atts.syncBehavior) lock_timeline = (*all_atts.syncBehavior == SMIL_SYNCBEHAVIOR_LOCKED) ? GF_TRUE : GF_FALSE;

			gf_term_get_mfurl_from_xlink(node, &url);

			new_res = gf_mo_register(node, &url, lock_timeline, GF_FALSE);
			gf_sg_mfurl_del(url);
			
			if (stack->resource!=new_res) {
				if (stack->resource) {
					gf_mo_stop(stack->resource);
					gf_mo_unregister(node, stack->resource);
				}
				stack->resource = new_res;
				if (stack->resource && stack->is_open) gf_mo_play(stack->resource, stack->clipBegin, stack->clipEnd, GF_FALSE);
			}
		}
		gf_node_dirty_clear(node, 0);
	}
	memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
	tr_state->svg_flags = backup_flags;
}
Ejemplo n.º 9
0
static void get_tspan_width(GF_Node *node, void *rs)
{
	SVGPropertiesPointers backup_props;
	u32 backup_flags;
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	SVG_Element *tspan = (SVG_Element *)node;
	SVGAllAttributes atts;
	GF_ChildNodeItem *child;

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

	child = ((GF_ParentNode *) tspan)->children;
	while (child) {
		switch  (gf_node_get_tag(child->node)) {
		case TAG_DOMText:
			get_domtext_width(child->node, &atts, tr_state);
			break;
		case TAG_SVG_tspan:
			get_tspan_width(child->node, tr_state);
			break;
		default:
			break;
		}
		child=child->next;
	}

	memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
	tr_state->svg_flags = backup_flags;
}
Ejemplo n.º 10
0
static void svg_play_texture(SVG_video_stack *stack, SVGAllAttributes *atts)
{
	SVGAllAttributes all_atts;
	Bool lock_scene = GF_FALSE;
	if (stack->txh.is_open) gf_sc_texture_stop(&stack->txh);

	if (!atts) {
		gf_svg_flatten_attributes((SVG_Element*)stack->txh.owner, &all_atts);
		atts = &all_atts;
	}
	if (atts->syncBehavior) lock_scene = (*atts->syncBehavior == SMIL_SYNCBEHAVIOR_LOCKED) ? GF_TRUE : GF_FALSE;

	gf_sc_texture_play_from_to(&stack->txh, &stack->txurl, 
		atts->clipBegin ? (*atts->clipBegin) : 0.0,
		atts->clipEnd ? (*atts->clipEnd) : -1.0,
		GF_FALSE, 
		lock_scene);
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
GF_MediaObject *gf_mo_load_xlink_resource(GF_Node *node, Bool primary_resource, Double clipBegin, Double clipEnd)
{
	GF_Scene *new_resource;
	SVGAllAttributes all_atts;
	XLinkAttributesPointers xlinkp;
	SMILSyncAttributesPointers syncp;
	GF_Scene *scene = gf_sg_get_private(gf_node_get_graph(node));
	if (!scene) return NULL;

	gf_svg_flatten_attributes((SVG_Element *)node, &all_atts);
	xlinkp.actuate = all_atts.xlink_actuate;
	xlinkp.arcrole = all_atts.xlink_arcrole;
	xlinkp.href = all_atts.xlink_href;
	xlinkp.role = all_atts.xlink_role;
	xlinkp.show = all_atts.xlink_show;
	xlinkp.title = all_atts.xlink_title;
	xlinkp.type = all_atts.xlink_type;
	syncp.syncBehavior = all_atts.syncBehavior;
	syncp.syncBehaviorDefault = all_atts.syncBehaviorDefault;
	syncp.syncMaster = all_atts.syncMaster;
	syncp.syncReference = all_atts.syncReference;
	syncp.syncTolerance = all_atts.syncTolerance;
	syncp.syncToleranceDefault = all_atts.syncToleranceDefault;

	if (!xlinkp.href) return NULL;

	if (xlinkp.href->type == XMLRI_ELEMENTID) return NULL;
//	else if (xlinkp.href->string && (xlinkp.href->string[0]=='#')) return NULL;

	new_resource = gf_svg_get_subscene(node, &xlinkp, &syncp, primary_resource ? 1 : 0, primary_resource);
	if (!new_resource) return NULL;

	/*play*/
	gf_mo_play(new_resource->root_od->mo, 0, -1, 0);

	return new_resource->root_od->mo;
}
Ejemplo n.º 13
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;
}
Ejemplo n.º 14
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;
}
Ejemplo n.º 15
0
/*
	This is a crude draft implementation of filter. The main drawback is that we don't cache any data.
	We should be able to check for changes in the sub-group or in the filter
*/
void svg_draw_filter(GF_Node *filter, GF_Node *node, GF_TraverseState *tr_state)
{
	GF_IRect rc1, rc2;

#ifndef GPAC_DISABLE_3D
	u32 type_3d;
#endif
	u32 prev_flags;
	GF_IRect txrc;
	Fixed scale_x, scale_y, temp_x, temp_y;
	DrawableContext *ctx, *child_ctx;
	GF_SURFACE offscreen_surface, old_surf;
	GF_Rect bounds, local_bounds, rc;
	GF_Matrix2D backup;
	SVGAllAttributes all_atts;
	GF_FilterStack *st = gf_node_get_private(filter);
	assert(tr_state->traversing_mode==TRAVERSE_SORT);

	/*store the current transform matrix, create a new one for group_cache*/
	gf_mx2d_copy(backup, tr_state->transform);
	gf_mx2d_init(tr_state->transform);

	gf_node_allow_cyclic_traverse(node);
	tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
	tr_state->bounds.width = tr_state->bounds.height = 0;
	gf_node_traverse(node, tr_state);

	local_bounds = bounds = tr_state->bounds;
	/*compute bounds in final coordinate system - this ensures that the cache has the correct anti aliasing*/
	gf_mx2d_apply_rect(&backup, &bounds);
	txrc = gf_rect_pixelize(&bounds);
	if (txrc.width%2) txrc.width++;
	if (txrc.height%2) txrc.height++;
	bounds = gf_rect_ft(&txrc);

	tr_state->traversing_mode = TRAVERSE_SORT;

	gf_mx2d_copy(tr_state->transform, backup);

	if (!bounds.width || !bounds.height) {
		return;
	}

	/*create a context */
	ctx = drawable_init_context_svg(st->drawable, tr_state);
	if (!ctx) return;

	/*setup texture */
	st->txh.height = txrc.height;
	st->txh.width = txrc.width;

	st->txh.stride = txrc.width * 4;
	st->txh.pixelformat = GF_PIXEL_ARGB;
#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) st->txh.pixelformat = GF_PIXEL_RGBA;
#endif
	st->txh.transparent = 1;

	if (st->txh.stride * st->txh.height > st->alloc_size) {
		st->alloc_size = st->txh.stride * st->txh.height;
		st->data = (u8*)gf_realloc(st->data, sizeof(u8) * st->alloc_size);
	}
	memset(st->data, 0x0, sizeof(char) * st->txh.stride * st->txh.height);
	st->txh.data = (char *) st->data;
	/*setup geometry (rectangle matching the bounds of the object)
	Warning, we want to center the cached bitmap at the center of the screen (main visual)*/
	gf_path_reset(st->drawable->path);

	gf_path_add_rect_center(st->drawable->path,
	                        bounds.x + bounds.width/2,
	                        bounds.y - bounds.height/2,
	                        bounds.width,
	                        bounds.height);


	old_surf = tr_state->visual->raster_surface;
	offscreen_surface = tr_state->visual->compositor->rasterizer->surface_new(tr_state->visual->compositor->rasterizer, tr_state->visual->center_coords);
	tr_state->visual->raster_surface = offscreen_surface;

	gf_mx2d_copy(backup, tr_state->transform);
	gf_mx2d_init(tr_state->transform);

	/*attach the buffer to visual*/
	tr_state->visual->compositor->rasterizer->surface_attach_to_buffer(offscreen_surface, st->txh.data,
	        st->txh.width,
	        st->txh.height,
	        0,
	        st->txh.stride,
	        st->txh.pixelformat);

	prev_flags = tr_state->immediate_draw;
	tr_state->immediate_draw = 1;
	tr_state->traversing_mode = TRAVERSE_SORT;
	tr_state->in_svg_filter = 1;

	/*recompute the bounds with the final scaling used*/
	scale_x = gf_divfix(bounds.width, local_bounds.width);
	scale_y = gf_divfix(bounds.height, local_bounds.height);
	gf_mx2d_init(tr_state->transform);
	gf_mx2d_add_scale(&tr_state->transform, scale_x, scale_y);

	rc = local_bounds;
	gf_mx2d_apply_rect(&tr_state->transform, &rc);

	/*centered the bitmap on the visual*/
	if (tr_state->visual->center_coords) {
		temp_x = -rc.x - rc.width/2;
		temp_y = rc.height/2 - rc.y;
	} else {
		temp_x = -rc.x;
		temp_y = rc.height - rc.y;
	}
	gf_mx2d_add_translation(&tr_state->transform, temp_x, temp_y);


	rc1 = tr_state->visual->surf_rect;
	rc2 = tr_state->visual->top_clipper;
	tr_state->visual->surf_rect.width = st->txh.width;
	tr_state->visual->surf_rect.height = st->txh.height;
	if (tr_state->visual->center_coords) {
		tr_state->visual->surf_rect.y = st->txh.height/2;
		tr_state->visual->surf_rect.x = -1 * (s32) st->txh.width/2;
	} else {
		tr_state->visual->surf_rect.y = st->txh.height;
		tr_state->visual->surf_rect.x = 0;
	}
	tr_state->visual->top_clipper = tr_state->visual->surf_rect;


#ifndef GPAC_DISABLE_3D
	type_3d = tr_state->visual->type_3d;
	tr_state->visual->type_3d=0;
#endif

	if (prev_flags) gf_node_allow_cyclic_traverse(node);
	gf_node_traverse(node, tr_state);

	child_ctx = ctx->next;
	while (child_ctx && child_ctx->drawable) {
		drawable_reset_bounds(child_ctx->drawable, tr_state->visual);
		child_ctx->drawable = NULL;
		child_ctx = child_ctx->next;
	}
	tr_state->visual->cur_context = ctx;


	/*restore state and destroy whatever needs to be cleaned*/
	tr_state->in_svg_filter = 0;
	tr_state->immediate_draw = prev_flags;
	tr_state->visual->compositor->rasterizer->surface_delete(offscreen_surface);
	tr_state->visual->raster_surface = old_surf;
	tr_state->traversing_mode = TRAVERSE_SORT;
	tr_state->visual->surf_rect = rc1;
	tr_state->visual->top_clipper = rc2;
#ifndef GPAC_DISABLE_3D
	tr_state->visual->type_3d = type_3d ;
#endif

	/*update texture*/
	st->txh.transparent = 1;
	st->txh.flags |= GF_SR_TEXTURE_NO_GL_FLIP;
	gf_sc_texture_set_data(&st->txh);
#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d)
		gf_sc_texture_push_image(&st->txh, 0, 0);
	else
#endif
		gf_sc_texture_push_image(&st->txh, 0, 1);

	ctx->flags |= CTX_NO_ANTIALIAS;
	ctx->aspect.fill_color = 0;
	ctx->aspect.line_color = 0xFF000000;
	ctx->aspect.fill_texture = &st->txh;
	ctx->flags |= CTX_TEXTURE_DIRTY;

	/*get the filter region*/
	bounds = local_bounds;
	gf_svg_flatten_attributes((SVG_Element *)filter, &all_atts);
	if (!all_atts.filterUnits || (*all_atts.filterUnits==SVG_GRADIENTUNITS_OBJECT)) {
		Fixed v;
		v = all_atts.x ? all_atts.x->value : INT2FIX(-10);
		bounds.x += gf_mulfix(v, bounds.width);
		v = all_atts.y ? all_atts.y->value : INT2FIX(-10);
		bounds.y += gf_mulfix(v, bounds.height);
		v = all_atts.width ? all_atts.width->value : INT2FIX(120);
		bounds.width = gf_mulfix(v, bounds.width);
		v = all_atts.height ? all_atts.height->value : INT2FIX(120);
		bounds.height = gf_mulfix(v, bounds.height);
	} else {
		bounds.x = all_atts.x ? all_atts.x->value : 0;
		bounds.y = all_atts.y ? all_atts.y->value : 0;
		bounds.width = all_atts.width ? all_atts.x->value : bounds.width;
		bounds.height = all_atts.x ? all_atts.x->value : 120;
	}
	gf_mx2d_apply_rect(&backup, &bounds);

	svg_filter_apply(filter, &st->txh, &bounds);


#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) {
		if (!st->drawable->mesh) {
			st->drawable->mesh = new_mesh();
			mesh_from_path(st->drawable->mesh, st->drawable->path);
		}
		visual_3d_draw_from_context(tr_state->ctx, tr_state);
		ctx->drawable = NULL;
		return;
	}
#endif

	/*we computed the texture in final screen coordinate, so use the identity matrix for the context*/
	gf_mx2d_init(tr_state->transform);
	drawable_finalize_sort(ctx, tr_state, NULL);
	gf_mx2d_copy(tr_state->transform, backup);
}
Ejemplo n.º 16
0
GF_EXPORT
void gf_smil_timing_init_runtime_info(GF_Node *timed_elt)
{
	s32 interval_index;
	GF_SceneGraph *sg;
	SMIL_Timing_RTI *rti;
	SMILTimingAttributesPointers *timingp = NULL;
	u32 tag = gf_node_get_tag(timed_elt);

	if ((tag>=GF_NODE_RANGE_FIRST_SVG) && (tag<=GF_NODE_RANGE_LAST_SVG)) {
		SVGAllAttributes all_atts;
		SVGTimedAnimBaseElement *e = (SVGTimedAnimBaseElement *)timed_elt;
		gf_svg_flatten_attributes((SVG_Element *)e, &all_atts);
		e->timingp = malloc(sizeof(SMILTimingAttributesPointers));
		e->timingp->begin		= all_atts.begin;
		e->timingp->clipBegin	= all_atts.clipBegin;
		e->timingp->clipEnd		= all_atts.clipEnd;
		e->timingp->dur			= all_atts.dur;
		e->timingp->end			= all_atts.end;
		e->timingp->fill		= all_atts.smil_fill;
		e->timingp->max			= all_atts.max;
		e->timingp->min			= all_atts.min;
		e->timingp->repeatCount = all_atts.repeatCount;
		e->timingp->repeatDur	= all_atts.repeatDur;
		e->timingp->restart		= all_atts.restart;
		timingp = e->timingp;
	} 
#ifdef GPAC_ENABLE_SVG_SA
	else if ((tag>=GF_NODE_RANGE_FIRST_SVG_SA) && (tag<=GF_NODE_RANGE_LAST_SVG_SA)) {
		SVG_SA_Element *e = (SVG_SA_Element *)timed_elt;
		e->timingp = malloc(sizeof(SMILTimingAttributesPointers));
		e->timingp->begin		= &e->timing->begin;
		e->timingp->clipBegin	= &e->timing->clipBegin;
		e->timingp->clipEnd		= &e->timing->clipEnd;
		e->timingp->dur			= &e->timing->dur;
		e->timingp->end			= &e->timing->end;
		e->timingp->fill		= &e->timing->fill;
		e->timingp->max			= &e->timing->max;
		e->timingp->min			= &e->timing->min;
		e->timingp->repeatCount = &e->timing->repeatCount;
		e->timingp->repeatDur	= &e->timing->repeatDur;
		e->timingp->restart		= &e->timing->restart;
		timingp = e->timingp;
	}
#endif
#ifdef GPAC_ENABLE_SVG_SANI
	else if ((tag>=GF_NODE_RANGE_FIRST_SVG_SANI) && (tag<=GF_NODE_RANGE_LAST_SVG_SANI)) {
		SVG_SANI_Element *e = (SVG_SANI_Element *)timed_elt;
		e->timingp = malloc(sizeof(SMILTimingAttributesPointers));
		e->timingp->begin		= &e->timing->begin;
		e->timingp->clipBegin	= &e->timing->clipBegin;
		e->timingp->clipEnd		= &e->timing->clipEnd;
		e->timingp->dur			= &e->timing->dur;
		e->timingp->end			= &e->timing->end;
		e->timingp->fill		= &e->timing->fill;
		e->timingp->max			= &e->timing->max;
		e->timingp->min			= &e->timing->min;
		e->timingp->repeatCount = &e->timing->repeatCount;
		e->timingp->repeatDur	= &e->timing->repeatDur;
		e->timingp->restart		= &e->timing->restart;
		timingp = e->timingp;
	}
#endif
	else {
		return;
	}

	if (!timingp) return;

	GF_SAFEALLOC(rti, SMIL_Timing_RTI)
	timingp->runtime = rti;
	rti->timed_elt = timed_elt;
	rti->timingp = timingp;
	rti->status = SMIL_STATUS_WAITING_TO_BEGIN;
	rti->evaluate_status = SMIL_TIMING_EVAL_NONE;	
	rti->intervals = gf_list_new();
	rti->current_interval = NULL;
	rti->evaluate = gf_smil_timing_null_timed_function;
	rti->scene_time = -1;
	rti->media_duration = -1;

	gf_smil_timing_init_interval_list(rti);
	interval_index = gf_smil_timing_find_interval_index(rti, GF_MAX_DOUBLE);
	if (interval_index >= 0) {
		rti->current_interval_index = interval_index;
		rti->current_interval = (SMIL_Interval*)gf_list_get(rti->intervals, rti->current_interval_index);
	} 

	sg = timed_elt->sgprivate->scenegraph;
	while (sg->parent_scene) sg = sg->parent_scene;
	gf_smil_timing_add_to_sg(sg, rti);
}
Ejemplo n.º 17
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;
}
Ejemplo n.º 18
0
void compositor_init_svg_font(GF_Compositor *compositor, GF_Node *node)
{
	SVG_handlerElement *handler;
	GF_Err e;
	SVGAllAttributes atts;
	GF_Font *font;
	GF_Node *node_font = gf_node_get_parent(node, 0);
	if (!node_font) return;

	if (gf_node_get_tag(node_font)!=TAG_SVG_font) return;

	gf_svg_flatten_attributes((SVG_Element*)node, &atts);
	if (!atts.font_family) return;

	/*register font to font manager*/
	GF_SAFEALLOC(font, GF_Font);
	e = gf_font_manager_register_font(compositor->font_manager, font);
	if (e) {
		gf_free(font);
		return;
	}
	font->ft_mgr = compositor->font_manager;

	font->get_glyphs = svg_font_get_glyphs;
	font->load_glyph = svg_font_load_glyph;
	font->udta = node_font;
	gf_node_set_private(node_font, font);
	gf_node_set_callback_function(node_font, svg_traverse_font);
	font->name = gf_strdup(atts.font_family->value);

	font->em_size = atts.units_per_em ? FIX2INT( gf_ceil(atts.units_per_em->value) ) : 1000;
	/*Inconsistency between SVG 1.2 and 1.1
		when not specify, ascent and descent are computed based on font.vert-origin-y, WHICH DOES NOT EXIST
	IN Tiny 1.2 !!! We assume it to be 0.
	*/
	font->ascent = atts.ascent ? FIX2INT( gf_ceil(atts.ascent->value) ) : 0;
	if (!font->ascent) font->ascent = font->em_size;
	font->descent = atts.descent ? FIX2INT( gf_ceil(atts.descent->value) ) : 0;
	font->baseline = atts.alphabetic ? FIX2INT( gf_ceil(atts.alphabetic->value) ) : 0;
	font->line_spacing = font->em_size;
	font->styles = 0;
	if (atts.font_style) {
		switch (*atts.font_style) {
		case SVG_FONTSTYLE_ITALIC:
			font->styles |= GF_FONT_ITALIC;
			break;
		case SVG_FONTSTYLE_OBLIQUE:
			font->styles |= GF_FONT_OBLIQUE;
			break;
		}
	}
	if (atts.font_variant && (*atts.font_variant ==SVG_FONTVARIANT_SMALLCAPS))
		font->styles |= GF_FONT_SMALLCAPS;

	if (atts.font_weight) {
		switch(*atts.font_weight) {
		case SVG_FONTWEIGHT_100: font->styles |= GF_FONT_WEIGHT_100; break;
		case SVG_FONTWEIGHT_LIGHTER: font->styles |= GF_FONT_WEIGHT_LIGHTER; break;
		case SVG_FONTWEIGHT_200: font->styles |= GF_FONT_WEIGHT_200; break;
		case SVG_FONTWEIGHT_300: font->styles |= GF_FONT_WEIGHT_300; break;
		case SVG_FONTWEIGHT_400: font->styles |= GF_FONT_WEIGHT_400; break;
		case SVG_FONTWEIGHT_NORMAL: font->styles |= GF_FONT_WEIGHT_NORMAL; break;
		case SVG_FONTWEIGHT_500: font->styles |= GF_FONT_WEIGHT_500; break;
		case SVG_FONTWEIGHT_600: font->styles |= GF_FONT_WEIGHT_600; break;
		case SVG_FONTWEIGHT_700: font->styles |= GF_FONT_WEIGHT_700; break;
		case SVG_FONTWEIGHT_BOLD: font->styles |= GF_FONT_WEIGHT_BOLD; break;
		case SVG_FONTWEIGHT_800: font->styles |= GF_FONT_WEIGHT_800; break;
		case SVG_FONTWEIGHT_900: font->styles |= GF_FONT_WEIGHT_900; break;
		case SVG_FONTWEIGHT_BOLDER: font->styles |= GF_FONT_WEIGHT_BOLDER; break;
		}
	}

	gf_svg_flatten_attributes((SVG_Element*)node_font, &atts);
	font->max_advance_h = atts.horiz_adv_x ? FIX2INT( gf_ceil(atts.horiz_adv_x->value) ) : 0;
	
	font->not_loaded = 1;

	/*wait for onLoad event before activating the font, otherwise we may not have all the glyphs*/
	handler = gf_dom_listener_build(node_font, GF_EVENT_LOAD, 0);
	handler->handle_event = svg_font_on_load;
	gf_node_set_private((GF_Node *)handler, compositor);
}
Ejemplo n.º 19
0
static void svg2bifs_node_start(void *sax_cbck, const char *name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes)
{
	u32 i;
	SVG_SANI_BIFS_Converter *converter = (SVG_SANI_BIFS_Converter *)sax_cbck;
	SVGPropertiesPointers *backup_props;
	char *id_string = NULL;

	u32	tag = gf_svg_get_element_tag(name);
	SVG_Element *elt = (SVG_Element*)gf_node_new(converter->svg_sg, tag);
	if (!gf_sg_get_root_node(converter->svg_sg)) {
		gf_node_register((GF_Node *)elt, NULL);
		gf_sg_set_root_node(converter->svg_sg, (GF_Node *)elt);
	} else {
		gf_node_register((GF_Node *)elt, converter->svg_parent);	
		//gf_node_list_add_child(&((GF_ParentNode*)converter->svg_parent)->children, (GF_Node *)elt);
	}
	converter->svg_parent = (GF_Node *)elt;
	
//	fprintf(stdout, "Converting %s\n", gf_node_get_class_name((GF_Node *)elt));
//	if (converter->bifs_parent) fprintf(stdout, "%s\n", gf_node_get_class_name(converter->bifs_parent));

	for (i=0; i<nb_attributes; i++) {
		GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
		if (!att->value || !strlen(att->value)) continue;

		if (!stricmp(att->name, "style")) {
			gf_svg_parse_style((GF_Node *)elt, att->value);
		} else if (!stricmp(att->name, "id") || !stricmp(att->name, "xml:id")) {
			gf_svg_parse_element_id((GF_Node *)elt, att->value, 0);
			id_string = att->value;
		} else {
			GF_FieldInfo info;
			if (gf_node_get_field_by_name((GF_Node *)elt, att->name, &info)==GF_OK) {
				gf_svg_parse_attribute((GF_Node *)elt, &info, att->value, 0);
			} else {
				fprintf(stdout, "Skipping attribute %s\n", att->name);
			}
		}
	}

	memset(&converter->all_atts, 0, sizeof(SVGAllAttributes));
	gf_svg_flatten_attributes(elt, &converter->all_atts);
	
	backup_props = gf_malloc(sizeof(SVGPropertiesPointers));
	memcpy(backup_props, &converter->svg_props, sizeof(SVGPropertiesPointers));
	gf_node_set_private((GF_Node *)elt, backup_props);

	gf_svg_apply_inheritance(&converter->all_atts, &converter->svg_props);

	if (!gf_sg_get_root_node(converter->bifs_sg)) {
		if (tag == TAG_SVG_svg) {
			GF_Node *node, *child;

			converter->bifs_sg->usePixelMetrics = 1;
			if (converter->all_atts.width && converter->all_atts.width->type == SVG_NUMBER_VALUE) {
				converter->bifs_sg->width = FIX2INT(converter->all_atts.width->value);
			} else {
				converter->bifs_sg->width = 320;
			}
			if (converter->all_atts.height && converter->all_atts.height->type == SVG_NUMBER_VALUE) {
				converter->bifs_sg->height = FIX2INT(converter->all_atts.height->value);
			} else {
				converter->bifs_sg->height = 200;
			}

			node = gf_node_new(converter->bifs_sg, TAG_MPEG4_OrderedGroup);
			gf_node_register(node, NULL);
			gf_sg_set_root_node(converter->bifs_sg, node);

			/* SVG to BIFS coordinate transformation */
			child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Viewport);
			gf_node_register(child, node);
			gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
			if (converter->all_atts.viewBox) {
				M_Viewport *vp = (M_Viewport*)child;
				vp->size.x = converter->all_atts.viewBox->width;
				vp->size.y = converter->all_atts.viewBox->height;
				vp->position.x = converter->all_atts.viewBox->x+converter->all_atts.viewBox->width/2;
				vp->position.y = -(converter->all_atts.viewBox->y+converter->all_atts.viewBox->height/2);
			} else {
				M_Viewport *vp = (M_Viewport*)child;
				vp->size.x = INT2FIX(converter->bifs_sg->width);
				vp->size.y = INT2FIX(converter->bifs_sg->height);
				vp->position.x = INT2FIX(converter->bifs_sg->width)/2;
				vp->position.y = -INT2FIX(converter->bifs_sg->height)/2;
			}

			child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Background2D);
			gf_node_register(child, node);
			gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
			{
				M_Background2D *b = (M_Background2D *)child;
				b->backColor.red = FIX_ONE;
				b->backColor.green = FIX_ONE;				
				b->backColor.blue = FIX_ONE;
			}

			child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D);
			gf_node_register(child, node);
			gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
			node = child;
			child = NULL;
			{
				M_Transform2D *tr = (M_Transform2D *)node;
				tr->scale.y = -FIX_ONE;
			}
			converter->bifs_parent = node;
		}
	} else {
		GF_Node *node, *child;
		
		node = converter->bifs_parent;

		switch(tag) {
		case TAG_SVG_g:
			{
				if (converter->all_atts.transform) {
					node = add_transform(converter, node);
					converter->bifs_parent = node;
				} else {
					M_Group *g = (M_Group*)gf_node_new(converter->bifs_sg, TAG_MPEG4_Group);
					gf_node_register((GF_Node *)g, node);
					gf_node_list_add_child(&((GF_ParentNode*)node)->children, (GF_Node *)g);
					node = (GF_Node *)g;
					converter->bifs_parent = node;
				}
			}
			break;
		case TAG_SVG_rect:
			{
				Bool is_parent_set = 0;
				if (converter->all_atts.transform) {
					node = add_transform(converter, node);
					converter->bifs_parent = node;
					is_parent_set = 1;
				} 
				if (converter->all_atts.x || converter->all_atts.y) {
					child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D);
					gf_node_register(child, node);
					gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
					node = child;
					child = NULL;
					if (!is_parent_set) {
						converter->bifs_parent = node;
						is_parent_set = 1;
					}
					{
						M_Transform2D *tr = (M_Transform2D *)node;
						if (converter->all_atts.x) tr->translation.x = converter->all_atts.x->value + (converter->all_atts.width?converter->all_atts.width->value/2:0);
						if (converter->all_atts.y) tr->translation.y = converter->all_atts.y->value + (converter->all_atts.height?converter->all_atts.height->value/2:0);
					}
				} 
				child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape);
				gf_node_register(child, node);
				gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
				node = child;
				child = NULL;
				if (!is_parent_set) converter->bifs_parent = node;
				{
					M_Shape *shape = (M_Shape *)node;
					shape->geometry = gf_node_new(converter->bifs_sg, TAG_MPEG4_Rectangle);
					gf_node_register(shape->geometry, (GF_Node *)shape);
					{
						M_Rectangle *rect = (M_Rectangle *)shape->geometry;
						if (converter->all_atts.width) rect->size.x = converter->all_atts.width->value;
						if (converter->all_atts.height) rect->size.y = converter->all_atts.height->value;					
					}			
					
					shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg);
					gf_node_register(shape->appearance, (GF_Node *)shape);
				}
			}
			break;
		case TAG_SVG_path:
			{
				Bool is_parent_set = 0;
				if (converter->all_atts.transform) {
					node = add_transform(converter, node);
					converter->bifs_parent = node;
					is_parent_set = 1;
				} 
				if (converter->all_atts.x || converter->all_atts.y) {
					child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D);
					gf_node_register(child, node);
					gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
					node = child;
					child = NULL;
					if (!is_parent_set) {
						converter->bifs_parent = node;
						is_parent_set = 1;
					}
					{
						M_Transform2D *tr = (M_Transform2D *)node;
						if (converter->all_atts.x) tr->translation.x = converter->all_atts.x->value;
						if (converter->all_atts.y) tr->translation.y = converter->all_atts.y->value;
					}
				} 
				child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape);
				gf_node_register(child, node);
				gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
				node = child;
				child = NULL;
				if (!is_parent_set) converter->bifs_parent = node;
				{
					M_Shape *shape = (M_Shape *)node;
					shape->geometry = gf_node_new(converter->bifs_sg, TAG_MPEG4_XCurve2D);
					gf_node_register(shape->geometry, (GF_Node *)shape);
					if (converter->all_atts.d) {
						M_Coordinate2D *c2d;
						M_XCurve2D *xc = (M_XCurve2D *)shape->geometry;
						u32 i, j, c;

						xc->point = gf_node_new(converter->bifs_sg, TAG_MPEG4_Coordinate2D);
						c2d = (M_Coordinate2D *)xc->point;
						gf_node_register(xc->point, (GF_Node *)xc);
						
						gf_sg_vrml_mf_alloc(&c2d->point, GF_SG_VRML_MFVEC2F, converter->all_atts.d->n_points);
						j= 0;
						for (i = 0; i < converter->all_atts.d->n_points; i++) {
							if (converter->all_atts.d->tags[i] != GF_PATH_CLOSE || i == converter->all_atts.d->n_points-1) {
								c2d->point.vals[j] = converter->all_atts.d->points[i];
								j++;
							}
						}
						c2d->point.count = j;

						gf_sg_vrml_mf_alloc(&xc->type, GF_SG_VRML_MFINT32, converter->all_atts.d->n_points);
						c = 0;
						j = 0;
						xc->type.vals[0] = 0;
						for (i = 1; i < converter->all_atts.d->n_points; i++) {
							switch(converter->all_atts.d->tags[i]) {
							case GF_PATH_CURVE_ON:
								if (c < converter->all_atts.d->n_contours &&
									i-1 == converter->all_atts.d->contours[c]) {
									xc->type.vals[j] = 0;
									c++;
								} else {
									xc->type.vals[j] = 1;
								}
								break;
							case GF_PATH_CURVE_CUBIC:
								xc->type.vals[j] = 2;
								i+=2;
								break;
							case GF_PATH_CLOSE:
								xc->type.vals[j] = 6;
								break;
							case GF_PATH_CURVE_CONIC:
								xc->type.vals[j] = 7;
								i++;
								break;
							}
							j++;
						}
						xc->type.count = j;
					}			
					
					shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg);
					gf_node_register(shape->appearance, (GF_Node *)shape);
				}
			}
			break;
		case TAG_SVG_polyline:
			{
				Bool is_parent_set = 0;
				if (converter->all_atts.transform) {
					node = add_transform(converter, node);
					converter->bifs_parent = node;
					is_parent_set = 1;
				} 

				child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape);
				gf_node_register(child, node);
				gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
				node = child;
				child = NULL;
				if (!is_parent_set) converter->bifs_parent = node;
				{
					M_Shape *shape = (M_Shape *)node;
					shape->geometry = gf_node_new(converter->bifs_sg, TAG_MPEG4_IndexedFaceSet2D);
					gf_node_register(shape->geometry, (GF_Node *)shape);
					if (converter->all_atts.points) {
						M_Coordinate2D *c2d;
						M_IndexedFaceSet2D *ifs = (M_IndexedFaceSet2D *)shape->geometry;
						u32 i;

						ifs->coord = gf_node_new(converter->bifs_sg, TAG_MPEG4_Coordinate2D);
						c2d = (M_Coordinate2D *)ifs->coord;
						gf_node_register(ifs->coord, (GF_Node *)ifs);
						
						gf_sg_vrml_mf_alloc(&c2d->point, GF_SG_VRML_MFVEC2F, gf_list_count(*converter->all_atts.points));
						for (i = 0; i < gf_list_count(*converter->all_atts.points); i++) {
							SVG_Point *p = (SVG_Point *)gf_list_get(*converter->all_atts.points, i);
							c2d->point.vals[i].x = p->x;
							c2d->point.vals[i].y = p->y;
						}						
					}			
					
					shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg);
					gf_node_register(shape->appearance, (GF_Node *)shape);
				}
			}
			break;
		case TAG_SVG_text:
			{
				Bool is_parent_set = 0;
				if (converter->all_atts.transform) {
					node = add_transform(converter, node);
					converter->bifs_parent = node;
					is_parent_set = 1;
				}

				child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D);
				gf_node_register(child, node);
				gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
				{
					M_Transform2D *tr = (M_Transform2D *)child;
					if (converter->all_atts.text_x) tr->translation.x = ((SVG_Coordinate *)gf_list_get(*converter->all_atts.text_x, 0))->value;
					if (converter->all_atts.text_y) tr->translation.y = ((SVG_Coordinate *)gf_list_get(*converter->all_atts.text_y, 0))->value;
					tr->scale.y = -FIX_ONE;
				}
				node = child;
				child = NULL;
				if (!is_parent_set) {
					converter->bifs_parent = node;
					is_parent_set = 1;
				}

				child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape);
				gf_node_register(child, node);
				gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
				node = child;
				child = NULL;
				if (!is_parent_set) converter->bifs_parent = node;
				{
					M_FontStyle *fs;
					M_Text *text; 
					M_Shape *shape = (M_Shape *)node;
					text = (M_Text *)gf_node_new(converter->bifs_sg, TAG_MPEG4_Text);
					shape->geometry = (GF_Node *)text;
					converter->bifs_text_node = shape->geometry;
					gf_node_register(shape->geometry, (GF_Node *)shape);
					
					fs = (M_FontStyle *)gf_node_new(converter->bifs_sg, TAG_MPEG4_XFontStyle);
					gf_node_register((GF_Node *)fs, (GF_Node*)text);
					text->fontStyle = (GF_Node *)fs;

					gf_sg_vrml_mf_alloc(&fs->family, GF_SG_VRML_MFSTRING, 1);				
					fs->family.vals[0] = strdup(converter->svg_props.font_family->value);				
					fs->size = converter->svg_props.font_size->value;

					shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg);
					gf_node_register(shape->appearance, (GF_Node *)shape);
				}
			}
			break;
		case TAG_SVG_ellipse:
		case TAG_SVG_circle:
			{
				Bool is_parent_set = 0;
				if (converter->all_atts.transform) {
					node = add_transform(converter, node);
					converter->bifs_parent = node;
					is_parent_set = 1;
				}
				if (converter->all_atts.cx || converter->all_atts.cy) {
					child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D);
					gf_node_register(child, node);
					gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
					{
						M_Transform2D *tr = (M_Transform2D *)child;
						if (converter->all_atts.cx) tr->translation.x = converter->all_atts.cx->value;
						if (converter->all_atts.cy) tr->translation.y = converter->all_atts.cy->value;
					}
					node = child;
					child = NULL;
					if (!is_parent_set) {
						converter->bifs_parent = node;
						is_parent_set = 1;
					}
				} 
				child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape);
				gf_node_register(child, node);
				gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
				node = child;
				child = NULL;
				if (!is_parent_set) converter->bifs_parent = node;
				{
					M_Shape *shape = (M_Shape *)node;
					if (tag == TAG_SVG_ellipse) {
						M_Ellipse *e = (M_Ellipse *)gf_node_new(converter->bifs_sg, TAG_MPEG4_Ellipse);
						shape->geometry = (GF_Node *)e;
						e->radius.x = converter->all_atts.rx->value;
						e->radius.y = converter->all_atts.ry->value;
					} else {
						M_Circle *c = (M_Circle *)gf_node_new(converter->bifs_sg, TAG_MPEG4_Circle);
						shape->geometry = (GF_Node *)c;
						c->radius = converter->all_atts.r->value;
					}
					gf_node_register(shape->geometry, (GF_Node *)shape);
					
					shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg);
					gf_node_register(shape->appearance, (GF_Node *)shape);
				}
			}
			break;

		case TAG_SVG_defs:
			{
				child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Switch);
				gf_node_register(child, node);
				gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
				node = child;
				child = NULL;
				{
					M_Switch *sw = (M_Switch *)node;
					sw->whichChoice = -1;
				}
				converter->bifs_parent = node;
			}
			break;
		case TAG_SVG_solidColor:
			{
				child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape);
				gf_node_register(child, node);
				gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
				node = child;
				child = NULL;
				converter->bifs_parent = node;
			}
			break;
		default:
			{
				fprintf(stdout, "Warning: element %s not supported \n", gf_node_get_class_name((GF_Node *)elt));
				child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D);
				gf_node_register(child, node);
				gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
				node = child;
				child = NULL;
				converter->bifs_parent = node;
			}
			break;
		}

		if (id_string) 
			gf_node_set_id(converter->bifs_parent, gf_node_get_id((GF_Node *)elt), gf_node_get_name((GF_Node *)elt));
	}
}
Ejemplo n.º 20
0
static void SVG_Build_Bitmap_Graph(SVG_video_stack *stack, GF_TraverseState *tr_state)
{
	u32 tag;
	GF_Rect rc, new_rc;
	Fixed x, y, width, height, txwidth, txheight;
	Fixed rectx, recty, rectwidth, rectheight;
	SVGAllAttributes atts;
	SVG_PreserveAspectRatio pAR;
	SVG_Element *e = (SVG_Element *)stack->graph->node;

	gf_svg_flatten_attributes(e, &atts);
	
	tag = gf_node_get_tag(stack->graph->node);
	switch (tag) {
	case TAG_SVG_image:
	case TAG_SVG_video:
		x = (atts.x ? atts.x->value : 0);
		y = (atts.y ? atts.y->value : 0);
		width = (atts.width ? atts.width->value : 0);
		height = (atts.height ? atts.height->value : 0);
		break;
	default:
		return;
	}

	if (!width || !height) return;
	
	txheight = INT2FIX(stack->txh.height);
	txwidth = INT2FIX(stack->txh.width);

	if (!txwidth || !txheight) return;

	if (!atts.preserveAspectRatio) {
		pAR.defer = GF_FALSE;
		pAR.meetOrSlice = SVG_MEETORSLICE_MEET;
		pAR.align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
	} else {
		pAR = *atts.preserveAspectRatio;
	}
	if (pAR.defer) {
		/* TODO */
		rectwidth = width;
		rectheight = height;
		rectx = x+rectwidth/2;
		recty = y+rectheight/2;
	} else {

		if (pAR.align==SVG_PRESERVEASPECTRATIO_NONE) {
			rectwidth = width;
			rectheight = height;				
			rectx = x+rectwidth/2;
			recty = y+rectheight/2;
		} else {
			Fixed scale, scale_w, scale_h;
			scale_w = gf_divfix(width, txwidth);
			scale_h = gf_divfix(height, txheight);
			if (pAR.meetOrSlice==SVG_MEETORSLICE_MEET) {
				if (scale_w > scale_h) {
					scale = scale_h;
					rectwidth = gf_mulfix(txwidth, scale);
					rectheight = height;
				} else {
					scale = scale_w;
					rectwidth = width;
					rectheight = gf_mulfix(txheight, scale);
				}
			} else {
				if (scale_w < scale_h) {
					scale = scale_h;
					rectwidth = gf_mulfix(txwidth, scale);
					rectheight = height;
				} else {
					scale = scale_w;
					rectwidth = width;
					rectheight = gf_mulfix(txheight, scale);
				}
			}

			rectx = x + rectwidth/2;
			recty = y + rectheight/2;
			switch (pAR.align) {
			case SVG_PRESERVEASPECTRATIO_XMINYMIN:
				break;
			case SVG_PRESERVEASPECTRATIO_XMIDYMIN:
				rectx += (width - rectwidth)/ 2; 
				break;
			case SVG_PRESERVEASPECTRATIO_XMAXYMIN:
				rectx += width - rectwidth; 
				break;
			case SVG_PRESERVEASPECTRATIO_XMINYMID:
				recty += (height - rectheight)/ 2; 
				break;
			case SVG_PRESERVEASPECTRATIO_XMIDYMID:
				rectx += (width - rectwidth)/ 2; 
				recty += (height - rectheight) / 2; 
				break;
			case SVG_PRESERVEASPECTRATIO_XMAXYMID:
				rectx += width - rectwidth; 
				recty += ( txheight - rectheight) / 2; 
				break;
			case SVG_PRESERVEASPECTRATIO_XMINYMAX:
				recty += height - rectheight; 
				break;
			case SVG_PRESERVEASPECTRATIO_XMIDYMAX:
				rectx += (width - rectwidth)/ 2; 
				recty += height - rectheight; 
				break;
			case SVG_PRESERVEASPECTRATIO_XMAXYMAX:
				rectx += width  - rectwidth; 
				recty += height - rectheight; 
				break;
			}
		}
	}


	gf_path_get_bounds(stack->graph->path, &rc);
	drawable_reset_path(stack->graph);
	gf_path_add_rect_center(stack->graph->path, rectx, recty, rectwidth, rectheight);
	gf_path_get_bounds(stack->graph->path, &new_rc);
	if (!gf_rect_equal(rc, new_rc)) 
		drawable_mark_modified(stack->graph, tr_state);
	else if (stack->txh.flags & GF_SR_TEXTURE_PRIVATE_MEDIA)
		drawable_mark_modified(stack->graph, tr_state);

	gf_node_dirty_clear(stack->graph->node, GF_SG_SVG_GEOMETRY_DIRTY);
}
Ejemplo n.º 21
0
static void svg_traverse_audio_ex(GF_Node *node, void *rs, Bool is_destroy, SVGPropertiesPointers *props)
{
	SVGAllAttributes all_atts;
	SVGPropertiesPointers backup_props;
	u32 backup_flags, restore;
	GF_TraverseState *tr_state = (GF_TraverseState*)rs;
	SVG_audio_stack *stack = (SVG_audio_stack *)gf_node_get_private(node);

	if (is_destroy) {
		gf_sc_audio_predestroy(&stack->input);
		gf_sg_mfurl_del(stack->aurl);
		gf_free(stack);
		return;
	}
	if (stack->is_active) {
		gf_sc_audio_register(&stack->input, (GF_TraverseState*)rs);
	}

	restore = 0;
	if (!props) {
		restore = 1;
		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;
		props = tr_state->svg_props;
	}

	if (gf_node_dirty_get(node) & GF_SG_SVG_XLINK_HREF_DIRTY) {
		SVGAllAttributes atts;
		Bool lock_timeline = GF_FALSE;
		if (stack->is_active) 
			gf_sc_audio_stop(&stack->input);

		stack->is_error = GF_FALSE;
		
		gf_node_dirty_clear(node, GF_SG_SVG_XLINK_HREF_DIRTY);
		gf_term_get_mfurl_from_xlink(node, &(stack->aurl));

		gf_svg_flatten_attributes((SVG_Element*) node, &atts);
		if (atts.syncBehavior) lock_timeline = (*atts.syncBehavior == SMIL_SYNCBEHAVIOR_LOCKED) ? GF_TRUE : GF_FALSE;

		if (stack->aurl.count && (gf_sc_audio_open(&stack->input, &stack->aurl,
				atts.clipBegin ? (*atts.clipBegin) : 0.0,
				atts.clipEnd ? (*atts.clipEnd) : -1.0,
				lock_timeline) == GF_OK) 

		) {
			gf_mo_set_speed(stack->input.stream, FIX_ONE);
			stack->is_active = GF_TRUE;
		} else if (stack->is_active) {
			gf_sc_audio_unregister(&stack->input);
			stack->is_active = GF_FALSE;
		}
	}

	/*store mute flag*/
	stack->input.is_muted = GF_FALSE;
	if (tr_state->switched_off
		|| compositor_svg_is_display_off(props)
		|| (*(props->visibility) == SVG_VISIBILITY_HIDDEN) ) {
	
		stack->input.is_muted = GF_TRUE;
	}

	stack->input.intensity = tr_state->svg_props->computed_audio_level;

	if (restore) {
		memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
		tr_state->svg_flags = backup_flags;
	}
}
Ejemplo n.º 22
0
static void svg_audio_smil_evaluate_ex(SMIL_Timing_RTI *rti, Fixed normalized_scene_time, u32 status, GF_Node *slave_audio, GF_Node *video)
{
	GF_Node *audio;
	SVG_audio_stack *stack;

	audio = slave_audio;
	if (!audio) audio = gf_smil_get_element(rti);

	stack = (SVG_audio_stack *)gf_node_get_private(audio);
	
	switch (status) {
	case SMIL_TIMING_EVAL_UPDATE:
		if (!stack->is_active && !stack->is_error) { 
			if (stack->aurl.count) {
				SVGAllAttributes atts;
				Bool lock_timeline = GF_FALSE;
				gf_svg_flatten_attributes((SVG_Element*) (video ? video : audio), &atts);

				if (atts.syncBehavior) lock_timeline = (*atts.syncBehavior == SMIL_SYNCBEHAVIOR_LOCKED) ? GF_TRUE : GF_FALSE;

				if (gf_sc_audio_open(&stack->input, &stack->aurl,
						atts.clipBegin ? (*atts.clipBegin) : 0.0,
						atts.clipEnd ? (*atts.clipEnd) : -1.0,
						lock_timeline) == GF_OK) 
				{
					gf_mo_set_speed(stack->input.stream, FIX_ONE);
					stack->is_active = GF_TRUE;
				} else {
					stack->is_error = GF_TRUE;
				}
			}
		}
		else if (!slave_audio && stack->input.stream_finished && (gf_smil_get_media_duration(rti) < 0) ) { 
			Double dur = gf_mo_get_duration(stack->input.stream);
			if (dur <= 0) {
				dur = gf_mo_get_last_frame_time(stack->input.stream);
				dur /= 1000;
			}
			gf_smil_set_media_duration(rti, dur);
		}
		break;
	case SMIL_TIMING_EVAL_REPEAT:
		if (stack->is_active) 
			gf_sc_audio_restart(&stack->input);
		break;
	case SMIL_TIMING_EVAL_FREEZE:
		gf_sc_audio_stop(&stack->input);
		stack->is_active = GF_FALSE;
		break;
	case SMIL_TIMING_EVAL_REMOVE:
		gf_sc_audio_stop(&stack->input);
		stack->is_active = GF_FALSE;
		break;
	case SMIL_TIMING_EVAL_DEACTIVATE:
		if (stack->is_active) {
			gf_sc_audio_stop(&stack->input);
			gf_sc_audio_unregister(&stack->input);
			stack->is_active = GF_FALSE;
		}
		break;
	}
}
Ejemplo n.º 23
0
void compositor_init_svg_glyph(GF_Compositor *compositor, GF_Node *node)
{
	u16 utf_name[20];
	u8 *utf8;
	u32 len;
	GF_Rect rc;
	GF_Glyph *glyph;
	GF_Font *font;
	SVG_GlyphStack *st;
	SVGAllAttributes atts;
	GF_Node *node_font = gf_node_get_parent(node, 0);

	/*locate the font node*/
	if (node_font) node_font = gf_node_get_parent(node, 0);
	if (!node_font || (gf_node_get_tag(node_font)!=TAG_SVG_font) ) return;
	font = gf_node_get_private(node_font);
	if (!font) return;

	gf_svg_flatten_attributes((SVG_Element*)node, &atts);

	if (gf_node_get_tag(node)==TAG_SVG_missing_glyph) {
		GF_SAFEALLOC(st, SVG_GlyphStack);
		goto reg_common;
	}
	/*we must have unicode specified*/
	if (!atts.unicode) return;

	GF_SAFEALLOC(st, SVG_GlyphStack);
	utf8 = (u8 *) *atts.unicode;
	len = gf_utf8_mbstowcs(utf_name, 200, (const char **) &utf8);
	/*this is a single glyph*/
	if (len==1) {
		st->glyph.utf_name = utf_name[0];
		st->uni_len = 1;
	} else {
		st->glyph.utf_name = (u32) (PTR_TO_U_CAST st);
		st->unicode = gf_malloc(sizeof(u16)*len);
		st->uni_len = len;
		memcpy(st->unicode, utf_name, sizeof(u16)*len);
	}

reg_common:
	st->glyph.ID = (u32) (PTR_TO_U_CAST st);
	st->font = font;
	st->glyph.horiz_advance = font->max_advance_h;
	if (atts.horiz_adv_x) st->glyph.horiz_advance = FIX2INT( gf_ceil(atts.horiz_adv_x->value) );
	if (atts.d) {
		st->glyph.path = atts.d;
		gf_path_get_bounds(atts.d, &rc);
		st->glyph.width = FIX2INT( gf_ceil(rc.width) );
		st->glyph.height = FIX2INT( gf_ceil(rc.height) );
	}
	st->glyph.vert_advance = st->glyph.height;
	if (!st->glyph.vert_advance) 
		st->glyph.vert_advance = font->max_advance_v;

	/*register glyph*/
	if (!font->glyph) {
		font->glyph = &st->glyph;
	} else {
		glyph = font->glyph;
		while (glyph->next) glyph = glyph->next;
		glyph->next = &st->glyph;
	}

	gf_node_set_private(node, st);
	gf_node_set_callback_function(node, svg_traverse_glyph);
}
Ejemplo n.º 24
0
void svg_drawable_pick(GF_Node *node, Drawable *drawable, GF_TraverseState *tr_state)
{
	DrawAspect2D asp;
	GF_Matrix2D inv_2d;
	Fixed x, y;
	Bool picked = 0;
	GF_Compositor *compositor = tr_state->visual->compositor;
	SVGPropertiesPointers backup_props;
	GF_Matrix2D backup_matrix;
	GF_Matrix mx_3d;
	SVGAllAttributes all_atts;

	if (!drawable->path) return;

	gf_svg_flatten_attributes((SVG_Element *)node, &all_atts);

	memcpy(&backup_props, tr_state->svg_props, sizeof(SVGPropertiesPointers));
	gf_svg_apply_inheritance(&all_atts, tr_state->svg_props);
	if (compositor_svg_is_display_off(tr_state->svg_props)) return;

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

	memset(&asp, 0, sizeof(DrawAspect2D));
	drawable_get_aspect_2d_svg(node, &asp, tr_state);

#ifndef GPAC_DISABLE_3D
	if (tr_state->visual->type_3d) {
		svg_drawable_3d_pick(drawable, tr_state, &asp);
		compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d);
		memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
		return;
	} 
#endif
	gf_mx2d_copy(inv_2d, tr_state->transform);
	gf_mx2d_inverse(&inv_2d);
	x = tr_state->ray.orig.x;
	y = tr_state->ray.orig.y;
	gf_mx2d_apply_coords(&inv_2d, &x, &y);

	picked = svg_drawable_is_over(drawable, x, y, &asp, tr_state, NULL);

	if (picked) {
		u32 count, i;
		compositor->hit_local_point.x = x;
		compositor->hit_local_point.y = y;
		compositor->hit_local_point.z = 0;

		gf_mx_from_mx2d(&compositor->hit_world_to_local, &tr_state->transform);
		gf_mx_from_mx2d(&compositor->hit_local_to_world, &inv_2d);

		compositor->hit_node = drawable->node;
		compositor->hit_use_dom_events = 1;
		compositor->hit_normal.x = compositor->hit_normal.y = 0; compositor->hit_normal.z = FIX_ONE;
		compositor->hit_texcoords.x = gf_divfix(x, drawable->path->bbox.width) + FIX_ONE/2;
		compositor->hit_texcoords.y = gf_divfix(y, drawable->path->bbox.height) + FIX_ONE/2;
		svg_clone_use_stack(compositor, tr_state);
		/*not use in SVG patterns*/
		compositor->hit_appear = NULL;

		/*also stack any VRML sensors present at the current level. If the event is not catched
		by a listener in the SVG tree, the event will be forwarded to the VRML tree*/
		gf_list_reset(tr_state->visual->compositor->sensors);
		count = gf_list_count(tr_state->vrml_sensors);
		for (i=0; i<count; i++) {
			gf_list_add(tr_state->visual->compositor->sensors, gf_list_get(tr_state->vrml_sensors, i));
		}

		GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] node %s is under mouse - hit %g %g 0\n", gf_node_get_log_name(drawable->node), FIX2FLT(x), FIX2FLT(y)));
	}

	compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d);
	memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
}
Ejemplo n.º 25
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;
}
Ejemplo n.º 26
0
static void svg2bifs_node_start(void *sax_cbck, const char *name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes)
{
    u32 i;
    SVG2BIFS_Converter *converter = (SVG2BIFS_Converter *)sax_cbck;
    SVGPropertiesPointers *backup_props;
    char *id_string = NULL;
    u32	tag;
    SVG_Element *elt;
    SVG_DeferedAnimation *anim = NULL;

    tag = gf_xml_get_element_tag(name, 0);
    elt = (SVG_Element*)gf_node_new(converter->svg_sg, tag);
    if (!gf_sg_get_root_node(converter->svg_sg)) {
        gf_node_register((GF_Node *)elt, NULL);
        gf_sg_set_root_node(converter->svg_sg, (GF_Node *)elt);
    } else {
        gf_node_register((GF_Node *)elt, converter->svg_parent);
        //gf_node_list_add_child(&((GF_ParentNode*)converter->svg_parent)->children, (GF_Node *)elt);
    }

//	fprintf(stdout, "Converting %s\n", gf_node_get_class_name((GF_Node *)elt));
//	if (converter->bifs_parent) fprintf(stdout, "%s\n", gf_node_get_class_name(converter->bifs_parent));

    if (gf_svg_is_animation_tag(tag)) {
        GF_SAFEALLOC(anim, SVG_DeferedAnimation);
        /*default anim target is parent node*/
        anim->animation_elt = elt;
        if (converter->svg_parent) {
            anim->target = anim->anim_parent = (SVG_Element*) converter->svg_parent;
        }
    }

    for (i=0; i<nb_attributes; i++) {
        GF_XMLAttribute *att = (GF_XMLAttribute *)&attributes[i];
        if (!att->value || !strlen(att->value)) continue;

        if (!stricmp(att->name, "style")) {
            gf_svg_parse_style((GF_Node *)elt, att->value);
        } else if (!stricmp(att->name, "id") || !stricmp(att->name, "xml:id")) {
            gf_svg_parse_element_id((GF_Node *)elt, att->value, 0);
            id_string = att->value;
        } else if (anim && !stricmp(att->name, "to")) {
            anim->to = gf_strdup(att->value);
        } else if (anim && !stricmp(att->name, "from")) {
            anim->from = gf_strdup(att->value);
        } else if (anim && !stricmp(att->name, "by")) {
            anim->by = gf_strdup(att->value);
        } else if (anim && !stricmp(att->name, "values")) {
            anim->values = gf_strdup(att->value);
        } else if (anim && (tag == TAG_SVG_animateTransform) && !stricmp(att->name, "type")) {
            anim->type = gf_strdup(att->value);
        } else {
            GF_FieldInfo info;
            if (gf_node_get_field_by_name((GF_Node *)elt, att->name, &info)==GF_OK) {
                gf_svg_parse_attribute((GF_Node *)elt, &info, att->value, 0);
            } else {
                fprintf(stdout, "Skipping attribute %s\n", att->name);
            }
        }
    }

    if (anim) {
        svg_parse_animation(converter->svg_sg, anim);
    }

    memset(&converter->all_atts, 0, sizeof(SVGAllAttributes));
    gf_svg_flatten_attributes(elt, &converter->all_atts);

    backup_props = gf_malloc(sizeof(SVGPropertiesPointers));
    memcpy(backup_props, &converter->svg_props, sizeof(SVGPropertiesPointers));
    gf_node_set_private((GF_Node *)elt, backup_props);

    gf_svg_apply_inheritance(&converter->all_atts, &converter->svg_props);

    fprintf(stdout, "START\t%s\t%s\t%s", converter->svg_parent ? gf_node_get_class_name(converter->svg_parent) : "none", converter->bifs_parent ? gf_node_get_class_name(converter->bifs_parent) : "none", name);
    converter->svg_parent = (GF_Node *)elt;
    if (!gf_sg_get_root_node(converter->bifs_sg)) {
        if (tag == TAG_SVG_svg) {
            GF_Node *node, *child;

            converter->bifs_sg->usePixelMetrics = 1;
            if (converter->all_atts.width && converter->all_atts.width->type == SVG_NUMBER_VALUE) {
                converter->bifs_sg->width = FIX2INT(converter->all_atts.width->value);
            } else {
                converter->bifs_sg->width = 320;
            }
            if (converter->all_atts.height && converter->all_atts.height->type == SVG_NUMBER_VALUE) {
                converter->bifs_sg->height = FIX2INT(converter->all_atts.height->value);
            } else {
                converter->bifs_sg->height = 200;
            }

            node = gf_node_new(converter->bifs_sg, TAG_MPEG4_OrderedGroup);
            gf_node_register(node, NULL);
            gf_sg_set_root_node(converter->bifs_sg, node);

            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_QuantizationParameter);
            gf_node_register(child, node);
            gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            {
                M_QuantizationParameter *qp = (M_QuantizationParameter *)child;
                qp->useEfficientCoding = 1;
            }

            /* SVG to BIFS coordinate transformation */
            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Viewport);
            gf_node_register(child, node);
            gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            {
                M_Viewport *vp = (M_Viewport*)child;
                if (converter->all_atts.viewBox) {
                    vp->size.x = converter->all_atts.viewBox->width;
                    vp->size.y = converter->all_atts.viewBox->height;
                    vp->position.x = converter->all_atts.viewBox->x+converter->all_atts.viewBox->width/2;
                    vp->position.y = -(converter->all_atts.viewBox->y+converter->all_atts.viewBox->height/2);
                } else {
                    vp->size.x = INT2FIX(converter->bifs_sg->width);
                    vp->size.y = INT2FIX(converter->bifs_sg->height);
                    vp->position.x = INT2FIX(converter->bifs_sg->width)/2;
                    vp->position.y = -INT2FIX(converter->bifs_sg->height)/2;
                }
            }

            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Background2D);
            gf_node_register(child, node);
            gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            {
                M_Background2D *b = (M_Background2D *)child;
                b->backColor.red = FIX_ONE;
                b->backColor.green = FIX_ONE;
                b->backColor.blue = FIX_ONE;
            }

            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D);
            gf_node_register(child, node);
            gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            node = child;
            child = NULL;
            {
                M_Transform2D *tr = (M_Transform2D *)node;
                tr->scale.y = -FIX_ONE;
            }
            converter->bifs_parent = node;
        }
    } else {
        GF_Node *node, *child;

        node = converter->bifs_parent;

        switch(tag) {
        case TAG_SVG_g:
        {
            if (converter->all_atts.transform) {
                node = add_transform_matrix(converter, node);
                converter->bifs_parent = node;
            } else {
                M_Group *g = (M_Group*)gf_node_new(converter->bifs_sg, TAG_MPEG4_Group);
                gf_node_register((GF_Node *)g, node);
                gf_node_list_add_child(&((GF_ParentNode*)node)->children, (GF_Node *)g);
                node = (GF_Node *)g;
                converter->bifs_parent = node;
            }
        }
        break;
        case TAG_SVG_rect:
        {
            Bool is_parent_set = 0;
            if (converter->all_atts.transform) {
                node = add_transform_matrix(converter, node);
                converter->bifs_parent = node;
                is_parent_set = 1;
            }
            if (converter->force_transform) {
                node = add_transform2d(converter, node);
                if (!is_parent_set) {
                    converter->bifs_parent = node;
                    is_parent_set = 1;
                }
            }
            if (converter->all_atts.x || converter->all_atts.y) {
                child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D);
                gf_node_register(child, node);
                gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
                node = child;
                child = NULL;
                if (!is_parent_set) {
                    converter->bifs_parent = node;
                    is_parent_set = 1;
                }
                {
                    M_Transform2D *tr = (M_Transform2D *)node;
                    if (converter->all_atts.x) tr->translation.x = converter->all_atts.x->value + (converter->all_atts.width?converter->all_atts.width->value/2:0);
                    if (converter->all_atts.y) tr->translation.y = converter->all_atts.y->value + (converter->all_atts.height?converter->all_atts.height->value/2:0);
                }
            }
            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape);
            gf_node_register(child, node);
            gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            node = child;
            child = NULL;
            if (!is_parent_set) converter->bifs_parent = node;
            {
                M_Shape *shape = (M_Shape *)node;
                shape->geometry = gf_node_new(converter->bifs_sg, TAG_MPEG4_Rectangle);
                gf_node_register(shape->geometry, (GF_Node *)shape);
                {
                    M_Rectangle *rect = (M_Rectangle *)shape->geometry;
                    if (converter->all_atts.width) rect->size.x = converter->all_atts.width->value;
                    if (converter->all_atts.height) rect->size.y = converter->all_atts.height->value;
                }

                shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg);
                gf_node_register(shape->appearance, (GF_Node *)shape);
            }
        }
        break;
        case TAG_SVG_path:
        {
            Bool is_parent_set = 0;
            if (converter->all_atts.transform) {
                node = add_transform_matrix(converter, node);
                converter->bifs_parent = node;
                is_parent_set = 1;
            }
            if (converter->force_transform) {
                node = add_transform2d(converter, node);
                if (!is_parent_set) {
                    converter->bifs_parent = node;
                    is_parent_set = 1;
                }
            }
            if (converter->all_atts.x || converter->all_atts.y) {
                child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D);
                gf_node_register(child, node);
                gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
                node = child;
                child = NULL;
                if (!is_parent_set) {
                    converter->bifs_parent = node;
                    is_parent_set = 1;
                }
                {
                    M_Transform2D *tr = (M_Transform2D *)node;
                    if (converter->all_atts.x) tr->translation.x = converter->all_atts.x->value;
                    if (converter->all_atts.y) tr->translation.y = converter->all_atts.y->value;
                }
            }
            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape);
            gf_node_register(child, node);
            gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            node = child;
            child = NULL;
            if (!is_parent_set) converter->bifs_parent = node;
            {
                M_Shape *shape = (M_Shape *)node;
                shape->geometry = gf_node_new(converter->bifs_sg, TAG_MPEG4_XCurve2D);
                gf_node_register(shape->geometry, (GF_Node *)shape);
                if (converter->all_atts.d) {
                    M_Coordinate2D *c2d;
                    M_XCurve2D *xc = (M_XCurve2D *)shape->geometry;
                    u32 i, j, c, k;

                    xc->point = gf_node_new(converter->bifs_sg, TAG_MPEG4_Coordinate2D);
                    c2d = (M_Coordinate2D *)xc->point;
                    gf_node_register(xc->point, (GF_Node *)xc);

                    gf_sg_vrml_mf_alloc(&c2d->point, GF_SG_VRML_MFVEC2F, converter->all_atts.d->n_points);
                    gf_sg_vrml_mf_alloc(&xc->type, GF_SG_VRML_MFINT32, converter->all_atts.d->n_points);

                    c = 0;
                    k = 0;
                    j = 0;
                    c2d->point.vals[k] = converter->all_atts.d->points[0];
                    k++;
                    xc->type.vals[0] = 0;
                    for (i = 1; i < converter->all_atts.d->n_points; ) {
                        switch(converter->all_atts.d->tags[i]) {
                        case GF_PATH_CURVE_ON:
                            c2d->point.vals[k] = converter->all_atts.d->points[i];
                            k++;

                            if (i-1 == converter->all_atts.d->contours[c]) {
                                xc->type.vals[j] = 0;
                                c++;
                            } else {
                                xc->type.vals[j] = 1;
                            }
                            i++;
                            break;
                        case GF_PATH_CURVE_CUBIC:
                            c2d->point.vals[k] = converter->all_atts.d->points[i];
                            c2d->point.vals[k+1] = converter->all_atts.d->points[i+1];
                            c2d->point.vals[k+2] = converter->all_atts.d->points[i+2];
                            k+=3;

                            xc->type.vals[j] = 2;
                            if (converter->all_atts.d->tags[i+2]==GF_PATH_CLOSE)  {
                                j++;
                                xc->type.vals[j] = 6;
                            }
                            i+=3;
                            break;
                        case GF_PATH_CLOSE:
                            xc->type.vals[j] = 6;
                            i++;
                            break;
                        case GF_PATH_CURVE_CONIC:
                            c2d->point.vals[k] = converter->all_atts.d->points[i];
                            c2d->point.vals[k+1] = converter->all_atts.d->points[i+1];
                            k+=2;

                            xc->type.vals[j] = 7;
                            if (converter->all_atts.d->tags[i+1]==GF_PATH_CLOSE)  {
                                j++;
                                xc->type.vals[j] = 6;
                            }
                            i+=2;
                            break;
                        }
                        j++;
                    }
                    xc->type.count = j;
                    c2d->point.count = k;
                }

                shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg);
                gf_node_register(shape->appearance, (GF_Node *)shape);
            }
        }
        break;
        case TAG_SVG_polyline:
        {
            Bool is_parent_set = 0;
            if (converter->all_atts.transform) {
                node = add_transform_matrix(converter, node);
                converter->bifs_parent = node;
                is_parent_set = 1;
            }
            if (converter->force_transform) {
                node = add_transform2d(converter, node);
                if (!is_parent_set) {
                    converter->bifs_parent = node;
                    is_parent_set = 1;
                }
            }
            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape);
            gf_node_register(child, node);
            gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            node = child;
            child = NULL;
            if (!is_parent_set) converter->bifs_parent = node;
            {
                M_Shape *shape = (M_Shape *)node;
                shape->geometry = gf_node_new(converter->bifs_sg, TAG_MPEG4_IndexedFaceSet2D);
                gf_node_register(shape->geometry, (GF_Node *)shape);
                if (converter->all_atts.points) {
                    M_Coordinate2D *c2d;
                    M_IndexedFaceSet2D *ifs = (M_IndexedFaceSet2D *)shape->geometry;
                    u32 i;

                    ifs->coord = gf_node_new(converter->bifs_sg, TAG_MPEG4_Coordinate2D);
                    c2d = (M_Coordinate2D *)ifs->coord;
                    gf_node_register(ifs->coord, (GF_Node *)ifs);

                    gf_sg_vrml_mf_alloc(&c2d->point, GF_SG_VRML_MFVEC2F, gf_list_count(*converter->all_atts.points));
                    for (i = 0; i < gf_list_count(*converter->all_atts.points); i++) {
                        SVG_Point *p = (SVG_Point *)gf_list_get(*converter->all_atts.points, i);
                        c2d->point.vals[i].x = p->x;
                        c2d->point.vals[i].y = p->y;
                    }
                }

                shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg);
                gf_node_register(shape->appearance, (GF_Node *)shape);
            }
        }
        break;
        case TAG_SVG_text:
        {
            Bool is_parent_set = 0;
            if (converter->all_atts.transform) {
                node = add_transform_matrix(converter, node);
                converter->bifs_parent = node;
                is_parent_set = 1;
            }
            if (converter->force_transform) {
                node = add_transform2d(converter, node);
                if (!is_parent_set) {
                    converter->bifs_parent = node;
                    is_parent_set = 1;
                }
            }

            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D);
            gf_node_register(child, node);
            gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            {
                M_Transform2D *tr = (M_Transform2D *)child;
                if (converter->all_atts.text_x) tr->translation.x = ((SVG_Coordinate *)gf_list_get(*converter->all_atts.text_x, 0))->value;
                if (converter->all_atts.text_y) tr->translation.y = ((SVG_Coordinate *)gf_list_get(*converter->all_atts.text_y, 0))->value;
                tr->scale.y = -FIX_ONE;
            }
            node = child;
            child = NULL;
            if (!is_parent_set) {
                converter->bifs_parent = node;
                is_parent_set = 1;
            }

            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape);
            gf_node_register(child, node);
            gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            node = child;
            child = NULL;
            if (!is_parent_set) converter->bifs_parent = node;
            {
                M_FontStyle *fs;
                M_Text *text;
                M_Shape *shape = (M_Shape *)node;
                text = (M_Text *)gf_node_new(converter->bifs_sg, TAG_MPEG4_Text);
                shape->geometry = (GF_Node *)text;
                converter->bifs_text_node = shape->geometry;
                gf_node_register(shape->geometry, (GF_Node *)shape);

                fs = (M_FontStyle *)gf_node_new(converter->bifs_sg, TAG_MPEG4_XFontStyle);
                gf_node_register((GF_Node *)fs, (GF_Node*)text);
                text->fontStyle = (GF_Node *)fs;

                gf_sg_vrml_mf_alloc(&fs->family, GF_SG_VRML_MFSTRING, 1);
                fs->family.vals[0] = gf_strdup(converter->svg_props.font_family->value);
                fs->size = converter->svg_props.font_size->value;

                shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg);
                gf_node_register(shape->appearance, (GF_Node *)shape);
            }
        }
        break;
        case TAG_SVG_ellipse:
        case TAG_SVG_circle:
        {
            Bool is_parent_set = 0;
            if (converter->all_atts.transform) {
                node = add_transform_matrix(converter, node);
                converter->bifs_parent = node;
                is_parent_set = 1;
            }
            if (converter->force_transform) {
                node = add_transform2d(converter, node);
                if (!is_parent_set) {
                    converter->bifs_parent = node;
                    is_parent_set = 1;
                }
            }
            if (converter->all_atts.cx || converter->all_atts.cy) {
                child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D);
                gf_node_register(child, node);
                gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
                {
                    M_Transform2D *tr = (M_Transform2D *)child;
                    if (converter->all_atts.cx) tr->translation.x = converter->all_atts.cx->value;
                    if (converter->all_atts.cy) tr->translation.y = converter->all_atts.cy->value;
                }
                node = child;
                child = NULL;
                if (!is_parent_set) {
                    converter->bifs_parent = node;
                    is_parent_set = 1;
                }
            }
            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape);
            gf_node_register(child, node);
            gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            node = child;
            child = NULL;
            if (!is_parent_set) converter->bifs_parent = node;
            {
                M_Shape *shape = (M_Shape *)node;
                if (tag == TAG_SVG_ellipse) {
                    M_Ellipse *e = (M_Ellipse *)gf_node_new(converter->bifs_sg, TAG_MPEG4_Ellipse);
                    shape->geometry = (GF_Node *)e;
                    e->radius.x = converter->all_atts.rx->value;
                    e->radius.y = converter->all_atts.ry->value;
                } else {
                    M_Circle *c = (M_Circle *)gf_node_new(converter->bifs_sg, TAG_MPEG4_Circle);
                    shape->geometry = (GF_Node *)c;
                    c->radius = converter->all_atts.r->value;
                }
                gf_node_register(shape->geometry, (GF_Node *)shape);

                shape->appearance = create_appearance(&converter->svg_props, converter->bifs_sg);
                gf_node_register(shape->appearance, (GF_Node *)shape);
            }
        }
        break;

        case TAG_SVG_defs:
        {
            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Switch);
            gf_node_register(child, node);
            gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            node = child;
            child = NULL;
            {
                M_Switch *sw = (M_Switch *)node;
                sw->whichChoice = -1;
            }
            converter->bifs_parent = node;
        }
        break;
        case TAG_SVG_solidColor:
        {
            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Shape);
            gf_node_register(child, node);
            gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            node = child;
            child = NULL;
            converter->bifs_parent = node;
        }
        break;
        case TAG_SVG_animateTransform:
        {
            GF_Node *child_ts;
            if (!gf_node_get_id(node)) {
                gf_node_set_id(node, gf_sg_get_next_available_node_id(converter->bifs_sg), NULL);
            }

            child_ts = gf_node_new(converter->bifs_sg, TAG_MPEG4_TimeSensor);
            if (!gf_node_get_id(child_ts)) {
                gf_node_set_id(child_ts, gf_sg_get_next_available_node_id(converter->bifs_sg), NULL);
            }
            gf_node_register(child_ts, node);
            gf_node_list_add_child(&((GF_ParentNode *)node)->children, child_ts);
            {
                M_TimeSensor *ts = (M_TimeSensor *)child_ts;
                if (converter->all_atts.dur) {
                    ts->cycleInterval = converter->all_atts.dur->clock_value;
                }
                if (converter->all_atts.repeatCount && converter->all_atts.repeatCount->type == SMIL_REPEATCOUNT_INDEFINITE) {
                    ts->loop = 1;
                }
            }

            if (converter->all_atts.transform_type) {
                GF_FieldInfo fromField, toField;

                switch (*converter->all_atts.transform_type) {
                case SVG_TRANSFORM_ROTATE:
                    child = gf_node_new(converter->bifs_sg, TAG_MPEG4_PositionInterpolator2D);
                    if (!gf_node_get_id(child)) {
                        gf_node_set_id(child, gf_sg_get_next_available_node_id(converter->bifs_sg), NULL);
                    }
                    gf_node_register(child, node);
                    gf_node_list_add_child(&((GF_ParentNode *)node)->children, child);

                    gf_node_get_field_by_name(child_ts, "fraction_changed", &fromField);
                    gf_node_get_field_by_name(child, "set_fraction", &toField);
                    gf_sg_route_new(converter->bifs_sg, child_ts, fromField.fieldIndex, child, toField.fieldIndex);

                    gf_node_get_field_by_name(child, "value_changed", &fromField);
                    gf_node_get_field_by_name(node, "rotationAngle", &toField);
                    gf_sg_route_new(converter->bifs_sg, child, fromField.fieldIndex, node, toField.fieldIndex);
                    {
                        M_PositionInterpolator2D *pi2d = (M_PositionInterpolator2D *)child;
                        if (converter->all_atts.keyTimes) {
                            SFFloat *g;
                            u32 count, i;
                            count = gf_list_count(*converter->all_atts.keyTimes);
                            for (i = 0; i < count; i++) {
                                Fixed *f = gf_list_get(*converter->all_atts.keyTimes, i);
                                gf_sg_vrml_mf_append(&pi2d->key, GF_SG_VRML_MFFLOAT, &g);
                                *g = *f;
                            }
                        }
                        if (converter->all_atts.values) {
                            SFVec2f *g;
                            u32 count, i;
                            count = gf_list_count(converter->all_atts.values->values);
                            for (i = 0; i < count; i++) {
                                SVG_Point_Angle *p;
                                p = gf_list_get(converter->all_atts.values->values, i);
                                gf_sg_vrml_mf_append(&pi2d->keyValue, GF_SG_VRML_MFVEC2F, &g);
                                g->x = p->x;
                                g->y = p->y;
                            }
                        }
                    }


                    child = gf_node_new(converter->bifs_sg, TAG_MPEG4_ScalarInterpolator);
                    if (!gf_node_get_id(child)) {
                        gf_node_set_id(child, gf_sg_get_next_available_node_id(converter->bifs_sg), NULL);
                    }
                    gf_node_register(child, node);
                    gf_node_list_add_child(&((GF_ParentNode *)node)->children, child);

                    gf_node_get_field_by_name(child_ts, "fraction_changed", &fromField);
                    gf_node_get_field_by_name(child, "set_fraction", &toField);
                    gf_sg_route_new(converter->bifs_sg, child_ts, fromField.fieldIndex, child, toField.fieldIndex);

                    gf_node_get_field_by_name(child, "value_changed", &fromField);
                    gf_node_get_field_by_name(node, "center", &toField);
                    gf_sg_route_new(converter->bifs_sg, child, fromField.fieldIndex, node, toField.fieldIndex);

                    {
                        M_ScalarInterpolator *si = (M_ScalarInterpolator *)child;
                        if (converter->all_atts.keyTimes) {
                            SFFloat *g;
                            u32 count, i;
                            count = gf_list_count(*converter->all_atts.keyTimes);
                            for (i = 0; i < count; i++) {
                                Fixed *f = gf_list_get(*converter->all_atts.keyTimes, i);
                                gf_sg_vrml_mf_append(&si->key, GF_SG_VRML_MFFLOAT, &g);
                                *g = *f;
                            }
                        }
                        if (converter->all_atts.values) {
                            SFFloat *g;
                            u32 count, i;
                            count = gf_list_count(converter->all_atts.values->values);
                            for (i = 0; i < count; i++) {
                                SVG_Point_Angle *p;
                                p = gf_list_get(converter->all_atts.values->values, i);
                                gf_sg_vrml_mf_append(&si->keyValue, GF_SG_VRML_MFFLOAT, &g);
                                *g = p->angle;
                            }
                        }
                    }

                    break;

                case SVG_TRANSFORM_SCALE:
                case SVG_TRANSFORM_TRANSLATE:
                    child = gf_node_new(converter->bifs_sg, TAG_MPEG4_PositionInterpolator2D);
                    if (!gf_node_get_id(child)) {
                        gf_node_set_id(child, gf_sg_get_next_available_node_id(converter->bifs_sg), NULL);
                    }
                    gf_node_register(child, node);
                    gf_node_list_add_child(&((GF_ParentNode *)node)->children, child);

                    gf_node_get_field_by_name(child_ts, "fraction_changed", &fromField);
                    gf_node_get_field_by_name(child, "set_fraction", &toField);
                    gf_sg_route_new(converter->bifs_sg, child_ts, fromField.fieldIndex, child, toField.fieldIndex);

                    gf_node_get_field_by_name(child, "value_changed", &fromField);
                    if (*converter->all_atts.transform_type == SVG_TRANSFORM_SCALE)
                        gf_node_get_field_by_name(node, "scale", &toField);
                    else
                        gf_node_get_field_by_name(node, "translation", &toField);

                    gf_sg_route_new(converter->bifs_sg, child, fromField.fieldIndex, node, toField.fieldIndex);
                    {
                        M_PositionInterpolator2D *pi2d = (M_PositionInterpolator2D *)child;
                        if (converter->all_atts.keyTimes) {
                            SFFloat *g;
                            u32 count, i;
                            count = gf_list_count(*converter->all_atts.keyTimes);
                            for (i = 0; i < count; i++) {
                                Fixed *f = gf_list_get(*converter->all_atts.keyTimes, i);
                                gf_sg_vrml_mf_append(&pi2d->key, GF_SG_VRML_MFFLOAT, &g);
                                *g = *f;
                            }
                        }
                        if (converter->all_atts.values) {
                            SFVec2f *g;
                            u32 count, i;
                            count = gf_list_count(converter->all_atts.values->values);
                            for (i = 0; i < count; i++) {
                                SVG_Point *p;
                                p = gf_list_get(converter->all_atts.values->values, i);
                                gf_sg_vrml_mf_append(&pi2d->keyValue, GF_SG_VRML_MFVEC2F, &g);
                                g->x = p->x;
                                g->y = p->y;
                            }
                        }
                    }
                    break;
                default:
                    fprintf(stdout, "Warning: transformation type not supported \n");
                }
            }
            //converter->bifs_parent = node;
        }
        break;
        default:
        {
            fprintf(stdout, "Warning: element %s not supported \n", gf_node_get_class_name((GF_Node *)elt));
            child = gf_node_new(converter->bifs_sg, TAG_MPEG4_Transform2D);
            gf_node_register(child, node);
            //gf_node_list_add_child(&((GF_ParentNode*)node)->children, child);
            node = child;
            child = NULL;
            converter->bifs_parent = node;
        }
        break;
        }

        if (id_string)
            gf_node_set_id(converter->bifs_parent, gf_sg_get_next_available_node_id(converter->bifs_sg), NULL);//gf_node_get_name((GF_Node *)elt));

    }
    fprintf(stdout, "\t%s\n", converter->bifs_parent ? gf_node_get_class_name(converter->bifs_parent) : "none");
}
Ejemplo n.º 27
0
static void svg_drawable_traverse(GF_Node *node, void *rs, Bool is_destroy,
							void (*rebuild_path)(GF_Node *, Drawable *, SVGAllAttributes *),
							Bool is_svg_rect, Bool is_svg_path)
{
	GF_Matrix2D backup_matrix;
	GF_Matrix mx_3d;
	DrawableContext *ctx;
	SVGPropertiesPointers backup_props;
	u32 backup_flags;
	Drawable *drawable = (Drawable *)gf_node_get_private(node);
	GF_TraverseState *tr_state = (GF_TraverseState *)rs;
	SVGAllAttributes all_atts;

	if (is_destroy) {
#if USE_GF_PATH
		/* The path is the same as the one in the SVG node, don't delete it here */
		if (is_svg_path) drawable->path = NULL;
#endif
		drawable_node_del(node);
		return;
	}
	assert(tr_state->traversing_mode!=TRAVERSE_DRAW_2D);

	
	if (tr_state->traversing_mode==TRAVERSE_PICK) {
		svg_drawable_pick(node, drawable, 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;
	
	/* Recreates the path (i.e the shape) only if the node is dirty */
	if (gf_node_dirty_get(node) & GF_SG_SVG_GEOMETRY_DIRTY) {
		/*the rebuild function is responsible for cleaning the path*/
		rebuild_path(node, drawable, &all_atts);
		gf_node_dirty_clear(node, GF_SG_SVG_GEOMETRY_DIRTY);
		drawable_mark_modified(drawable, tr_state);
	}
	if (drawable->path) {
		if (*(tr_state->svg_props->fill_rule)==GF_PATH_FILL_ZERO_NONZERO) {
			if (!(drawable->path->flags & GF_PATH_FILL_ZERO_NONZERO)) {
				drawable->path->flags |= GF_PATH_FILL_ZERO_NONZERO;
				drawable_mark_modified(drawable, tr_state);
			}
		} else {
			if (drawable->path->flags & GF_PATH_FILL_ZERO_NONZERO) {
				drawable->path->flags &= ~GF_PATH_FILL_ZERO_NONZERO;
				drawable_mark_modified(drawable, tr_state);
			}
		}
	}

	if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
		if (! compositor_svg_is_display_off(tr_state->svg_props)) {
			DrawAspect2D asp;
			gf_path_get_bounds(drawable->path, &tr_state->bounds);
			if (!tr_state->ignore_strike) {
				memset(&asp, 0, sizeof(DrawAspect2D));
				drawable_get_aspect_2d_svg(node, &asp, tr_state);
				if (asp.pen_props.width) {
					StrikeInfo2D *si = drawable_get_strikeinfo(tr_state->visual->compositor, drawable, &asp, NULL, drawable->path, 0, NULL);
					if (si && si->outline) {
						gf_path_get_bounds(si->outline, &tr_state->bounds);
					}
				}
			}
			compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, NULL);
			if (!tr_state->abort_bounds_traverse)
				gf_mx2d_apply_rect(&tr_state->transform, &tr_state->bounds);
			gf_sc_get_nodes_bounds(node, NULL, tr_state, NULL);

			compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, NULL);
		}
	} else if (tr_state->traversing_mode == TRAVERSE_SORT) {
		/*reset our flags - this may break reuse of nodes and change-detection in dirty-rect algo */
		gf_node_dirty_clear(node, 0);

		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);

			ctx = drawable_init_context_svg(drawable, tr_state);
			if (ctx) {
				if (is_svg_rect) {
					if (ctx->aspect.fill_texture && ctx->aspect.fill_texture->transparent) {}
					else if (GF_COL_A(ctx->aspect.fill_color) != 0xFF) {}
					else if (ctx->transform.m[1] || ctx->transform.m[3]) {}
					else {
						ctx->flags &= ~CTX_IS_TRANSPARENT;
						if (!ctx->aspect.pen_props.width) 
							ctx->flags |= CTX_NO_ANTIALIAS;
					}
				}

				if (all_atts.pathLength && all_atts.pathLength->type==SVG_NUMBER_VALUE) 
					ctx->aspect.pen_props.path_length = all_atts.pathLength->value;

#ifndef GPAC_DISABLE_3D
				if (tr_state->visual->type_3d) {
					if (!drawable->mesh) {
						drawable->mesh = new_mesh();
						if (drawable->path) mesh_from_path(drawable->mesh, drawable->path);
					}
					visual_3d_draw_from_context(ctx, tr_state);
					ctx->drawable = NULL;
				} else 
#endif
				{
					drawable_finalize_sort(ctx, tr_state, NULL);
				}
			}
			compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d);
		}
	}

	memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers));
	tr_state->svg_flags = backup_flags;
}
Ejemplo n.º 28
0
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;
}
Ejemplo n.º 29
0
/* Attributes from the timed elements are not easy to use during runtime, 
   the runtime info is a set of easy to use structures. 
   This function initializes them (intervals, status ...) 
   and registers the element with the scenegraph */
GF_EXPORT
void gf_smil_timing_init_runtime_info(GF_Node *timed_elt)
{
	GF_SceneGraph *sg;
	SMIL_Timing_RTI *rti;
	SMILTimingAttributesPointers *timingp = NULL;
	u32 tag = gf_node_get_tag(timed_elt);
	SVGAllAttributes all_atts;
	SVGTimedAnimBaseElement *e = (SVGTimedAnimBaseElement *)timed_elt;

	gf_svg_flatten_attributes((SVG_Element *)e, &all_atts);
	e->timingp = gf_malloc(sizeof(SMILTimingAttributesPointers));
	e->timingp->begin		= all_atts.begin;
	e->timingp->clipBegin	= all_atts.clipBegin;
	e->timingp->clipEnd		= all_atts.clipEnd;
	e->timingp->dur			= all_atts.dur;
	e->timingp->end			= all_atts.end;
	e->timingp->fill		= all_atts.smil_fill;
	e->timingp->max			= all_atts.max;
	e->timingp->min			= all_atts.min;
	e->timingp->repeatCount = all_atts.repeatCount;
	e->timingp->repeatDur	= all_atts.repeatDur;
	e->timingp->restart		= all_atts.restart;
	timingp = e->timingp;
	if (!timingp) return;

	if (tag == TAG_SVG_audio || tag == TAG_SVG_video) {
		/* if the dur attribute is not set, then it should be set to media 
		   as this is the default for media elements see 
		   http://www.w3.org/TR/2005/REC-SMIL2-20051213/smil-timing.html#Timing-DurValueSemantics
		   "For simple media elements that specify continuous media (i.e. media with an inherent notion of time), 
		   the implicit duration is the intrinsic duration of the media itself - e.g. video and audio files 
		   have a defined duration."
		TODO: Check if this should work with the animation element */
		if (!e->timingp->dur) {
			GF_FieldInfo info;
			gf_node_get_attribute_by_tag((GF_Node *)e, TAG_SVG_ATT_dur, 1, 0, &info);
			e->timingp->dur = (SMIL_Duration *)info.far_ptr;
			e->timingp->dur->type = SMIL_DURATION_MEDIA;
		}
	}

	GF_SAFEALLOC(rti, SMIL_Timing_RTI)
	timingp->runtime = rti;
	rti->timed_elt = timed_elt;
	GF_LOG(GF_LOG_DEBUG, GF_LOG_SMIL, ("[SMIL Timing   ] Time %f - Timed element %s - Initialization\n", gf_node_get_scene_time((GF_Node *)rti->timed_elt), gf_node_get_log_name((GF_Node *)rti->timed_elt)));

	rti->timingp = timingp;
	rti->status = SMIL_STATUS_WAITING_TO_BEGIN;
	rti->evaluate_status = SMIL_TIMING_EVAL_NONE;	
	rti->evaluate = gf_smil_timing_null_timed_function;
	rti->scene_time = -1;
	rti->force_reevaluation = 0;
	rti->media_duration = -1;

	GF_SAFEALLOC(rti->current_interval, SMIL_Interval);
	gf_smil_timing_get_first_interval(rti);
	GF_SAFEALLOC(rti->next_interval, SMIL_Interval);
	gf_smil_timing_get_next_interval(rti, 0, rti->next_interval, rti->current_interval->begin);

	/* Now that the runtime info for this timed element is initialized, we can tell the scene graph that it can start
	   notifying the scene time to this element. Because of the 'animation' element, we can have many scene graphs
	   sharing the same scene time, we therefore add this timed element to the rootmost scene graph. */
	sg = timed_elt->sgprivate->scenegraph;
	while (sg->parent_scene) sg = sg->parent_scene;
	gf_smil_timing_add_to_sg(sg, rti);
}
Ejemplo n.º 30
0
/*translate string to glyph sequence*/
static GF_Err svg_font_get_glyphs(void *udta, const char *utf_string, u32 *glyph_buffer, u32 *io_glyph_buffer_size, const char *lang, Bool *is_rtl)
{
	u32 prev_c;
	u32 len;
	u32 i, gl_idx;
	u16 *utf_res;
	GF_Node *node = (GF_Node *)udta;
	GF_ChildNodeItem *child;
	char *utf8 = (char*) utf_string;

	/*FIXME - use glyphs unicode attributes for glyph substitution*/
	len = utf_string ? strlen(utf_string) : 0;
	if (!len) {
		*io_glyph_buffer_size = 0;
		return GF_OK;
	}

	if (*io_glyph_buffer_size < len+1) {
		*io_glyph_buffer_size = len+1;
		return GF_BUFFER_TOO_SMALL;
	}

	len = gf_utf8_mbstowcs((u16*) glyph_buffer, *io_glyph_buffer_size, (const char**)&utf8);
	if ((s32) len < 0) return GF_IO_ERR;
	/*should not happen*/
	if (utf8) return GF_IO_ERR;

	/*perform bidi relayout*/
	utf_res = (u16 *) glyph_buffer;
	*is_rtl = gf_utf8_reorder_bidi(utf_res, len);

	/*move 16bit buffer to 32bit*/
	for (i=len; i>0; i--) {
		glyph_buffer[i-1] = utf_res[i-1];
	}

	gl_idx = 0;
	prev_c = 0;
	for (i=0;i<len; i++) {
		SVG_GlyphStack *missing_glyph = NULL;
		SVG_GlyphStack *st = NULL;
		child = ((GF_ParentNode *) node)->children;
		while (child) {
			u32 tag = gf_node_get_tag(child->node);
			if (tag==TAG_SVG_missing_glyph) {
				missing_glyph = gf_node_get_private(child->node);
			} else if (tag ==TAG_SVG_glyph) {
				Bool glyph_ok = 0;
				SVGAllAttributes atts;
				
				st = gf_node_get_private(child->node);
				if (!st) {
					child = child->next;
					continue;
				}

				if (st->glyph.utf_name==glyph_buffer[i]) {
					u32 j, count;
					gf_svg_flatten_attributes((SVG_Element*)child->node, &atts);
					if (!lang) {
						glyph_ok = 1;
					} else {
						if (!atts.lang) {
							glyph_ok = 1;
						} else {
							count = gf_list_count(*atts.lang);
							for (j=0; j<count; j++) {
								char *name = gf_list_get(*atts.lang, j);
								if (!stricmp(name, lang) || strstr(lang, name)) {
									glyph_ok = 1;
									break;
								}
							}
						}
					}
					if (atts.arabic_form) {
						Bool first = (!prev_c || (prev_c==' ')) ? 1 : 0;
						Bool last = ((i+1==len) || (glyph_buffer[i+1]==' ') ) ? 1 : 0;
						if (!strcmp(*atts.arabic_form, "isolated")) {
							if (!first || !last) glyph_ok = 0;
						}
						if (!strcmp(*atts.arabic_form, "initial")) {
							if (!first) glyph_ok = 0;
						}
						if (!strcmp(*atts.arabic_form, "medial")) {
							if (first || last) glyph_ok = 0;
						}
						if (!strcmp(*atts.arabic_form, "terminal")) {
							if (!last) glyph_ok = 0;
						}
					}
					if (glyph_ok) break;
				}
				/*perform glyph substitution*/
				else if (st->uni_len>1) {
					u32 j;
					for (j=0; j<st->uni_len; j++) {
						if (i+j>=len) break;
						if (glyph_buffer[i+j] != st->unicode[j]) break;
					}
					if (j==st->uni_len)
						break;
				}
				st = NULL;
			}
			child = child->next;
		}
		prev_c = glyph_buffer[i];

		if (!st) 
			st = missing_glyph;
		glyph_buffer[gl_idx] = st ? st->glyph.ID : 0;
		if (st && st->uni_len>1) i++;
		
		gl_idx++;
	}
	*io_glyph_buffer_size = len = gl_idx;
	
	return GF_OK;
}