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