Пример #1
0
Файл: main.c Проект: erelh/gpac
static void svg2bifs_node_end(void *sax_cbck, const char *name, const char *name_space)
{
	SVG2BIFS_Converter *converter = (SVG2BIFS_Converter *)sax_cbck;
	GF_Node *parent;

	SVGPropertiesPointers *backup_props = gf_node_get_private(converter->svg_parent);
	memcpy(&converter->svg_props, backup_props, sizeof(SVGPropertiesPointers));
//	gf_free(backup_props);
	gf_node_set_private(converter->svg_parent, NULL);

	if (!(gf_node_get_tag(converter->svg_parent) == TAG_SVG_animateTransform))
		converter->bifs_parent = gf_node_get_parent(converter->bifs_parent, 0);
	parent = gf_node_get_parent(converter->svg_parent, 0);
	gf_node_unregister(converter->svg_parent, parent);
	if (!parent) gf_sg_set_root_node(converter->svg_sg, NULL);
	converter->svg_parent = parent;
	converter->bifs_text_node = NULL;

	fprintf(stdout, "END:\t%s\t%s\n", converter->svg_parent ? gf_node_get_class_name(converter->svg_parent) : "none", converter->bifs_parent ? gf_node_get_class_name(converter->bifs_parent) : "none");
}
Пример #2
0
// HasDefParent -- checks if an ancestor of this node has an ID
GF_Node * V4SceneManager::HasDefParent(GF_Node * node) {
  
  assert(node);

  // also checks the node itself

  int count = gf_node_get_parent_count(node);
  GF_Node * parent;

  // loops through all the parents and recurses
  for (int i=0; i<count; i++) {
    parent = gf_node_get_parent(node, i);
    const char * name = gf_node_get_name(parent);
    if (name) return parent;

    parent = HasDefParent(parent);
    if (parent) return parent;
  }

  return NULL;
}
Пример #3
0
char *gf_term_resolve_xlink(GF_Node *node, char *the_url)
{
	char *url;
	GF_Scene *scene = gf_sg_get_private(gf_node_get_graph(node));
	if (!scene) return NULL;

	url = gf_strdup(the_url);
	/*apply XML:base*/
	while (node) {
		GF_FieldInfo info;
		if (gf_node_get_attribute_by_tag(node, TAG_XML_ATT_base, 0, 0, &info)==GF_OK) {
			char *new_url = gf_url_concatenate( ((XMLRI*)info.far_ptr)->string, url);
			if (new_url) {
				gf_free(url);
				url = new_url;
			}
		}
		node = gf_node_get_parent(node, 0);
	}

	/*if this is a fragment and no XML:BASE was found, this is a fragment of the current document*/
	if (url[0]=='#') return url;

	if (scene) {
		char *the_url;
		if (scene->redirect_xml_base) {
			the_url = gf_url_concatenate(scene->redirect_xml_base, url);
		} else {
//			the_url = gf_url_concatenate(is->root_od->net_service->url, url);
			/*the root url of a document should be "." if not specified, so that the final URL resolve happens only once
			at the service level*/
			the_url = gf_strdup(url);
		}
		gf_free(url);
		return the_url;
	}
	return url;
}
Пример #4
0
void gf_inline_on_modified(GF_Node *node)
{
	u32 ODID;
	GF_MediaObject *mo;
	M_Inline *pInline = (M_Inline *) node;
	GF_Scene *scene = (GF_Scene *)gf_node_get_private(node);

	ODID = gf_mo_get_od_id(&pInline->url);
	if (scene) {
		mo = (scene->root_od) ? scene->root_od->mo : NULL;

		/*disconnect current inline if we're the last one using it (same as regular OD session leave/join)*/
		if (mo) {
			Bool changed = GF_TRUE;
			if (ODID != GF_MEDIA_EXTERNAL_ID) {
				if (ODID && (ODID==scene->root_od->OD->objectDescriptorID)) changed = GF_FALSE;
			} else {
				if (gf_mo_is_same_url(mo, &pInline->url, NULL, 0) ) changed = GF_FALSE;
			}
			if (mo->num_open) {
				if (!changed) return;

				gf_scene_notify_event(scene, GF_EVENT_UNLOAD, node, NULL, GF_OK, GF_TRUE);
				gf_node_dirty_parents(node);
				gf_mo_event_target_remove_by_node(mo, node);

				/*reset the scene pointer as it may get destroyed*/
				switch (gf_node_get_tag(node)) {
				case TAG_MPEG4_Inline:
#ifndef GPAC_DISABLE_X3D
				case TAG_X3D_Inline:
#endif
					gf_node_set_private(node, NULL);
					break;
				}

				mo->num_open --;
				if (!mo->num_open) {
					if (ODID == GF_MEDIA_EXTERNAL_ID) {
						GF_Scene *parent = scene->root_od->parentscene;
						/*!!! THIS WILL DESTROY THE INLINE SCENE OBJECT !!!*/
						gf_odm_disconnect(scene->root_od, GF_TRUE);
						/*and force removal of the media object*/
						if (parent) {
							if (gf_list_del_item(parent->scene_objects, mo)>=0) {
								gf_sg_vrml_mf_reset(&mo->URLs, GF_SG_VRML_MFURL);
								gf_mo_del(mo);
							}
						}
					} else {
						gf_term_lock_media_queue(scene->root_od->term, GF_TRUE);

						/*external media are completely unloaded, except addons which are only declared once */
						if (!scene->root_od->addon && (scene->root_od->OD->objectDescriptorID==GF_MEDIA_EXTERNAL_ID)) {
							scene->root_od->action_type = GF_ODM_ACTION_DELETE;
						} else {
							scene->root_od->action_type = GF_ODM_ACTION_STOP;
						}
						if (gf_list_find(scene->root_od->term->media_queue, scene->root_od)<0)
							gf_list_add(scene->root_od->term->media_queue, scene->root_od);

						gf_term_lock_media_queue(scene->root_od->term, GF_FALSE);
					}
				}
			}
		}
	}
	/*force a redraw and load scene at next pass - we cannot load the scene now because
		- we can be in a JS call (eg JS mutex blocked)
		- locating scene objects matching the new url needs exclusive access to the MediaObject list, achieved with the term net mutex
		- another service may already be setting up objects (eg exclusive access to the net mutex grabbed), which can trigger event forwarding
		- some event forwarders may request JS context (eg access to JS mutex)

		In such a case we would end up in a deadlock - this needs urgent fixing ...
	*/
	if (ODID) {
		/*if no parent we must process the url change as we may not be traversed later on (not in the scene tree)*/
		if (gf_node_get_parent(node, 0)==NULL) {
			gf_inline_set_scene(pInline);
		} else {
			gf_node_dirty_parents(node);
		}
	}
}
Пример #5
0
Bool group_cache_compute_stats(GF_Node *node, GroupingNode2D *group, GF_TraverseState *tr_state, DrawableContext *first_child, Bool skip_first_child)
{
	GF_Rect group_bounds;
	DrawableContext *ctx;
	u32 nb_segments, nb_objects;
	u32 alpha_pixels, opaque_pixels, area_world;
	u32 video_cache_max_size, cache_size, prev_cache_size;
	u32 i;
	GF_RectArray ra;

	/*compute stats*/
	nb_objects = 0;
	nb_segments = 0;
	alpha_pixels = opaque_pixels = 0;
	prev_cache_size = group->cached_size;
	/*reset bounds*/
	group_bounds.width = group_bounds.height = 0;
	video_cache_max_size = tr_state->visual->compositor->video_cache_max_size;

	/*never cache root node - this should be refined*/
	if (gf_node_get_parent(node, 0) == NULL) goto group_reject;
	if (!group->traverse_time) goto group_reject;

	ra_init(&ra);

	ctx = first_child;
	if (!first_child) ctx = tr_state->visual->context;
	if (skip_first_child) ctx = ctx->next;
	/*compute properties for the sub display list*/
	while (ctx && ctx->drawable) {
		//Fixed area;
		u32 alpha_comp;

		/*get area and compute alpha/opaque coverage*/
		alpha_comp = GF_COL_A(ctx->aspect.fill_color);

		/*add to group area*/
		gf_rect_union(&group_bounds, &ctx->bi->unclip);
		nb_objects++;

		/*no alpha*/
		if ((alpha_comp==0xFF)
			/*no transparent texture*/
			&& (!ctx->aspect.fill_texture || !ctx->aspect.fill_texture->transparent)
		) {

			ra_union_rect(&ra, &ctx->bi->clip);
		}
		nb_segments += ctx->drawable->path->n_points;

		ctx = ctx->next;
	}

	if (
		/*TEST 1: discard visually empty groups*/
		(!group_bounds.width || !group_bounds.height)
		||
		/*TEST 2: discard small groups*/
		(nb_objects<MIN_OBJECTS_IN_CACHE)
		||
		/*TEST 3: low complexity group*/
		(nb_segments && (nb_segments<10))
	) {
		ra_del(&ra);
		goto group_reject;
	}

	ra_refresh(&ra);
	opaque_pixels = 0;
	for (i=0; i<ra.count; i++) {
		opaque_pixels += ra.list[i].width * ra.list[i].height;
	}
	ra_del(&ra);

	/*get coverage in world coords*/
	area_world = FIX2INT(group_bounds.width) * FIX2INT(group_bounds.height);

	/*TEST 4: discard low coverage groups in world coords (plenty of space wasted)
		we consider that this % of the area is actually drawn - this is of course wrong,
		we would need to compute each path coverage in local coords then get the ratio
	*/
	if (10*opaque_pixels < 7*area_world) goto group_reject;

	/*the memory size allocated for the cache - cache is drawn in final coordinate system !!*/
	group_bounds.width = tr_state->visual->compositor->cache_scale * group_bounds.width / 100;
	group_bounds.height = tr_state->visual->compositor->cache_scale * group_bounds.height / 100;
	cache_size = FIX2INT(group_bounds.width) * FIX2INT(group_bounds.height) * 4 /* pixelFormat is ARGB*/;

	/*TEST 5: cache is less than 10x10 pixels: discard*/
	if (cache_size < 400) goto group_reject;
	/*TEST 6: cache is larger than our allowed memory: discard*/
	if (cache_size>=video_cache_max_size) {
		tr_state->cache_too_small = 1;
		goto group_reject;
	}

	/*compute the delta value for measuring the group importance for later discard
		(avg_time - Tcache) / (size_cache - drawable_gain)
	*/
	group->priority = INT2FIX(nb_objects*1024*group->traverse_time) / cache_size / group->nb_stats_frame;
	/*OK, group is a good candidate for caching*/
	group->nb_objects = nb_objects;
	group->cached_size = cache_size;


	/*we're moving from non-cached to cached*/
	if (!(group->flags & GROUP_IS_CACHABLE)) {
		group->flags |= GROUP_IS_CACHABLE;
		tr_state->visual->compositor->draw_next_frame = 1;

		/*insert the candidate and then update the list in order*/
		group_cache_insert_entry(node, group, tr_state);
		/*keep track of this cache object for later removal*/
		gf_list_add(tr_state->visual->compositor->cached_groups_queue, group);

		GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Turning cache on during stat pass for node %s - %d kb used in all caches\n", gf_node_get_log_name(node), tr_state->visual->compositor->video_cache_current_size ));
	}
	/*update memory occupation*/
	else {
		tr_state->visual->compositor->video_cache_current_size -= prev_cache_size;
		tr_state->visual->compositor->video_cache_current_size += group->cached_size;

		if (group->cache)
			group->cache->force_recompute = 1;
	}
	return 1;


group_reject:
	group->nb_objects = nb_objects;

	if ((group->flags & GROUP_IS_CACHABLE) || group->cache) {
		group->flags &= ~GROUP_IS_CACHABLE;

		if (group->cache) {
			group_cache_del(group->cache);
			group->cache = NULL;
			group->flags &= ~GROUP_IS_CACHED;
		}
		gf_list_del_item(tr_state->visual->compositor->cached_groups, group);
		tr_state->visual->compositor->video_cache_current_size -= cache_size;
	}

#if 0
	GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] REJECT %s\tObjects: %d\tSlope: %g\tBytes: %d\tTime: %d\n",
										gf_node_get_log_name(node),
										group->nb_objects,
										FIX2FLT(group->priority),
										group->cached_size,
										group->traverse_time
										));

	GF_LOG(GF_LOG_DEBUG, GF_LOG_CACHE, ("[CACHE] Status (B): Max: %d\tUsed: %d\tNb Groups: %d\n",
								tr_state->visual->compositor->video_cache_max_size,
								tr_state->visual->compositor->video_cache_current_size,
								gf_list_count(tr_state->visual->compositor->cached_groups)
								));
#endif
	return 0;
}
Пример #6
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);
}
Пример #7
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);
}