Exemple #1
0
Bool osd_load_scene(GF_OSD *osd)
{
	GF_Node *n;
	GF_List *nodes;
	const char *opt;
	GF_DOMHandler *hdl;
	/*BT/VRML from string*/
	GF_List *gf_sm_load_bt_from_string(GF_SceneGraph *in_scene, const char *node_str, Bool force_wrl);

	/*create a new scene*/
	osd->odm = gf_odm_new();
	osd->odm->term = osd->term;
	osd->odm->subscene = gf_scene_new(NULL);
	osd->odm->subscene->root_od = osd->odm;
	gf_sg_set_scene_size_info(osd->odm->subscene->graph, 0, 0, 1);

	/*create a scene graph*/
	nodes = gf_sm_load_bt_from_string(osd->odm->subscene->graph, osd_scene_graph, 0);
	n = gf_list_get(nodes, 0);
	gf_list_del(nodes);

	if (!n) return 0;
	
	gf_sg_set_root_node(osd->odm->subscene->graph, n);
	gf_sg_set_scene_size_info(osd->odm->subscene->graph, 0, 0, 1);

	hdl = gf_dom_listener_build(n, GF_EVENT_RESIZE, 0);
	hdl->handle_event = osd_on_resize;
	hdl->evt_listen_obj = osd;

	osd->visible = (M_Switch *)gf_sg_find_node_by_name(osd->odm->subscene->graph, "N1");
	osd->transform = (M_Transform2D *)gf_sg_find_node_by_name(osd->odm->subscene->graph, "N2");
	osd->ct2d = (M_CompositeTexture2D *)gf_sg_find_node_by_name(osd->odm->subscene->graph, "N3");
	osd->text = (M_Text *)gf_sg_find_node_by_name(osd->odm->subscene->graph, "N4");
	if (osd->text->string.vals[0]) {
		gf_free(osd->text->string.vals[0]);
		osd->text->string.vals[0] = NULL;
	}
	strcpy(osd->statBuffer, "Hello World !");
	osd->text->string.vals[0] = osd->statBuffer;

	opt = gf_cfg_get_key(osd->term->user->config, "OSD", "Visible");
	if (!opt || strcmp(opt, "yes")) osd->visible->whichChoice = -1;


	return 1;
}
Exemple #2
0
static void OnAnchor(SensorHandler *sh, Bool is_over, GF_Event *ev, RayHitInfo *hit_info)
{
	GF_Event evt;
	MFURL *url;
	AnchorStack *st = (AnchorStack *) gf_node_get_private(sh->owner);

	if ((ev->type==GF_EVENT_MOUSEDOWN) && (ev->mouse.button==GF_MOUSE_LEFT)) st->active = 1;
	else if (st->active && (ev->type==GF_EVENT_MOUSEUP) && (ev->mouse.button==GF_MOUSE_LEFT) ) {
		u32 i;
		if (gf_node_get_tag(sh->owner)==TAG_MPEG4_Anchor) {
			url = & ((M_Anchor *)sh->owner)->url;
			evt.navigate.param_count = ((M_Anchor *)sh->owner)->parameter.count;
			evt.navigate.parameters = (const char **) ((M_Anchor *)sh->owner)->parameter.vals;
		} else {
			url = & ((X_Anchor *)sh->owner)->url;
			evt.navigate.param_count = ((X_Anchor *)sh->owner)->parameter.count;
			evt.navigate.parameters = (const char **) ((X_Anchor *)sh->owner)->parameter.vals;
		}
		evt.type = GF_EVENT_NAVIGATE;
		i=0;
		while (i<url->count) {
			evt.navigate.to_url = url->vals[i].url;
			if (!evt.navigate.to_url) break;
			/*current scene navigation*/
			if (evt.navigate.to_url[0] == '#') {
				GF_Node *bindable;
				evt.navigate.to_url++;
				bindable = gf_sg_find_node_by_name(gf_node_get_graph(sh->owner), (char *) evt.navigate.to_url);
				if (bindable) {
					Bindable_SetSetBind(bindable, 1);
					break;
				}
			} else if (st->compositor->term) {
				if (gf_is_process_anchor(sh->owner, &evt))
					break;
			} else if (st->compositor->user->EventProc) {
				if (st->compositor->user->EventProc(st->compositor->user->opaque, &evt))
					break;
			}
			i++;
		}
	} else if (ev->type==GF_EVENT_MOUSEMOVE) {
		if (st->compositor->user->EventProc) {
			evt.type = GF_EVENT_NAVIGATE_INFO;
			if (gf_node_get_tag(sh->owner)==TAG_MPEG4_Anchor) {
				evt.navigate.to_url = ((M_Anchor *)sh->owner)->description.buffer;
				url = & ((M_Anchor *)sh->owner)->url;
			} else {
				evt.navigate.to_url = ((X_Anchor *)sh->owner)->description.buffer;
				url = & ((X_Anchor *)sh->owner)->url;
			}
			if (!evt.navigate.to_url || !strlen(evt.navigate.to_url)) evt.navigate.to_url = url->vals[0].url;
			st->compositor->user->EventProc(st->compositor->user->opaque, &evt);
		}
	}
}
Exemple #3
0
GF_Node *compositor_svg_get_xlink_resource_node(GF_Node *node, XMLRI *xlink)
{
	SVGlinkStack *stack;
	switch (gf_node_get_tag(node)) {
	case TAG_SVG_animation:
		stack = gf_node_get_private(node);
		return gf_sg_get_root_node(stack->inline_sg);
	case TAG_SVG_use:
		stack = gf_node_get_private(node);
		if (stack && stack->fragment_id)
			return gf_sg_find_node_by_name(stack->inline_sg, (char *) stack->fragment_id+1);
		return xlink ? xlink->target : NULL;
	}
	return NULL;
}
Exemple #4
0
/* Tries to resolve event-based or sync-based time values
   Used in parsing, to determine if a timed element can be initialized */
Bool gf_svg_resolve_smil_times(GF_Node *anim, void *event_base_element, 
							GF_List *smil_times, Bool is_end, const char *node_name)
{
	u32 i, done, count;

	done = 0;
	count = gf_list_count(smil_times);
	for (i=0; i<count; i++) {
		SMIL_Time *t = (SMIL_Time *)gf_list_get(smil_times, i);

		if (t->type != GF_SMIL_TIME_EVENT) {
			done++;
			continue;
		}
		if (!t->element_id) {
			if (!t->element) t->element = (GF_Node *)event_base_element;
			done++;
			continue;
		}
		/*commented out because it breaks regular anims (cf interact-pevents-07-t.svg)*/
//		if (node_name && strcmp(node_name, t->element_id)) continue;
	
		t->element = gf_sg_find_node_by_name(anim->sgprivate->scenegraph, t->element_id);
		if (t->element) {
			gf_free(t->element_id);
			t->element_id = NULL;
			done++;
		}
	}
	/*lacuna value of discard is 0*/
	if (!count && !is_end && (anim->sgprivate->tag==TAG_SVG_discard) ) {
		SMIL_Time *t;
		GF_SAFEALLOC(t, SMIL_Time);
		t->clock = 0;
		t->type = GF_SMIL_TIME_CLOCK;
		gf_list_add(smil_times, t);
		return 1;
	}

	if (done!=count) return 0;
	return 1;
}
Exemple #5
0
GF_EXPORT
GF_Err gf_bifs_encoder_new_stream(GF_BifsEncoder *codec, u16 ESID, GF_BIFSConfig *cfg, Bool encodeNames, Bool has_predictive)
{
	u32 i, count;
	BIFSStreamInfo *pInfo;

//	gf_mx_p(codec->mx);
	if (BE_GetStream(codec, ESID) != NULL) {
//		gf_mx_v(codec->mx);
		return GF_BAD_PARAM;
	}

	GF_SAFEALLOC(pInfo, BIFSStreamInfo);
	pInfo->ESID = ESID;
	codec->UseName = encodeNames;
	pInfo->config.Height = cfg->pixelHeight;
	pInfo->config.Width = cfg->pixelWidth;
	pInfo->config.NodeIDBits = cfg->nodeIDbits;
	pInfo->config.RouteIDBits = cfg->routeIDbits;
	pInfo->config.ProtoIDBits = cfg->protoIDbits;
	pInfo->config.PixelMetrics = cfg->pixelMetrics;
	pInfo->config.version = (has_predictive || cfg->protoIDbits) ? 2 : 1;
	pInfo->config.UsePredictiveMFField = has_predictive;

	if (cfg->elementaryMasks) {
		pInfo->config.elementaryMasks = gf_list_new();
		count = gf_list_count(cfg->elementaryMasks);
		for (i=0; i<count; i++) {
			BIFSElementaryMask *bem;
			GF_ElementaryMask *em = (GF_ElementaryMask *)gf_list_get(cfg->elementaryMasks, i);
			GF_SAFEALLOC(bem, BIFSElementaryMask);
			if (em->node_id) bem->node = gf_sg_find_node(codec->scene_graph, em->node_id);
			else if (em->node_name) bem->node = gf_sg_find_node_by_name(codec->scene_graph, em->node_name);
			bem->node_id = em->node_id;
			gf_list_add(pInfo->config.elementaryMasks, bem);
		}
	}

	gf_list_add(codec->streamInfo, pInfo);
//	gf_mx_v(codec->mx);
	return GF_OK;
}
Exemple #6
0
static void anchor_activation(GF_Node *node, AnchorStack *st, GF_Compositor *compositor)
{
	GF_Event evt;
	u32 i;
	MFURL *url = NULL;
	switch (gf_node_get_tag(node)) {
	case TAG_MPEG4_Anchor:
		url = & ((M_Anchor *)node)->url;
		evt.navigate.param_count = ((M_Anchor *)node)->parameter.count;
		evt.navigate.parameters = (const char **) ((M_Anchor *)node)->parameter.vals;
		break;
#ifndef GPAC_DISABLE_X3D
	case TAG_X3D_Anchor:
		url = & ((X_Anchor *)node)->url;
		evt.navigate.param_count = ((X_Anchor *)node)->parameter.count;
		evt.navigate.parameters = (const char **) ((X_Anchor *)node)->parameter.vals;
		break;
#endif
	}
	evt.type = GF_EVENT_NAVIGATE;
	i=0;
	while (url && i<url->count) {
		evt.navigate.to_url = url->vals[i].url;
		if (!evt.navigate.to_url) break;
		/*current scene navigation*/
		if (evt.navigate.to_url[0] == '#') {
			GF_Node *bindable;
			evt.navigate.to_url++;
			bindable = gf_sg_find_node_by_name(gf_node_get_graph(node), (char *) evt.navigate.to_url);
			if (bindable) {
				Bindable_SetSetBind(bindable, 1);
				break;
			}
		} else if (compositor->term) {
			if (gf_scene_process_anchor(node, &evt))
				break;
		} else if (gf_term_send_event(compositor->term, &evt)) {
			break;
		}
		i++;
	}
}
Exemple #7
0
GF_EXPORT
Bool gf_mo_get_visual_info(GF_MediaObject *mo, u32 *width, u32 *height, u32 *stride, u32 *pixel_ar, u32 *pixelFormat, Bool *is_flipped)
{
	GF_CodecCapability cap;
	if ((mo->type != GF_MEDIA_OBJECT_VIDEO) && (mo->type!=GF_MEDIA_OBJECT_TEXT)) return GF_FALSE;

	if (width) {
		cap.CapCode = GF_CODEC_WIDTH;
		gf_codec_get_capability(mo->odm->codec, &cap);
		*width = cap.cap.valueInt;
	}
	if (height) {
		cap.CapCode = GF_CODEC_HEIGHT;
		gf_codec_get_capability(mo->odm->codec, &cap);
		*height = cap.cap.valueInt;
	}
	if (mo->type==GF_MEDIA_OBJECT_TEXT) return GF_TRUE;

	if (is_flipped) {
		cap.CapCode = GF_CODEC_FLIP;
		cap.cap.valueInt = 0;
		gf_codec_get_capability(mo->odm->codec, &cap);
		*is_flipped = cap.cap.valueInt ? GF_TRUE : GF_FALSE;
	}

	if (stride) {
		cap.CapCode = GF_CODEC_STRIDE;
		gf_codec_get_capability(mo->odm->codec, &cap);
		*stride = cap.cap.valueInt;
	}
	if (pixelFormat) {
		cap.CapCode = GF_CODEC_PIXEL_FORMAT;
		gf_codec_get_capability(mo->odm->codec, &cap);
		*pixelFormat = cap.cap.valueInt;

		if (mo->odm && mo->odm->parentscene->is_dynamic_scene) {
#ifndef GPAC_DISABLE_VRML
			const char *name = gf_node_get_name(gf_event_target_get_node(gf_mo_event_target_get(mo, 0)));
			if (name && !strcmp(name, "DYN_VIDEO")) {
				const char *opt;
				u32 r, g, b, a;
				M_Background2D *back = (M_Background2D *) gf_sg_find_node_by_name(mo->odm->parentscene->graph, "DYN_BACK");
				if (back) {
					switch (cap.cap.valueInt) {
					case GF_PIXEL_ARGB:
					case GF_PIXEL_RGBA:
					case GF_PIXEL_YUVA:
						opt = gf_cfg_get_key(mo->odm->term->user->config, "Compositor", "BackColor");
						if (!opt) {
							gf_cfg_set_key(mo->odm->term->user->config, "Compositor", "BackColor", "FF999999");
							opt = "FF999999";
						}
						sscanf(opt, "%02X%02X%02X%02X", &a, &r, &g, &b);
						back->backColor.red = INT2FIX(r)/255;
						back->backColor.green = INT2FIX(g)/255;
						back->backColor.blue = INT2FIX(b)/255;
						break;
					default:
						back->backColor.red = back->backColor.green = back->backColor.blue = 0;
						break;
					}
					gf_node_dirty_set((GF_Node *)back, 0, GF_TRUE);
				}
			}
#endif
		}
	}
	/*get PAR settings*/
	if (pixel_ar) {
		cap.CapCode = GF_CODEC_PAR;
		gf_codec_get_capability(mo->odm->codec, &cap);
		*pixel_ar = cap.cap.valueInt;
		if (! (*pixel_ar & 0x0000FFFF)) *pixel_ar = 0;
		if (! (*pixel_ar & 0xFFFF0000)) *pixel_ar = 0;

		/**/
		if (! *pixel_ar) {
			GF_Channel *ch;
			GF_NetworkCommand com;
			com.base.command_type = GF_NET_CHAN_GET_PIXEL_AR;
			ch = (GF_Channel *)gf_list_get(mo->odm->channels, 0);
			if (!ch) return GF_FALSE;

			com.base.on_channel = ch;
			com.par.hSpacing = com.par.vSpacing = 0;
			if (gf_term_service_command(ch->service, &com) == GF_OK) {
				if ((com.par.hSpacing>65535) || (com.par.vSpacing>65535)) {
					com.par.hSpacing>>=16;
					com.par.vSpacing>>=16;
				}
				if (com.par.hSpacing|| com.par.vSpacing)
					*pixel_ar = (com.par.hSpacing<<16) | com.par.vSpacing;
			}
		}
Exemple #8
0
static Bool OnAnchor(SensorHandler *sh, GF_Event *evt, DrawableContext *ctx, GF_Matrix2D *sensor_matrix)
{
	u32 i;
	GF_Event event;
	AnchorStack *st = (AnchorStack *) gf_node_get_private(sh->owner);
	M_Anchor *an = (M_Anchor *) sh->owner;

	if (ctx==NULL) {
		event.type = GF_EVENT_NAVIGATE_INFO;
		event.navigate.to_url = "";
		st->compositor->user->EventProc(st->compositor->user->opaque, &event);
		st->is_over = 0;
		return 0;
	}

	if (evt->type == GF_EVENT_MOUSEMOVE) {
		if (!st->is_over && st->compositor->user->EventProc) {
			event.type = GF_EVENT_NAVIGATE_INFO;
			event.navigate.to_url = an->description.buffer;
			if (!event.navigate.to_url || !strlen(event.navigate.to_url)) event.navigate.to_url = an->url.vals[0].url;
			st->compositor->user->EventProc(st->compositor->user->opaque, &event);
		}
		st->is_over = 1;
		return 0;
	}

	if ((evt->type != GF_EVENT_MOUSEUP) || (evt->mouse.button != GF_MOUSE_LEFT)) return 0;

	event.type = GF_EVENT_NAVIGATE;
	event.navigate.param_count = an->parameter.count;
	event.navigate.parameters = (const char **) an->parameter.vals;
	i=0;
	while (i<an->url.count) {
		event.navigate.to_url = an->url.vals[i].url;
		if (!event.navigate.to_url) break;
		/*current scene navigation*/
		if (event.navigate.to_url[0] == '#') {
			GF_Node *n;
			event.navigate.to_url++;
			n = gf_sg_find_node_by_name(gf_node_get_graph(sh->owner), (char *) event.navigate.to_url);
			if (n) {
				switch (gf_node_get_tag(n)) {
				case TAG_MPEG4_Viewport:
					((M_Viewport *)n)->set_bind = 1;
					((M_Viewport *)n)->on_set_bind(n);
					break;
				}
				break;
			}
		} else if (st->compositor->term) {
			if (gf_is_process_anchor(sh->owner, &event))
				break;
		} else if (st->compositor->user->EventProc) {
			if (st->compositor->user->EventProc(st->compositor->user->opaque, &event))
				break;
		}

		i++;
	}
	return 0;
}
Exemple #9
0
static void svg_parse_animation(GF_SceneGraph *sg, SVG_DeferedAnimation *anim)
{
    GF_FieldInfo info;
    u32 tag;
    u8 anim_value_type = 0;

    if (anim->resolve_stage==0) {
        /* Stage 0: parsing the animation attribute values
        			for that we need to resolve the target first */
        if (!anim->target)
            anim->target = (SVG_Element *) gf_sg_find_node_by_name(sg, anim->target_id + 1);

        if (!anim->target) {
            /* the target is still not known stay in stage 0 */
            return;
        } else {
            XMLRI *iri;
            gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_XLINK_ATT_href, 1, 0, &info);
            iri = (XMLRI *)info.far_ptr;
            iri->type = XMLRI_ELEMENTID;
            iri->target = anim->target;
            gf_node_register_iri(sg, iri);
        }

        tag = gf_node_get_tag((GF_Node *)anim->animation_elt);
        /* get the attribute name attribute if specified */
        if (anim->type && (tag== TAG_SVG_animateTransform) ) {
            gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_transform_type, 1, 0, &info);
            gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->type, 0);
            switch(*(SVG_TransformType *) info.far_ptr) {
            case SVG_TRANSFORM_TRANSLATE:
                anim_value_type = SVG_Transform_Translate_datatype;
                break;
            case SVG_TRANSFORM_SCALE:
                anim_value_type = SVG_Transform_Scale_datatype;
                break;
            case SVG_TRANSFORM_ROTATE:
                anim_value_type = SVG_Transform_Rotate_datatype;
                break;
            case SVG_TRANSFORM_SKEWX:
                anim_value_type = SVG_Transform_SkewX_datatype;
                break;
            case SVG_TRANSFORM_SKEWY:
                anim_value_type = SVG_Transform_SkewY_datatype;
                break;
            case SVG_TRANSFORM_MATRIX:
                anim_value_type = SVG_Transform_datatype;
                break;
            default:
                fprintf(stdout, "unknown datatype for animate transform");
                return;
            }
        }
        else if (gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_attributeName, 0, 0, &info) == GF_OK) {
            gf_node_get_attribute_by_name((GF_Node *)anim->target, ((SMIL_AttributeName *)info.far_ptr)->name, 0, 1, 1, &info);
            anim_value_type = info.fieldType;
        } else {
            if (tag == TAG_SVG_animateMotion) {
                anim_value_type = SVG_Motion_datatype;
            } else if (tag == TAG_SVG_discard) {
                /* there is no value to parse in discard, we can jump to the next stage */
                anim->resolve_stage = 1;
                svg_parse_animation(sg, anim);
                return;
            } else {
                fprintf(stdout, "Missing attributeName attribute on %s", gf_node_get_name((GF_Node *)anim->animation_elt));
                return;
            }
        }

        if (anim->to) {
            gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_to, 1, 0, &info);
            gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->to, anim_value_type);
        }
        if (anim->from) {
            gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_from, 1, 0, &info);
            gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->from, anim_value_type);
        }
        if (anim->by) {
            gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_by, 1, 0, &info);
            gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->by, anim_value_type);
        }
        if (anim->values) {
            gf_node_get_attribute_by_tag((GF_Node *)anim->animation_elt, TAG_SVG_ATT_values, 1, 0, &info);
            gf_svg_parse_attribute((GF_Node *)anim->animation_elt, &info, anim->values, anim_value_type);
        }
        anim->resolve_stage = 1;
    }
}
Exemple #10
0
static GF_Err gf_text_import_srt_bifs(GF_SceneManager *ctx, GF_ESD *src, GF_MuxInfo *mux)
{
	GF_Err e;
	GF_Node *text, *font;
	GF_StreamContext *srt;
	FILE *srt_in;
	GF_FieldInfo string, style;
	u32 sh, sm, ss, sms, eh, em, es, ems, start, end;
	GF_AUContext *au;
	GF_Command *com;
	SFString *sfstr;
	GF_CommandField *inf;
	Bool italic, underlined, bold;
	u32 state, curLine, line, i, len;
	char szLine[2048], szText[2048], *ptr;
	GF_StreamContext *sc = NULL;

	if (!ctx->scene_graph) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] base scene not assigned\n"));
		return GF_BAD_PARAM;
	}
	i=0;
	while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) {
		if (sc->streamType==GF_STREAM_SCENE) break;
		sc = NULL;
	}

	if (!sc) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot locate base scene\n"));
		return GF_BAD_PARAM;
	}
	if (!mux->textNode) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Target text node unspecified\n"));
		return GF_BAD_PARAM;
	}
	text = gf_sg_find_node_by_name(ctx->scene_graph, mux->textNode);
	if (!text) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot find target text node %s\n", mux->textNode));
		return GF_BAD_PARAM;
	}
	if (gf_node_get_field_by_name(text, "string", &string) != GF_OK) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Target text node %s doesn't look like text\n", mux->textNode));
		return GF_BAD_PARAM;
	}

	font = NULL;
	if (mux->fontNode) {
		font = gf_sg_find_node_by_name(ctx->scene_graph, mux->fontNode);
		if (!font) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot find target font node %s\n", mux->fontNode));
			return GF_BAD_PARAM;
		}
		if (gf_node_get_field_by_name(font, "style", &style) != GF_OK) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Target font node %s doesn't look like font\n", mux->fontNode));
			return GF_BAD_PARAM;
		}
	}

	srt_in = gf_f64_open(mux->file_name, "rt");
	if (!srt_in) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot open input file %s\n", mux->file_name));
		return GF_URL_ERROR;
	}

	srt = gf_sm_stream_new(ctx, src->ESID, GF_STREAM_SCENE, 1);
	if (!srt) return GF_OUT_OF_MEM;

	if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG);
	src->slConfig->timestampResolution = 1000;
	if (!src->decoderConfig) src->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG);
	src->decoderConfig->streamType = GF_STREAM_SCENE;
	src->decoderConfig->objectTypeIndication = 1;

	e = GF_OK;
	state = end = 0;
	curLine = 0;
	au = NULL;
	com = NULL;
	italic = underlined = bold = 0;
	inf = NULL;

	while (1) {
		char *sOK = fgets(szLine, 2048, srt_in);

		if (sOK) REM_TRAIL_MARKS(szLine, "\r\n\t ")

			if (!sOK || !strlen(szLine)) {
				state = 0;
				if (au) {
					/*if italic or underscore do it*/
					if (font && (italic || underlined || bold)) {
						com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE);
						com->node = font;
						gf_node_register(font, NULL);
						inf = gf_sg_command_field_new(com);
						inf->fieldIndex = style.fieldIndex;
						inf->fieldType = style.fieldType;
						inf->field_ptr = gf_sg_vrml_field_pointer_new(style.fieldType);
						sfstr = (SFString *)inf->field_ptr;
						if (bold && italic && underlined) sfstr->buffer = gf_strdup("BOLDITALIC UNDERLINED");
						else if (italic && underlined) sfstr->buffer = gf_strdup("ITALIC UNDERLINED");
						else if (bold && underlined) sfstr->buffer = gf_strdup("BOLD UNDERLINED");
						else if (underlined) sfstr->buffer = gf_strdup("UNDERLINED");
						else if (bold && italic) sfstr->buffer = gf_strdup("BOLDITALIC");
						else if (bold) sfstr->buffer = gf_strdup("BOLD");
						else sfstr->buffer = gf_strdup("ITALIC");
						gf_list_add(au->commands, com);
					}

					au = gf_sm_stream_au_new(srt, end, 0, 1);
					com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE);
					com->node = text;
					gf_node_register(text, NULL);
					inf = gf_sg_command_field_new(com);
					inf->fieldIndex = string.fieldIndex;
					inf->fieldType = string.fieldType;
					inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType);
					gf_list_add(au->commands, com);
					/*reset font styles so that all AUs are true random access*/
					if (font) {
						com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE);
						com->node = font;
						gf_node_register(font, NULL);
						inf = gf_sg_command_field_new(com);
						inf->fieldIndex = style.fieldIndex;
						inf->fieldType = style.fieldType;
						inf->field_ptr = gf_sg_vrml_field_pointer_new(style.fieldType);
						gf_list_add(au->commands, com);
					}
					au = NULL;
				}
				inf = NULL;
				if (!sOK) break;
				continue;
			}

		switch (state) {
		case 0:
			if (sscanf(szLine, "%u", &line) != 1) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] bad frame format (src: %s)\n", szLine));
				e = GF_CORRUPTED_DATA;
				goto exit;
			}
			if (line != curLine + 1) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] bad frame: previous %d - current %d (src: %s)\n", curLine, line, szLine));
				e = GF_CORRUPTED_DATA;
				goto exit;
			}
			curLine = line;
			state = 1;
			break;
		case 1:
			if (sscanf(szLine, "%u:%u:%u,%u --> %u:%u:%u,%u", &sh, &sm, &ss, &sms, &eh, &em, &es, &ems) != 8) {
				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] bad frame %u (src: %s)\n", curLine, szLine));
				e = GF_CORRUPTED_DATA;
				goto exit;
			}
			start = (3600*sh + 60*sm + ss)*1000 + sms;
			if (start<end) {
				GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[srt->bifs] corrupted frame starts before end of previous one (SRT Frame %d) - adjusting time stamps\n", curLine));
				start = end;
			}
			end = (3600*eh + 60*em + es)*1000 + ems;
			/*make stream start at 0 by inserting a fake AU*/
			if ((curLine==1) && start>0) {
				au = gf_sm_stream_au_new(srt, 0, 0, 1);
				com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE);
				com->node = text;
				gf_node_register(text, NULL);
				inf = gf_sg_command_field_new(com);
				inf->fieldIndex = string.fieldIndex;
				inf->fieldType = string.fieldType;
				inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType);
				gf_list_add(au->commands, com);
			}

			au = gf_sm_stream_au_new(srt, start, 0, 1);
			com = NULL;
			state = 2;
			italic = underlined = bold = 0;
			break;

		default:
			ptr = szLine;
			/*FIXME - other styles posssibles ??*/
			while (1) {
				if (!strnicmp(ptr, "<i>", 3)) {
					italic = 1;
					ptr += 3;
				}
				else if (!strnicmp(ptr, "<u>", 3)) {
					underlined = 1;
					ptr += 3;
				}
				else if (!strnicmp(ptr, "<b>", 3)) {
					bold = 1;
					ptr += 3;
				}
				else
					break;
			}
			/*if style remove end markers*/
			while ((strlen(ptr)>4) && (ptr[strlen(ptr) - 4] == '<') && (ptr[strlen(ptr) - 1] == '>')) {
				ptr[strlen(ptr) - 4] = 0;
			}

			if (!com) {
				com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE);
				com->node = text;
				gf_node_register(text, NULL);
				inf = gf_sg_command_field_new(com);
				inf->fieldIndex = string.fieldIndex;
				inf->fieldType = string.fieldType;
				inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType);
				gf_list_add(au->commands, com);
			}
			assert(inf);
			gf_sg_vrml_mf_append(inf->field_ptr, GF_SG_VRML_MFSTRING, (void **) &sfstr);
			len = 0;
			for (i=0; i<strlen(ptr); i++) {
				/*FIXME - UTF16 support !!*/
				if (ptr[i] & 0x80) {
					/*non UTF8 (likely some win-CP)*/
					if ((ptr[i+1] & 0xc0) != 0x80) {
						szText[len] = 0xc0 | ( (ptr[i] >> 6) & 0x3 );
						len++;
						ptr[i] &= 0xbf;
					}
					/*we only handle UTF8 chars on 2 bytes (eg first byte is 0b110xxxxx)*/
					else if ((ptr[i] & 0xe0) == 0xc0) {
						szText[len] = ptr[i];
						len++;
						i++;
					}
				}
				szText[len] = ptr[i];
				len++;
			}
			szText[len] = 0;
			sfstr->buffer = gf_strdup(szText);
			break;
		}
Exemple #11
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;
}
Exemple #12
0
static void svg_a_handle_event(GF_Node *handler, GF_DOM_Event *event, GF_Node *observer)
{
	GF_Compositor *compositor;
	GF_Event evt;
	SVG_Element *a;
	SVGAllAttributes all_atts;

	if (event->event_phase & GF_DOM_EVENT_PHASE_PREVENT) return;

	assert(gf_node_get_tag((GF_Node*)event->currentTarget->ptr)==TAG_SVG_a);
	a = (SVG_Element *) event->currentTarget->ptr;
	gf_svg_flatten_attributes(a, &all_atts);

	compositor = (GF_Compositor *)gf_node_get_private((GF_Node *)handler);

	if (!compositor->user->EventProc) return;
	if (!all_atts.xlink_href) return;

	if (event->type==GF_EVENT_MOUSEOVER) {
		evt.type = GF_EVENT_NAVIGATE_INFO;
		
		if (all_atts.xlink_title) evt.navigate.to_url = *all_atts.xlink_title;
		else if (all_atts.xlink_href->string) evt.navigate.to_url = all_atts.xlink_href->string;
		else {
			evt.navigate.to_url = gf_node_get_name(all_atts.xlink_href->target);
			if (!evt.navigate.to_url) evt.navigate.to_url = "document internal link";
		}

		gf_term_send_event(compositor->term, &evt);
		return;
	}

	evt.type = GF_EVENT_NAVIGATE;
	
	if (all_atts.xlink_href->type == XMLRI_STRING) {
		evt.navigate.to_url = gf_term_resolve_xlink(handler, all_atts.xlink_href->string);
		if (evt.navigate.to_url) {
			if (all_atts.target) {
				evt.navigate.parameters = (const char **) &all_atts.target;
				evt.navigate.param_count = 1;
			} else {
				evt.navigate.parameters = NULL;
				evt.navigate.param_count = 0;
			}

			if (evt.navigate.to_url[0] != '#') {
				if (compositor->term) {
					gf_scene_process_anchor(handler, &evt);
				} else {
					gf_term_send_event(compositor->term, &evt);
				}
				gf_free((char *)evt.navigate.to_url);
				return;
			}
			all_atts.xlink_href->target = gf_sg_find_node_by_name(gf_node_get_graph(handler), (char *) evt.navigate.to_url+1);
			if (all_atts.xlink_href->target) {
				all_atts.xlink_href->type = XMLRI_ELEMENTID;
				gf_free((char *)evt.navigate.to_url);
			} else {
				svg_a_set_view(handler, compositor, evt.navigate.to_url + 1);
				gf_free((char *)evt.navigate.to_url);
				return;
			}
		}
	}
	if (!all_atts.xlink_href->target) {
		return;
	} 
	/*this is a time event*/
	if (is_timing_target(all_atts.xlink_href->target)) {
		gf_smil_timing_insert_clock(all_atts.xlink_href->target, 0, gf_node_get_scene_time((GF_Node *)handler) );
	} 
	/*this is an implicit SVGView event*/
	else {
		svg_a_set_view(handler, compositor, gf_node_get_name(all_atts.xlink_href->target));
	}
}
Exemple #13
0
static void svg_recompute_viewport_transformation(GF_Node *node, SVGsvgStack *stack, GF_TraverseState *tr_state, SVGAllAttributes *atts) 
{
	GF_Matrix2D mx;
	SVG_ViewBox ext_vb, *vb;
	SVG_PreserveAspectRatio par;
	Fixed scale, vp_w, vp_h;
	Fixed parent_width, parent_height, doc_width, doc_height;

	/*canvas size negociation has already been done when attaching the scene to the compositor*/
	if (atts->width && (atts->width->type==SVG_NUMBER_PERCENTAGE) ) { 
		parent_width = gf_mulfix(tr_state->vp_size.x, atts->width->value/100);
		doc_width = 0;
	} else if (!stack->root_svg) {
		doc_width = parent_width = atts->width ? atts->width->value : 0;
	} else {
		parent_width = tr_state->vp_size.x;
		doc_width = atts->width ? atts->width->value : 0;
	}

	if (atts->height && (atts->height->type==SVG_NUMBER_PERCENTAGE) ) { 
		parent_height = gf_mulfix(tr_state->vp_size.y, atts->height->value/100);
		doc_height = 0;
	} else if (!stack->root_svg) {
		doc_height = parent_height = atts->height ? atts->height->value : 0;
	} else {
		parent_height = tr_state->vp_size.y;
		doc_height = atts->height ? atts->height->value : 0;
	}

	stack->vp = stack->parent_vp = tr_state->vp_size;

	vb = atts->viewBox;

	gf_mx2d_init(mx);

	if (stack->root_svg) {
		const char *frag_uri = gf_scene_get_fragment_uri(node);
		if (frag_uri) {
			/*SVGView*/
			if (!strncmp(frag_uri, "svgView", 7)) {
				if (!strncmp(frag_uri, "svgView(viewBox(", 16)) {
					Float x, y, w, h;
					sscanf(frag_uri, "svgView(viewBox(%f,%f,%f,%f))", &x, &y, &w, &h);
					ext_vb.x = FLT2FIX(x);
					ext_vb.y = FLT2FIX(y);
					ext_vb.width = FLT2FIX(w);
					ext_vb.height = FLT2FIX(h);
					ext_vb.is_set = 1;
					vb = &ext_vb;
				}
				else if (!strncmp(frag_uri, "svgView(transform(", 18)) {
					Bool ret = gf_svg_parse_transformlist(&mx, (char *) frag_uri+18);
                    if (!ret) {
                        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error parsing SVG View transform component: %s\n", frag_uri+18));
                    }
				}
			}
			/*fragID*/
			else {
				GF_Node *target = gf_sg_find_node_by_name(gf_node_get_graph(node), (char *) frag_uri);
				if (target) {
					GF_Matrix2D mx;
					GF_TraverseState bounds_state;
					memset(&bounds_state, 0, sizeof(bounds_state));
					bounds_state.traversing_mode = TRAVERSE_GET_BOUNDS;
					bounds_state.visual = tr_state->visual;
					bounds_state.for_node = target;
					bounds_state.svg_props = tr_state->svg_props;
					gf_mx2d_init(bounds_state.transform);
					gf_mx2d_init(bounds_state.mx_at_node);
					gf_mx_init(tr_state->visual->compositor->hit_world_to_local);
					gf_sc_get_nodes_bounds(node, ((GF_ParentNode *)node)->children, &bounds_state, NULL);
					gf_mx2d_from_mx(&mx, &tr_state->visual->compositor->hit_world_to_local);
					gf_mx2d_apply_rect(&mx, &bounds_state.bounds);
					ext_vb.x = bounds_state.bounds.x;
					ext_vb.y = bounds_state.bounds.y-bounds_state.bounds.height;
					ext_vb.width = bounds_state.bounds.width;
					ext_vb.height = bounds_state.bounds.height;
					ext_vb.is_set = 1;
					vb = &ext_vb;
				}
			}
		}
	}
	gf_mx2d_init(stack->viewbox_mx);

	if (!vb) {
		if (!doc_width || !doc_height) {
			gf_mx2d_copy(stack->viewbox_mx, mx);
			return;
		}
		/*width/height were specified in the doc, use them to compute a dummy viewbox*/
		ext_vb.x = 0;
		ext_vb.y = 0;
		ext_vb.width = doc_width;
		ext_vb.height = doc_height;
		ext_vb.is_set = 1;
		vb = &ext_vb;
	}
	if ((vb->width<=0) || (vb->height<=0) ) {
		gf_mx2d_copy(stack->viewbox_mx, mx);
		return;
	}
	stack->vp.x = vb->width;
	stack->vp.y = vb->height;

	/*setup default*/
	par.defer = 0;
	par.meetOrSlice = SVG_MEETORSLICE_MEET;
	par.align = SVG_PRESERVEASPECTRATIO_XMIDYMID;

	/*use parent (animation, image) viewport settings*/
	if (tr_state->parent_anim_atts) {
		if (tr_state->parent_anim_atts->preserveAspectRatio) {
			if (tr_state->parent_anim_atts->preserveAspectRatio->defer) {
				if (atts->preserveAspectRatio) 
					par = *atts->preserveAspectRatio;
			} else {
				par = *tr_state->parent_anim_atts->preserveAspectRatio;
			}
		}
	}
	/*use current viewport settings*/
	else if (atts->preserveAspectRatio) {
		par = *atts->preserveAspectRatio;
	}

	if (par.meetOrSlice==SVG_MEETORSLICE_MEET) {
		if (gf_divfix(parent_width, vb->width) > gf_divfix(parent_height, vb->height)) {
			scale = gf_divfix(parent_height, vb->height);
			vp_w = gf_mulfix(vb->width, scale);
			vp_h = parent_height;
		} else {
			scale = gf_divfix(parent_width, vb->width);
			vp_w = parent_width;
			vp_h = gf_mulfix(vb->height, scale);
		}
	} else {
		if (gf_divfix(parent_width, vb->width) < gf_divfix(parent_height, vb->height)) {
			scale = gf_divfix(parent_height, vb->height);
			vp_w = gf_mulfix(vb->width, scale);
			vp_h = parent_height;
		} else {
			scale = gf_divfix(parent_width, vb->width);
			vp_w = parent_width;
			vp_h = gf_mulfix(vb->height, scale);
		}
	}

	if (par.align==SVG_PRESERVEASPECTRATIO_NONE) {
		stack->viewbox_mx.m[0] = gf_divfix(parent_width, vb->width);
		stack->viewbox_mx.m[4] = gf_divfix(parent_height, vb->height);
		stack->viewbox_mx.m[2] = - gf_muldiv(vb->x, parent_width, vb->width); 
		stack->viewbox_mx.m[5] = - gf_muldiv(vb->y, parent_height, vb->height); 
	} else {
		Fixed dx, dy;
		stack->viewbox_mx.m[0] = stack->viewbox_mx.m[4] = scale;
		stack->viewbox_mx.m[2] = - gf_mulfix(vb->x, scale); 
		stack->viewbox_mx.m[5] = - gf_mulfix(vb->y, scale); 

		dx = dy = 0;
		switch (par.align) {
		case SVG_PRESERVEASPECTRATIO_XMINYMIN:
			break;
		case SVG_PRESERVEASPECTRATIO_XMIDYMIN:
			dx = ( parent_width - vp_w) / 2; 
			break;
		case SVG_PRESERVEASPECTRATIO_XMAXYMIN:
			dx = parent_width - vp_w; 
			break;
		case SVG_PRESERVEASPECTRATIO_XMINYMID:
			dy = ( parent_height - vp_h) / 2; 
			break;
		case SVG_PRESERVEASPECTRATIO_XMIDYMID:
			dx = ( parent_width  - vp_w) / 2; 
			dy = ( parent_height - vp_h) / 2; 
			break;
		case SVG_PRESERVEASPECTRATIO_XMAXYMID:
			dx = parent_width  - vp_w; 
			dy = ( parent_height - vp_h) / 2; 
			break;
		case SVG_PRESERVEASPECTRATIO_XMINYMAX:
			dy = parent_height - vp_h; 
			break;
		case SVG_PRESERVEASPECTRATIO_XMIDYMAX:
			dx = (parent_width - vp_w) / 2; 
			dy = parent_height - vp_h; 
			break;
		case SVG_PRESERVEASPECTRATIO_XMAXYMAX:
			dx = parent_width  - vp_w; 
			dy = parent_height - vp_h; 
			break;
		}
		gf_mx2d_add_translation(&stack->viewbox_mx, dx, dy);
		stack->dx = dx;
		stack->dy = dy;
		stack->vpw = vp_w;
		stack->vph = vp_h;

		/*we need a clipper*/
		if (stack->root_svg && !tr_state->parent_anim_atts && (par.meetOrSlice==SVG_MEETORSLICE_SLICE)) {
			GF_Rect rc;
			rc.width = parent_width;
			rc.height = parent_height;
			if (!stack->root_svg) {
				rc.x = 0;
				rc.y = parent_height;
				gf_mx2d_apply_rect(&stack->viewbox_mx, &rc);
			} else {
				rc.x = dx;
				rc.y = dy + parent_height;
			}
//			tr_state->visual->top_clipper = gf_rect_pixelize(&rc);
		}
	}
	gf_mx2d_add_matrix(&stack->viewbox_mx, &mx);
}