1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2007-2012
6  *					All rights reserved
7  *
8  *  This file is part of GPAC / Scene Compositor sub-project
9  *
10  *  GPAC is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU Lesser General Public License as published by
12  *  the Free Software Foundation; either version 2, or (at your option)
13  *  any later version.
14  *
15  *  GPAC is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; see the file COPYING.  If not, write to
22  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25 
26 #include <gpac/utf.h>
27 
28 #ifndef GPAC_DISABLE_SVG
29 
30 #include "visual_manager.h"
31 #include "nodes_stacks.h"
32 
33 typedef struct
34 {
35 	u16 *unicode;
36 	u16 uni_len;
37 
38 	GF_Glyph glyph;
39 	GF_Font *font;
40 } SVG_GlyphStack;
41 
42 
43 /*translate string to glyph sequence*/
svg_font_get_glyphs(void * udta,const char * utf_string,u32 * glyph_buffer,u32 * io_glyph_buffer_size,const char * lang,Bool * is_rtl)44 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)
45 {
46 	u32 prev_c;
47 	size_t len;
48 	u32 i, gl_idx;
49 	u16 *utf_res;
50 	GF_Node *node = (GF_Node *)udta;
51 	GF_ChildNodeItem *child;
52 	char *utf8 = (char*) utf_string;
53 
54 	/*FIXME - use glyphs unicode attributes for glyph substitution*/
55 	len = utf_string ? (u32) strlen(utf_string) : 0;
56 	if (!len) {
57 		*io_glyph_buffer_size = 0;
58 		return GF_OK;
59 	}
60 
61 	if (*io_glyph_buffer_size < len+1) {
62 		*io_glyph_buffer_size = (u32) len+1;
63 		return GF_BUFFER_TOO_SMALL;
64 	}
65 
66 	len = gf_utf8_mbstowcs((u16*) glyph_buffer, *io_glyph_buffer_size, (const char**)&utf8);
67 	if (len == (size_t) -1) return GF_IO_ERR;
68 	/*should not happen*/
69 	if (utf8) return GF_IO_ERR;
70 
71 	/*perform bidi relayout*/
72 	utf_res = (u16 *) glyph_buffer;
73 	*is_rtl = gf_utf8_reorder_bidi(utf_res, (u32) len);
74 
75 	/*move 16bit buffer to 32bit*/
76 	for (i=(u32)len; i>0; i--) {
77 		glyph_buffer[i-1] = utf_res[i-1];
78 	}
79 
80 	gl_idx = 0;
81 	prev_c = 0;
82 	for (i=0; i<len; i++) {
83 		SVG_GlyphStack *missing_glyph = NULL;
84 		SVG_GlyphStack *st = NULL;
85 		child = ((GF_ParentNode *) node)->children;
86 		while (child) {
87 			u32 tag = gf_node_get_tag(child->node);
88 			if (tag==TAG_SVG_missing_glyph) {
89 				missing_glyph = gf_node_get_private(child->node);
90 			} else if (tag ==TAG_SVG_glyph) {
91 				Bool glyph_ok = 0;
92 				SVGAllAttributes atts;
93 
94 				st = gf_node_get_private(child->node);
95 				if (!st) {
96 					child = child->next;
97 					continue;
98 				}
99 
100 				if (st->glyph.utf_name==glyph_buffer[i]) {
101 					u32 j, count;
102 					gf_svg_flatten_attributes((SVG_Element*)child->node, &atts);
103 					if (!lang) {
104 						glyph_ok = 1;
105 					} else {
106 						if (!atts.lang) {
107 							glyph_ok = 1;
108 						} else {
109 							count = gf_list_count(*atts.lang);
110 							for (j=0; j<count; j++) {
111 								char *name = gf_list_get(*atts.lang, j);
112 								if (!stricmp(name, lang) || strstr(lang, name)) {
113 									glyph_ok = 1;
114 									break;
115 								}
116 							}
117 						}
118 					}
119 					if (atts.arabic_form) {
120 						Bool first = (!prev_c || (prev_c==' ')) ? 1 : 0;
121 						Bool last = ((i+1==len) || (glyph_buffer[i+1]==' ') ) ? 1 : 0;
122 						if (!strcmp(*atts.arabic_form, "isolated")) {
123 							if (!first || !last) glyph_ok = 0;
124 						}
125 						if (!strcmp(*atts.arabic_form, "initial")) {
126 							if (!first) glyph_ok = 0;
127 						}
128 						if (!strcmp(*atts.arabic_form, "medial")) {
129 							if (first || last) glyph_ok = 0;
130 						}
131 						if (!strcmp(*atts.arabic_form, "terminal")) {
132 							if (!last) glyph_ok = 0;
133 						}
134 					}
135 					if (glyph_ok) break;
136 				}
137 				/*perform glyph substitution*/
138 				else if (st->uni_len>1) {
139 					u32 j;
140 					for (j=0; j<st->uni_len; j++) {
141 						if (i+j>=len) break;
142 						if (glyph_buffer[i+j] != st->unicode[j]) break;
143 					}
144 					if (j==st->uni_len)
145 						break;
146 				}
147 				st = NULL;
148 			}
149 			child = child->next;
150 		}
151 		prev_c = glyph_buffer[i];
152 
153 		if (!st)
154 			st = missing_glyph;
155 		glyph_buffer[gl_idx] = st ? st->glyph.ID : 0;
156 		if (st && st->uni_len>1) i++;
157 
158 		gl_idx++;
159 	}
160 	*io_glyph_buffer_size = /* len = */ gl_idx;
161 
162 	return GF_OK;
163 }
164 
165 /*loads glyph by name - returns NULL if glyph cannot be found*/
svg_font_load_glyph(void * udta,u32 glyph_name)166 static GF_Glyph *svg_font_load_glyph(void *udta, u32 glyph_name)
167 {
168 	GF_ChildNodeItem *child = ((GF_ParentNode *) udta)->children;
169 
170 	while (child) {
171 		if (gf_node_get_tag(child->node)==TAG_SVG_glyph) {
172 			SVG_GlyphStack *st = gf_node_get_private(child->node);
173 			if (st->glyph.ID==glyph_name) {
174 				return &st->glyph;
175 			}
176 		}
177 		child = child->next;
178 	}
179 
180 	return NULL;
181 }
182 
svg_traverse_font(GF_Node * node,void * rs,Bool is_destroy)183 static void svg_traverse_font(GF_Node *node, void *rs, Bool is_destroy)
184 {
185 	if (is_destroy) {
186 		GF_Font *font = gf_node_get_private(node);
187 		if (font) {
188 			gf_font_manager_unregister_font(font->ft_mgr, font);
189 			if (font->name) gf_free(font->name);
190 			gf_free(font);
191 		}
192 	}
193 }
194 
svg_font_on_load(GF_Node * handler,GF_DOM_Event * event,GF_Node * observer)195 static void svg_font_on_load(GF_Node *handler, GF_DOM_Event *event, GF_Node *observer)
196 {
197 	GF_Font *font;
198 	assert(event->currentTarget->ptr_type==GF_DOM_EVENT_TARGET_NODE);
199 	assert(gf_node_get_tag((GF_Node*)event->currentTarget->ptr)==TAG_SVG_font);
200 	font = gf_node_get_private((GF_Node*)event->currentTarget->ptr);
201 	font->not_loaded = 0;
202 
203 	/*brute-force signaling that all fonts have changed and texts must be recomputed*/
204 	font->compositor->reset_fonts = 1;
205 	gf_sc_next_frame_state(font->compositor, GF_SC_DRAW_FRAME);
206 	font->compositor->fonts_pending--;
207 }
208 
compositor_init_svg_font(GF_Compositor * compositor,GF_Node * node)209 void compositor_init_svg_font(GF_Compositor *compositor, GF_Node *node)
210 {
211 	SVG_handlerElement *handler;
212 	GF_Err e;
213 	SVGAllAttributes atts;
214 	GF_Font *font;
215 	GF_Node *node_font = gf_node_get_parent(node, 0);
216 	if (!node_font) return;
217 
218 	if (gf_node_get_tag(node_font)!=TAG_SVG_font) return;
219 
220 	gf_svg_flatten_attributes((SVG_Element*)node, &atts);
221 	if (!atts.font_family) return;
222 
223 	/*register font to font manager*/
224 	GF_SAFEALLOC(font, GF_Font);
225 	if (!font) {
226 		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate svg font\n"));
227 		return;
228 	}
229 	e = gf_font_manager_register_font(compositor->font_manager, font);
230 	if (e) {
231 		gf_free(font);
232 		return;
233 	}
234 	font->ft_mgr = compositor->font_manager;
235 	font->compositor = compositor;
236 
237 	font->get_glyphs = svg_font_get_glyphs;
238 	font->load_glyph = svg_font_load_glyph;
239 	font->udta = node_font;
240 	gf_node_set_private(node_font, font);
241 	gf_node_set_callback_function(node_font, svg_traverse_font);
242 	font->name = gf_strdup(atts.font_family->value);
243 
244 	font->em_size = atts.units_per_em ? FIX2INT( gf_ceil(atts.units_per_em->value) ) : 1000;
245 	/*Inconsistency between SVG 1.2 and 1.1
246 		when not specify, ascent and descent are computed based on font.vert-origin-y, WHICH DOES NOT EXIST
247 	IN Tiny 1.2 !!! We assume it to be 0.
248 	*/
249 	font->ascent = atts.ascent ? FIX2INT( gf_ceil(atts.ascent->value) ) : 0;
250 	if (!font->ascent) font->ascent = font->em_size;
251 	font->descent = atts.descent ? FIX2INT( gf_ceil(atts.descent->value) ) : 0;
252 	font->baseline = atts.alphabetic ? FIX2INT( gf_ceil(atts.alphabetic->value) ) : 0;
253 	font->line_spacing = font->em_size;
254 	font->styles = 0;
255 	if (atts.font_style) {
256 		switch (*atts.font_style) {
257 		case SVG_FONTSTYLE_ITALIC:
258 			font->styles |= GF_FONT_ITALIC;
259 			break;
260 		case SVG_FONTSTYLE_OBLIQUE:
261 			font->styles |= GF_FONT_OBLIQUE;
262 			break;
263 		}
264 	}
265 	if (atts.font_variant && (*atts.font_variant ==SVG_FONTVARIANT_SMALLCAPS))
266 		font->styles |= GF_FONT_SMALLCAPS;
267 
268 	if (atts.font_weight) {
269 		switch(*atts.font_weight) {
270 		case SVG_FONTWEIGHT_100:
271 			font->styles |= GF_FONT_WEIGHT_100;
272 			break;
273 		case SVG_FONTWEIGHT_LIGHTER:
274 			font->styles |= GF_FONT_WEIGHT_LIGHTER;
275 			break;
276 		case SVG_FONTWEIGHT_200:
277 			font->styles |= GF_FONT_WEIGHT_200;
278 			break;
279 		case SVG_FONTWEIGHT_300:
280 			font->styles |= GF_FONT_WEIGHT_300;
281 			break;
282 		case SVG_FONTWEIGHT_400:
283 			font->styles |= GF_FONT_WEIGHT_400;
284 			break;
285 		case SVG_FONTWEIGHT_NORMAL:
286 			font->styles |= GF_FONT_WEIGHT_NORMAL;
287 			break;
288 		case SVG_FONTWEIGHT_500:
289 			font->styles |= GF_FONT_WEIGHT_500;
290 			break;
291 		case SVG_FONTWEIGHT_600:
292 			font->styles |= GF_FONT_WEIGHT_600;
293 			break;
294 		case SVG_FONTWEIGHT_700:
295 			font->styles |= GF_FONT_WEIGHT_700;
296 			break;
297 		case SVG_FONTWEIGHT_BOLD:
298 			font->styles |= GF_FONT_WEIGHT_BOLD;
299 			break;
300 		case SVG_FONTWEIGHT_800:
301 			font->styles |= GF_FONT_WEIGHT_800;
302 			break;
303 		case SVG_FONTWEIGHT_900:
304 			font->styles |= GF_FONT_WEIGHT_900;
305 			break;
306 		case SVG_FONTWEIGHT_BOLDER:
307 			font->styles |= GF_FONT_WEIGHT_BOLDER;
308 			break;
309 		}
310 	}
311 
312 	gf_svg_flatten_attributes((SVG_Element*)node_font, &atts);
313 	font->max_advance_h = atts.horiz_adv_x ? FIX2INT( gf_ceil(atts.horiz_adv_x->value) ) : 0;
314 
315 	font->not_loaded = 1;
316 
317 	/*wait for onLoad event before activating the font, otherwise we may not have all the glyphs*/
318 	handler = gf_dom_listener_build(node_font, GF_EVENT_LOAD, 0);
319 	handler->handle_event = svg_font_on_load;
320 }
321 
322 
svg_traverse_glyph(GF_Node * node,void * rs,Bool is_destroy)323 static void svg_traverse_glyph(GF_Node *node, void *rs, Bool is_destroy)
324 {
325 	if (is_destroy) {
326 		GF_Font *font;
327 		GF_Glyph *prev_glyph, *a_glyph;
328 		SVG_GlyphStack *st = gf_node_get_private(node);
329 		if (st->unicode) gf_free(st->unicode);
330 
331 		font = st->font;
332 		prev_glyph = NULL;
333 		a_glyph = font->glyph;
334 		while (a_glyph) {
335 			if (a_glyph == &st->glyph) break;
336 			prev_glyph = a_glyph;
337 			a_glyph = a_glyph->next;
338 		}
339 		if (prev_glyph) {
340 			prev_glyph->next = st->glyph.next;
341 		} else {
342 			font->glyph = st->glyph.next;
343 		}
344 		gf_free(st);
345 	}
346 }
347 
compositor_init_svg_glyph(GF_Compositor * compositor,GF_Node * node)348 void compositor_init_svg_glyph(GF_Compositor *compositor, GF_Node *node)
349 {
350 	u16 utf_name[20];
351 	u8 *utf8;
352 	size_t len;
353 	GF_Rect rc;
354 	GF_Glyph *glyph;
355 	GF_Font *font;
356 	SVG_GlyphStack *st;
357 	SVGAllAttributes atts;
358 	GF_Node *node_font = gf_node_get_parent(node, 0);
359 
360 	/*locate the font node*/
361 	if (node_font) node_font = gf_node_get_parent(node, 0);
362 	if (!node_font || (gf_node_get_tag(node_font)!=TAG_SVG_font) ) return;
363 	font = gf_node_get_private(node_font);
364 	if (!font) return;
365 
366 	gf_svg_flatten_attributes((SVG_Element*)node, &atts);
367 
368 	if (gf_node_get_tag(node)==TAG_SVG_missing_glyph) {
369 		GF_SAFEALLOC(st, SVG_GlyphStack);
370 		if (!st) return;
371 		goto reg_common;
372 	}
373 	/*we must have unicode specified*/
374 	if (!atts.unicode) return;
375 
376 	GF_SAFEALLOC(st, SVG_GlyphStack);
377 	if (!st) return;
378 	utf8 = (u8 *) *atts.unicode;
379 	len = gf_utf8_mbstowcs(utf_name, 200, (const char **) &utf8);
380 	/*this is a single glyph*/
381 	if (len==1) {
382 		st->glyph.utf_name = utf_name[0];
383 		st->uni_len = 1;
384 	} else {
385 		st->glyph.utf_name = (u32) (PTR_TO_U_CAST st);
386 		st->unicode = gf_malloc(sizeof(u16)*len);
387 		st->uni_len = (u16) len;
388 		memcpy(st->unicode, utf_name, sizeof(u16)*len);
389 	}
390 
391 reg_common:
392 	st->glyph.ID = (u32)(PTR_TO_U_CAST st);
393 	st->font = font;
394 	st->glyph.horiz_advance = font->max_advance_h;
395 	if (atts.horiz_adv_x) st->glyph.horiz_advance = FIX2INT( gf_ceil(atts.horiz_adv_x->value) );
396 	if (atts.d) {
397 		st->glyph.path = atts.d;
398 		gf_path_get_bounds(atts.d, &rc);
399 		st->glyph.width = FIX2INT( gf_ceil(rc.width) );
400 		st->glyph.height = FIX2INT( gf_ceil(rc.height) );
401 	}
402 	st->glyph.vert_advance = st->glyph.height;
403 	if (!st->glyph.vert_advance)
404 		st->glyph.vert_advance = font->max_advance_v;
405 
406 	/*register glyph*/
407 	if (!font->glyph) {
408 		font->glyph = &st->glyph;
409 	} else {
410 		glyph = font->glyph;
411 		while (glyph->next) glyph = glyph->next;
412 		glyph->next = &st->glyph;
413 	}
414 
415 	gf_node_set_private(node, st);
416 	gf_node_set_callback_function(node, svg_traverse_glyph);
417 }
418 
419 
420 typedef struct
421 {
422 	GF_Font *font;
423 	GF_Font *alias;
424 	GF_Compositor *compositor;
425 	GF_MediaObject *mo;
426 } FontURIStack;
427 
svg_font_uri_check(GF_Node * node,FontURIStack * st)428 static Bool svg_font_uri_check(GF_Node *node, FontURIStack *st)
429 {
430 	GF_Font *font;
431 	GF_Node *font_elt;
432 	SVGAllAttributes atts;
433 	gf_svg_flatten_attributes((SVG_Element*)node, &atts);
434 	if (!atts.xlink_href) return 0;
435 
436 	if (atts.xlink_href->type == XMLRI_ELEMENTID) {
437 		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);
438 	} else {
439 		GF_SceneGraph *ext_sg;
440 		char *font_name = strchr(atts.xlink_href->string, '#');
441 		if (!font_name) return 0;
442 		if (!st->mo) {
443 			st->mo = gf_mo_load_xlink_resource(node, 0, 0, -1);
444 			if (!st->mo) {
445 				st->compositor->fonts_pending--;
446 				return 0;
447 			}
448 		}
449 		ext_sg = gf_mo_get_scenegraph(st->mo);
450 		if (!ext_sg) {
451 			st->compositor->fonts_pending--;
452 			return 0;
453 		}
454 		atts.xlink_href->target = gf_sg_find_node_by_name(ext_sg, font_name+1);
455 		if (!atts.xlink_href->target) {
456 			st->compositor->fonts_pending--;
457 			return 0;
458 		}
459 	}
460 	font_elt = atts.xlink_href->target;
461 	if (gf_node_get_tag(font_elt) != TAG_SVG_font) {
462 		st->compositor->fonts_pending--;
463 		return 0;
464 	}
465 	font = gf_node_get_private(font_elt);
466 	if (!font) {
467 		st->compositor->fonts_pending--;
468 		return 0;
469 	}
470 
471 	st->alias = font;
472 
473 	gf_mo_is_done(st->mo);
474 	font->not_loaded = 0;
475 	return 1;
476 }
477 
svg_font_uri_get_alias(void * udta)478 GF_Font *svg_font_uri_get_alias(void *udta)
479 {
480 	GF_Node *node = (GF_Node *)udta;
481 	FontURIStack *st = gf_node_get_private(node);
482 	if (!st->alias && !svg_font_uri_check(node, st)) {
483 		return NULL;
484 	}
485 	return st->alias;
486 }
487 
svg_font_uri_get_glyphs(void * udta,const char * utf_string,u32 * glyph_buffer,u32 * io_glyph_buffer_size,const char * lang,Bool * is_rtl)488 static GF_Err svg_font_uri_get_glyphs(void *udta, const char *utf_string, u32 *glyph_buffer, u32 *io_glyph_buffer_size, const char *lang, Bool *is_rtl)
489 {
490 	return GF_URL_ERROR;
491 }
492 
svg_font_uri_load_glyph(void * udta,u32 glyph_name)493 static GF_Glyph *svg_font_uri_load_glyph(void *udta, u32 glyph_name)
494 {
495 	return NULL;
496 }
497 
svg_traverse_font_face_uri(GF_Node * node,void * rs,Bool is_destroy)498 static void svg_traverse_font_face_uri(GF_Node *node, void *rs, Bool is_destroy)
499 {
500 	if (is_destroy) {
501 		FontURIStack *st = gf_node_get_private(node);
502 		if (st) {
503 			gf_font_manager_unregister_font(st->font->ft_mgr, st->font);
504 			if (st->font->name) gf_free(st->font->name);
505 			gf_free(st->font);
506 			if (st->mo) gf_mo_unload_xlink_resource(node, st->mo);
507 			gf_free(st);
508 		}
509 	}
510 }
511 
compositor_init_svg_font_face_uri(GF_Compositor * compositor,GF_Node * node)512 void compositor_init_svg_font_face_uri(GF_Compositor *compositor, GF_Node *node)
513 {
514 	GF_Node *par;
515 	GF_Font *font;
516 	FontURIStack *stack;
517 	GF_Err e;
518 	SVGAllAttributes atts;
519 
520 	/*check parent is a font-face-src*/
521 	par = gf_node_get_parent(node, 0);
522 	if (!par || (gf_node_get_tag(par)!=TAG_SVG_font_face_src)) return;
523 	/*check parent's parent is a font-face*/
524 	par = gf_node_get_parent(par, 0);
525 	if (!par || (gf_node_get_tag(par)!=TAG_SVG_font_face)) return;
526 
527 
528 	gf_svg_flatten_attributes((SVG_Element*)node, &atts);
529 	if (!atts.xlink_href) return;
530 
531 	/*get font familly*/
532 	gf_svg_flatten_attributes((SVG_Element*)par, &atts);
533 	if (!atts.font_family) return;
534 
535 	/*if font with the same name exists, don't load*/
536 	if (gf_compositor_svg_set_font(compositor->font_manager, atts.font_family->value, 0, 1) != NULL)
537 		return;
538 
539 	/*register font to font manager*/
540 	GF_SAFEALLOC(font, GF_Font);
541 	if (!font) {
542 		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate font for svg font face URI\n"));
543 		return;
544 	}
545 
546 	e = gf_font_manager_register_font(compositor->font_manager, font);
547 	if (e) {
548 		gf_free(font);
549 		return;
550 	}
551 	GF_SAFEALLOC(stack, FontURIStack);
552 	if (!stack) {
553 		gf_free(font);
554 		GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate svg font face URI stack\n"));
555 		return;
556 	}
557 	stack->font = font;
558 	stack->compositor = compositor;
559 
560 	font->ft_mgr = compositor->font_manager;
561 
562 	font->get_glyphs = svg_font_uri_get_glyphs;
563 	font->load_glyph = svg_font_uri_load_glyph;
564 	font->get_alias = svg_font_uri_get_alias;
565 	font->udta = node;
566 	font->name = gf_strdup(atts.font_family->value);
567 	gf_node_set_private(node, stack);
568 	gf_node_set_callback_function(node, svg_traverse_font_face_uri);
569 
570 	font->not_loaded = 1;
571 	compositor->fonts_pending++;
572 	svg_font_uri_check(node, stack);
573 }
574 
575 
576 #endif /*GPAC_DISABLE_SVG*/
577 
578