Line data Source code
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*/
44 2 : 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 2 : char *utf8 = (char*) utf_string;
53 :
54 : /*FIXME - use glyphs unicode attributes for glyph substitution*/
55 2 : len = utf_string ? (u32) strlen(utf_string) : 0;
56 2 : if (!len) {
57 0 : *io_glyph_buffer_size = 0;
58 0 : return GF_OK;
59 : }
60 :
61 2 : if (*io_glyph_buffer_size < len+1) {
62 0 : *io_glyph_buffer_size = (u32) len+1;
63 0 : return GF_BUFFER_TOO_SMALL;
64 : }
65 :
66 2 : len = gf_utf8_mbstowcs((u16*) glyph_buffer, *io_glyph_buffer_size, (const char**)&utf8);
67 2 : if (len == (size_t) -1) return GF_IO_ERR;
68 : /*should not happen*/
69 2 : if (utf8) return GF_IO_ERR;
70 :
71 : /*perform bidi relayout*/
72 : utf_res = (u16 *) glyph_buffer;
73 2 : *is_rtl = gf_utf8_reorder_bidi(utf_res, (u32) len);
74 :
75 : /*move 16bit buffer to 32bit*/
76 14 : for (i=(u32)len; i>0; i--) {
77 10 : glyph_buffer[i-1] = utf_res[i-1];
78 : }
79 :
80 : gl_idx = 0;
81 : prev_c = 0;
82 10 : for (i=0; i<len; i++) {
83 : SVG_GlyphStack *missing_glyph = NULL;
84 : SVG_GlyphStack *st = NULL;
85 10 : child = ((GF_ParentNode *) node)->children;
86 60 : while (child) {
87 50 : u32 tag = gf_node_get_tag(child->node);
88 50 : if (tag==TAG_SVG_missing_glyph) {
89 10 : missing_glyph = gf_node_get_private(child->node);
90 40 : } else if (tag ==TAG_SVG_glyph) {
91 : Bool glyph_ok = 0;
92 : SVGAllAttributes atts;
93 :
94 30 : st = gf_node_get_private(child->node);
95 30 : if (!st) {
96 0 : child = child->next;
97 0 : continue;
98 : }
99 :
100 30 : if (st->glyph.utf_name==glyph_buffer[i]) {
101 : u32 j, count;
102 10 : gf_svg_flatten_attributes((SVG_Element*)child->node, &atts);
103 10 : if (!lang) {
104 : glyph_ok = 1;
105 : } else {
106 0 : if (!atts.lang) {
107 : glyph_ok = 1;
108 : } else {
109 0 : count = gf_list_count(*atts.lang);
110 0 : for (j=0; j<count; j++) {
111 0 : char *name = gf_list_get(*atts.lang, j);
112 0 : if (!stricmp(name, lang) || strstr(lang, name)) {
113 : glyph_ok = 1;
114 : break;
115 : }
116 : }
117 : }
118 : }
119 10 : if (atts.arabic_form) {
120 0 : Bool first = (!prev_c || (prev_c==' ')) ? 1 : 0;
121 0 : Bool last = ((i+1==len) || (glyph_buffer[i+1]==' ') ) ? 1 : 0;
122 0 : if (!strcmp(*atts.arabic_form, "isolated")) {
123 0 : if (!first || !last) glyph_ok = 0;
124 : }
125 0 : if (!strcmp(*atts.arabic_form, "initial")) {
126 0 : if (!first) glyph_ok = 0;
127 : }
128 0 : if (!strcmp(*atts.arabic_form, "medial")) {
129 0 : if (first || last) glyph_ok = 0;
130 : }
131 0 : if (!strcmp(*atts.arabic_form, "terminal")) {
132 0 : if (!last) glyph_ok = 0;
133 : }
134 : }
135 10 : if (glyph_ok) break;
136 : }
137 : /*perform glyph substitution*/
138 20 : else if (st->uni_len>1) {
139 : u32 j;
140 0 : for (j=0; j<st->uni_len; j++) {
141 0 : if (i+j>=len) break;
142 0 : if (glyph_buffer[i+j] != st->unicode[j]) break;
143 : }
144 0 : if (j==st->uni_len)
145 : break;
146 : }
147 : st = NULL;
148 : }
149 40 : child = child->next;
150 : }
151 10 : prev_c = glyph_buffer[i];
152 :
153 10 : if (!st)
154 : st = missing_glyph;
155 10 : glyph_buffer[gl_idx] = st ? st->glyph.ID : 0;
156 10 : if (st && st->uni_len>1) i++;
157 :
158 10 : gl_idx++;
159 : }
160 2 : *io_glyph_buffer_size = /* len = */ gl_idx;
161 :
162 2 : return GF_OK;
163 : }
164 :
165 : /*loads glyph by name - returns NULL if glyph cannot be found*/
166 0 : static GF_Glyph *svg_font_load_glyph(void *udta, u32 glyph_name)
167 : {
168 0 : GF_ChildNodeItem *child = ((GF_ParentNode *) udta)->children;
169 :
170 0 : while (child) {
171 0 : if (gf_node_get_tag(child->node)==TAG_SVG_glyph) {
172 0 : SVG_GlyphStack *st = gf_node_get_private(child->node);
173 0 : if (st->glyph.ID==glyph_name) {
174 0 : return &st->glyph;
175 : }
176 : }
177 0 : child = child->next;
178 : }
179 :
180 : return NULL;
181 : }
182 :
183 1 : static void svg_traverse_font(GF_Node *node, void *rs, Bool is_destroy)
184 : {
185 1 : if (is_destroy) {
186 1 : GF_Font *font = gf_node_get_private(node);
187 1 : if (font) {
188 1 : gf_font_manager_unregister_font(font->ft_mgr, font);
189 1 : if (font->name) gf_free(font->name);
190 1 : gf_free(font);
191 : }
192 : }
193 1 : }
194 :
195 1 : 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 1 : font = gf_node_get_private((GF_Node*)event->currentTarget->ptr);
201 1 : font->not_loaded = 0;
202 :
203 : /*brute-force signaling that all fonts have changed and texts must be recomputed*/
204 1 : font->compositor->reset_fonts = 1;
205 1 : gf_sc_next_frame_state(font->compositor, GF_SC_DRAW_FRAME);
206 1 : font->compositor->fonts_pending--;
207 1 : }
208 :
209 2 : 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 2 : GF_Node *node_font = gf_node_get_parent(node, 0);
216 3 : if (!node_font) return;
217 :
218 2 : if (gf_node_get_tag(node_font)!=TAG_SVG_font) return;
219 :
220 1 : gf_svg_flatten_attributes((SVG_Element*)node, &atts);
221 1 : if (!atts.font_family) return;
222 :
223 : /*register font to font manager*/
224 1 : GF_SAFEALLOC(font, GF_Font);
225 1 : if (!font) {
226 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate svg font\n"));
227 : return;
228 : }
229 1 : e = gf_font_manager_register_font(compositor->font_manager, font);
230 1 : if (e) {
231 0 : gf_free(font);
232 0 : return;
233 : }
234 1 : font->ft_mgr = compositor->font_manager;
235 1 : font->compositor = compositor;
236 :
237 1 : font->get_glyphs = svg_font_get_glyphs;
238 1 : font->load_glyph = svg_font_load_glyph;
239 1 : font->udta = node_font;
240 1 : gf_node_set_private(node_font, font);
241 1 : gf_node_set_callback_function(node_font, svg_traverse_font);
242 1 : font->name = gf_strdup(atts.font_family->value);
243 :
244 1 : 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 1 : font->ascent = atts.ascent ? FIX2INT( gf_ceil(atts.ascent->value) ) : 0;
250 1 : if (!font->ascent) font->ascent = font->em_size;
251 1 : font->descent = atts.descent ? FIX2INT( gf_ceil(atts.descent->value) ) : 0;
252 1 : font->baseline = atts.alphabetic ? FIX2INT( gf_ceil(atts.alphabetic->value) ) : 0;
253 1 : font->line_spacing = font->em_size;
254 1 : font->styles = 0;
255 1 : if (atts.font_style) {
256 0 : switch (*atts.font_style) {
257 0 : case SVG_FONTSTYLE_ITALIC:
258 0 : font->styles |= GF_FONT_ITALIC;
259 0 : break;
260 0 : case SVG_FONTSTYLE_OBLIQUE:
261 0 : font->styles |= GF_FONT_OBLIQUE;
262 0 : break;
263 : }
264 : }
265 1 : if (atts.font_variant && (*atts.font_variant ==SVG_FONTVARIANT_SMALLCAPS))
266 0 : font->styles |= GF_FONT_SMALLCAPS;
267 :
268 1 : if (atts.font_weight) {
269 0 : switch(*atts.font_weight) {
270 0 : case SVG_FONTWEIGHT_100:
271 0 : font->styles |= GF_FONT_WEIGHT_100;
272 0 : break;
273 0 : case SVG_FONTWEIGHT_LIGHTER:
274 0 : font->styles |= GF_FONT_WEIGHT_LIGHTER;
275 0 : break;
276 0 : case SVG_FONTWEIGHT_200:
277 0 : font->styles |= GF_FONT_WEIGHT_200;
278 0 : break;
279 0 : case SVG_FONTWEIGHT_300:
280 0 : font->styles |= GF_FONT_WEIGHT_300;
281 0 : break;
282 0 : case SVG_FONTWEIGHT_400:
283 0 : font->styles |= GF_FONT_WEIGHT_400;
284 0 : break;
285 0 : case SVG_FONTWEIGHT_NORMAL:
286 0 : font->styles |= GF_FONT_WEIGHT_NORMAL;
287 0 : break;
288 0 : case SVG_FONTWEIGHT_500:
289 0 : font->styles |= GF_FONT_WEIGHT_500;
290 0 : break;
291 0 : case SVG_FONTWEIGHT_600:
292 0 : font->styles |= GF_FONT_WEIGHT_600;
293 0 : break;
294 0 : case SVG_FONTWEIGHT_700:
295 0 : font->styles |= GF_FONT_WEIGHT_700;
296 0 : break;
297 0 : case SVG_FONTWEIGHT_BOLD:
298 0 : font->styles |= GF_FONT_WEIGHT_BOLD;
299 0 : break;
300 0 : case SVG_FONTWEIGHT_800:
301 0 : font->styles |= GF_FONT_WEIGHT_800;
302 0 : break;
303 0 : case SVG_FONTWEIGHT_900:
304 0 : font->styles |= GF_FONT_WEIGHT_900;
305 0 : break;
306 0 : case SVG_FONTWEIGHT_BOLDER:
307 0 : font->styles |= GF_FONT_WEIGHT_BOLDER;
308 0 : break;
309 : }
310 : }
311 :
312 1 : gf_svg_flatten_attributes((SVG_Element*)node_font, &atts);
313 1 : font->max_advance_h = atts.horiz_adv_x ? FIX2INT( gf_ceil(atts.horiz_adv_x->value) ) : 0;
314 :
315 1 : font->not_loaded = 1;
316 :
317 : /*wait for onLoad event before activating the font, otherwise we may not have all the glyphs*/
318 1 : handler = gf_dom_listener_build(node_font, GF_EVENT_LOAD, 0);
319 1 : handler->handle_event = svg_font_on_load;
320 : }
321 :
322 :
323 6 : static void svg_traverse_glyph(GF_Node *node, void *rs, Bool is_destroy)
324 : {
325 6 : if (is_destroy) {
326 : GF_Font *font;
327 : GF_Glyph *prev_glyph, *a_glyph;
328 6 : SVG_GlyphStack *st = gf_node_get_private(node);
329 6 : if (st->unicode) gf_free(st->unicode);
330 :
331 6 : font = st->font;
332 : prev_glyph = NULL;
333 6 : a_glyph = font->glyph;
334 12 : while (a_glyph) {
335 6 : if (a_glyph == &st->glyph) break;
336 : prev_glyph = a_glyph;
337 0 : a_glyph = a_glyph->next;
338 : }
339 6 : if (prev_glyph) {
340 0 : prev_glyph->next = st->glyph.next;
341 : } else {
342 6 : font->glyph = st->glyph.next;
343 : }
344 6 : gf_free(st);
345 : }
346 6 : }
347 :
348 8 : 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 8 : GF_Node *node_font = gf_node_get_parent(node, 0);
359 :
360 : /*locate the font node*/
361 8 : if (node_font) node_font = gf_node_get_parent(node, 0);
362 10 : if (!node_font || (gf_node_get_tag(node_font)!=TAG_SVG_font) ) return;
363 6 : font = gf_node_get_private(node_font);
364 6 : if (!font) return;
365 :
366 6 : gf_svg_flatten_attributes((SVG_Element*)node, &atts);
367 :
368 6 : if (gf_node_get_tag(node)==TAG_SVG_missing_glyph) {
369 1 : GF_SAFEALLOC(st, SVG_GlyphStack);
370 1 : if (!st) return;
371 : goto reg_common;
372 : }
373 : /*we must have unicode specified*/
374 5 : if (!atts.unicode) return;
375 :
376 5 : GF_SAFEALLOC(st, SVG_GlyphStack);
377 5 : if (!st) return;
378 5 : utf8 = (u8 *) *atts.unicode;
379 5 : len = gf_utf8_mbstowcs(utf_name, 200, (const char **) &utf8);
380 : /*this is a single glyph*/
381 5 : if (len==1) {
382 5 : st->glyph.utf_name = utf_name[0];
383 5 : st->uni_len = 1;
384 : } else {
385 0 : st->glyph.utf_name = (u32) (PTR_TO_U_CAST st);
386 0 : st->unicode = gf_malloc(sizeof(u16)*len);
387 0 : st->uni_len = (u16) len;
388 : memcpy(st->unicode, utf_name, sizeof(u16)*len);
389 : }
390 :
391 6 : reg_common:
392 6 : st->glyph.ID = (u32)(PTR_TO_U_CAST st);
393 6 : st->font = font;
394 6 : st->glyph.horiz_advance = font->max_advance_h;
395 6 : if (atts.horiz_adv_x) st->glyph.horiz_advance = FIX2INT( gf_ceil(atts.horiz_adv_x->value) );
396 6 : if (atts.d) {
397 6 : st->glyph.path = atts.d;
398 6 : gf_path_get_bounds(atts.d, &rc);
399 6 : st->glyph.width = FIX2INT( gf_ceil(rc.width) );
400 6 : st->glyph.height = FIX2INT( gf_ceil(rc.height) );
401 : }
402 6 : st->glyph.vert_advance = st->glyph.height;
403 6 : if (!st->glyph.vert_advance)
404 0 : st->glyph.vert_advance = font->max_advance_v;
405 :
406 : /*register glyph*/
407 6 : if (!font->glyph) {
408 1 : font->glyph = &st->glyph;
409 : } else {
410 : glyph = font->glyph;
411 15 : while (glyph->next) glyph = glyph->next;
412 5 : glyph->next = &st->glyph;
413 : }
414 :
415 6 : gf_node_set_private(node, st);
416 6 : 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 :
428 0 : 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 0 : gf_svg_flatten_attributes((SVG_Element*)node, &atts);
434 0 : if (!atts.xlink_href) return 0;
435 :
436 0 : if (atts.xlink_href->type == XMLRI_ELEMENTID) {
437 0 : 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 0 : char *font_name = strchr(atts.xlink_href->string, '#');
441 0 : if (!font_name) return 0;
442 0 : if (!st->mo) {
443 0 : st->mo = gf_mo_load_xlink_resource(node, 0, 0, -1);
444 0 : if (!st->mo) {
445 0 : st->compositor->fonts_pending--;
446 0 : return 0;
447 : }
448 : }
449 0 : ext_sg = gf_mo_get_scenegraph(st->mo);
450 0 : if (!ext_sg) {
451 0 : st->compositor->fonts_pending--;
452 0 : return 0;
453 : }
454 0 : atts.xlink_href->target = gf_sg_find_node_by_name(ext_sg, font_name+1);
455 0 : if (!atts.xlink_href->target) {
456 0 : st->compositor->fonts_pending--;
457 0 : return 0;
458 : }
459 : }
460 0 : font_elt = atts.xlink_href->target;
461 0 : if (gf_node_get_tag(font_elt) != TAG_SVG_font) {
462 0 : st->compositor->fonts_pending--;
463 0 : return 0;
464 : }
465 0 : font = gf_node_get_private(font_elt);
466 0 : if (!font) {
467 0 : st->compositor->fonts_pending--;
468 0 : return 0;
469 : }
470 :
471 0 : st->alias = font;
472 :
473 0 : gf_mo_is_done(st->mo);
474 0 : font->not_loaded = 0;
475 0 : return 1;
476 : }
477 :
478 0 : GF_Font *svg_font_uri_get_alias(void *udta)
479 : {
480 : GF_Node *node = (GF_Node *)udta;
481 0 : FontURIStack *st = gf_node_get_private(node);
482 0 : if (!st->alias && !svg_font_uri_check(node, st)) {
483 : return NULL;
484 : }
485 0 : return st->alias;
486 : }
487 :
488 0 : 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 0 : return GF_URL_ERROR;
491 : }
492 :
493 0 : static GF_Glyph *svg_font_uri_load_glyph(void *udta, u32 glyph_name)
494 : {
495 0 : return NULL;
496 : }
497 :
498 0 : static void svg_traverse_font_face_uri(GF_Node *node, void *rs, Bool is_destroy)
499 : {
500 0 : if (is_destroy) {
501 0 : FontURIStack *st = gf_node_get_private(node);
502 0 : if (st) {
503 0 : gf_font_manager_unregister_font(st->font->ft_mgr, st->font);
504 0 : if (st->font->name) gf_free(st->font->name);
505 0 : gf_free(st->font);
506 0 : if (st->mo) gf_mo_unload_xlink_resource(node, st->mo);
507 0 : gf_free(st);
508 : }
509 : }
510 0 : }
511 :
512 1 : 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 1 : par = gf_node_get_parent(node, 0);
522 2 : if (!par || (gf_node_get_tag(par)!=TAG_SVG_font_face_src)) return;
523 : /*check parent's parent is a font-face*/
524 0 : par = gf_node_get_parent(par, 0);
525 0 : if (!par || (gf_node_get_tag(par)!=TAG_SVG_font_face)) return;
526 :
527 :
528 0 : gf_svg_flatten_attributes((SVG_Element*)node, &atts);
529 0 : if (!atts.xlink_href) return;
530 :
531 : /*get font familly*/
532 0 : gf_svg_flatten_attributes((SVG_Element*)par, &atts);
533 0 : if (!atts.font_family) return;
534 :
535 : /*if font with the same name exists, don't load*/
536 0 : 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 0 : GF_SAFEALLOC(font, GF_Font);
541 0 : if (!font) {
542 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate font for svg font face URI\n"));
543 : return;
544 : }
545 :
546 0 : e = gf_font_manager_register_font(compositor->font_manager, font);
547 0 : if (e) {
548 0 : gf_free(font);
549 0 : return;
550 : }
551 0 : GF_SAFEALLOC(stack, FontURIStack);
552 0 : if (!stack) {
553 0 : gf_free(font);
554 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate svg font face URI stack\n"));
555 : return;
556 : }
557 0 : stack->font = font;
558 0 : stack->compositor = compositor;
559 :
560 0 : font->ft_mgr = compositor->font_manager;
561 :
562 0 : font->get_glyphs = svg_font_uri_get_glyphs;
563 0 : font->load_glyph = svg_font_uri_load_glyph;
564 0 : font->get_alias = svg_font_uri_get_alias;
565 0 : font->udta = node;
566 0 : font->name = gf_strdup(atts.font_family->value);
567 0 : gf_node_set_private(node, stack);
568 0 : gf_node_set_callback_function(node, svg_traverse_font_face_uri);
569 :
570 0 : font->not_loaded = 1;
571 0 : compositor->fonts_pending++;
572 0 : svg_font_uri_check(node, stack);
573 : }
574 :
575 :
576 : #endif /*GPAC_DISABLE_SVG*/
577 :
|