PageRenderTime 740ms CodeModel.GetById 11ms app.highlight 656ms RepoModel.GetById 1ms app.codeStats 4ms

/src/scenegraph/svg_attributes.c

https://github.com/svettom/gpac
C | 6454 lines | 5969 code | 326 blank | 159 comment | 1469 complexity | 18d4b2816d8a3b02f0d6947c3f58ec2a MD5 | raw file
   1/*
   2 *					GPAC Multimedia Framework
   3 *
   4 *			Authors: Cyril Concolato, Jean Le Feuvre
   5 *			Copyright (c) Telecom ParisTech 2004-2012
   6 *					All rights reserved
   7 *
   8 *  This file is part of GPAC / SVG Loader module
   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 "../../include/gpac/base_coding.h"
  27#include "../../include/gpac/events.h"
  28#include "../../include/gpac/nodes_svg.h"
  29
  30#ifndef GPAC_DISABLE_SVG
  31
  32#include "../../include/gpac/internal/scenegraph_dev.h"
  33
  34#define DUMP_COORDINATES 1
  35
  36
  37static const struct dom_event_def {u32 event;  const char *name; u32 category; } defined_dom_events [] =
  38{
  39	{ GF_EVENT_ABORT, "abort", GF_DOM_EVENT_DOM },
  40	{ GF_EVENT_ERROR, "error", GF_DOM_EVENT_DOM },
  41	{ GF_EVENT_LOAD, "load", GF_DOM_EVENT_DOM },
  42	{ GF_EVENT_UNLOAD, "unload", GF_DOM_EVENT_DOM },
  43
  44	/*focus - we differentiate from UI/key events to avoid browing focus if no listener is on place*/
  45	{ GF_EVENT_FOCUSIN, "DOMFocusIn", GF_DOM_EVENT_FOCUS },
  46	{ GF_EVENT_FOCUSIN, "focusin", GF_DOM_EVENT_FOCUS },
  47	{ GF_EVENT_FOCUSOUT, "DOMFocusOut", GF_DOM_EVENT_FOCUS },
  48	{ GF_EVENT_FOCUSOUT, "focusout", GF_DOM_EVENT_FOCUS },
  49	{ GF_EVENT_CHANGE, "change", GF_DOM_EVENT_FOCUS },
  50	{ GF_EVENT_FOCUS, "focus", GF_DOM_EVENT_FOCUS },
  51	{ GF_EVENT_BLUR, "blur", GF_DOM_EVENT_FOCUS },
  52
  53	/*key events*/
  54	{ GF_EVENT_KEYDOWN, "keydown", GF_DOM_EVENT_KEY },
  55	{ GF_EVENT_KEYDOWN, "accesskey", GF_DOM_EVENT_KEY },
  56	{ GF_EVENT_KEYDOWN, "keypress", GF_DOM_EVENT_KEY },
  57	{ GF_EVENT_KEYUP, "keyup", GF_DOM_EVENT_KEY },
  58	{ GF_EVENT_LONGKEYPRESS, "longaccesskey", GF_DOM_EVENT_KEY },
  59
  60	{ GF_EVENT_CLICK, "click", GF_DOM_EVENT_MOUSE },
  61	{ GF_EVENT_DBLCLICK, "dblclick", GF_DOM_EVENT_MOUSE },
  62	{ GF_EVENT_MOUSEDOWN, "mousedown", GF_DOM_EVENT_MOUSE },
  63	{ GF_EVENT_MOUSEMOVE, "mousemove", GF_DOM_EVENT_MOUSE },
  64	{ GF_EVENT_MOUSEOUT, "mouseout", GF_DOM_EVENT_MOUSE },
  65	{ GF_EVENT_MOUSEOVER, "mouseover", GF_DOM_EVENT_MOUSE },
  66	{ GF_EVENT_MOUSEUP, "mouseup", GF_DOM_EVENT_MOUSE },
  67	{ GF_EVENT_MOUSEWHEEL, "wheel", GF_DOM_EVENT_MOUSE },
  68	{ GF_EVENT_MOUSEWHEEL, "SVGMousewheel", GF_DOM_EVENT_MOUSE },
  69
  70	/*activate is not a basic DOM but a MOUSE and KEY event*/
  71	{ GF_EVENT_ACTIVATE, "activate", GF_DOM_EVENT_MOUSE | GF_DOM_EVENT_KEY },
  72	{ GF_EVENT_ACTIVATE, "DOMActivate", GF_DOM_EVENT_MOUSE | GF_DOM_EVENT_KEY },
  73
  74	/*text events*/
  75	{ GF_EVENT_TEXTINPUT, "textInput", GF_DOM_EVENT_TEXT },
  76	{ GF_EVENT_TEXTSELECT, "select", GF_DOM_EVENT_TEXT },
  77
  78	/*SMIL events*/
  79	{ GF_EVENT_BEGIN, "begin", GF_DOM_EVENT_FAKE },
  80	{ GF_EVENT_BEGIN_EVENT, "beginEvent", GF_DOM_EVENT_SMIL },
  81	{ GF_EVENT_END, "end", GF_DOM_EVENT_FAKE },
  82	{ GF_EVENT_END_EVENT, "endEvent", GF_DOM_EVENT_SMIL },
  83	{ GF_EVENT_REPEAT, "repeat", GF_DOM_EVENT_FAKE },
  84	{ GF_EVENT_REPEAT_EVENT, "repeatEvent", GF_DOM_EVENT_SMIL },
  85
  86	/*all SVG/HTML/... UI events*/
  87	{ GF_EVENT_RESIZE, "resize", GF_DOM_EVENT_UI },
  88	{ GF_EVENT_SCROLL, "scroll", GF_DOM_EVENT_UI },
  89	{ GF_EVENT_ZOOM, "zoom", GF_DOM_EVENT_UI },
  90
  91
  92	{ GF_EVENT_LOAD, "SVGLoad", GF_DOM_EVENT_DOM },
  93	{ GF_EVENT_RESIZE, "SVGResize", GF_DOM_EVENT_UI },
  94	{ GF_EVENT_SCROLL, "SVGScroll", GF_DOM_EVENT_UI },
  95	{ GF_EVENT_ZOOM, "SVGZoom", GF_DOM_EVENT_UI },
  96
  97	/*mutation events and DCCI*/
  98	{ GF_EVENT_TREE_MODIFIED, "DOMSubtreeModified", GF_DOM_EVENT_MUTATION },
  99	{ GF_EVENT_NODE_INSERTED, "DOMNodeInserted", GF_DOM_EVENT_MUTATION },
 100	{ GF_EVENT_NODE_REMOVED, "DOMNodeRemoved", GF_DOM_EVENT_MUTATION },
 101	{ GF_EVENT_NODE_REMOVED_DOC, "DOMNodeRemovedFromDocument", GF_DOM_EVENT_MUTATION },
 102	{ GF_EVENT_NODE_INSERTED_DOC, "DOMNodeInsertedIntoDocument", GF_DOM_EVENT_MUTATION },
 103	{ GF_EVENT_ATTR_MODIFIED, "DOMAttrModified", GF_DOM_EVENT_MUTATION },
 104	{ GF_EVENT_CHAR_DATA_MODIFIED, "DOMCharacterDataModified", GF_DOM_EVENT_MUTATION },
 105	{ GF_EVENT_NODE_NAME_CHANGED, "DOMElementNameChanged", GF_DOM_EVENT_MUTATION },
 106	{ GF_EVENT_ATTR_NAME_CHANGED, "DOMAttributeNameChanged", GF_DOM_EVENT_MUTATION },
 107	{ GF_EVENT_DCCI_PROP_CHANGE, "DCCI-prop-change", GF_DOM_EVENT_MUTATION },
 108
 109	/*LASeR events - some events are attached to other categorues*/
 110	{ GF_EVENT_ACTIVATED, "activatedEvent", GF_DOM_EVENT_LASER },
 111	{ GF_EVENT_DEACTIVATED, "deactivatedEvent", GF_DOM_EVENT_LASER },
 112	{ GF_EVENT_EXECUTION_TIME, "executionTime", GF_DOM_EVENT_FAKE },
 113	{ GF_EVENT_PAUSE, "pause", GF_DOM_EVENT_SMIL },
 114	{ GF_EVENT_PAUSED_EVENT, "pausedEvent", GF_DOM_EVENT_SMIL },
 115	{ GF_EVENT_PLAY, "play", GF_DOM_EVENT_SMIL },
 116	{ GF_EVENT_RESUME_EVENT, "resumedEvent", GF_DOM_EVENT_SMIL },
 117	{ GF_EVENT_REPEAT_KEY, "repeatKey", GF_DOM_EVENT_KEY },
 118	{ GF_EVENT_SHORT_ACCESSKEY, "shortAccessKey", GF_DOM_EVENT_KEY },
 119
 120	/*LASeR unofficial events*/
 121	{ GF_EVENT_BATTERY, "battery", GF_DOM_EVENT_LASER },
 122	{ GF_EVENT_CPU, "cpu", GF_DOM_EVENT_LASER },
 123
 124	/*MediaAccess events*/
 125#if 0
 126	{ GF_EVENT_MEDIA_BEGIN_SESSION_SETUP, "BeginSessionSetup", GF_DOM_EVENT_MEDIA_ACCESS },
 127	{ GF_EVENT_MEDIA_END_SESSION_SETUP, "EndSessionSetup", GF_DOM_EVENT_MEDIA_ACCESS },
 128	{ GF_EVENT_MEDIA_DATA_REQUEST, "DataRequest", GF_DOM_EVENT_MEDIA_ACCESS },
 129	{ GF_EVENT_MEDIA_PLAYABLE, "Playable", GF_DOM_EVENT_MEDIA_ACCESS },
 130	{ GF_EVENT_MEDIA_NOT_PLAYABLE, "NotPlayable", GF_DOM_EVENT_MEDIA_ACCESS },
 131	{ GF_EVENT_MEDIA_DATA_PROGRESS, "DataReceptionProgress", GF_DOM_EVENT_MEDIA_ACCESS },
 132	{ GF_EVENT_MEDIA_END_OF_DATA, "EndOfDataReception", GF_DOM_EVENT_MEDIA_ACCESS },
 133	{ GF_EVENT_MEDIA_STOP, "Stop", GF_DOM_EVENT_MEDIA_ACCESS },
 134	{ GF_EVENT_MEDIA_ERROR, "Error", GF_DOM_EVENT_MEDIA_ACCESS },
 135#endif
 136
 137	{ GF_EVENT_MEDIA_SETUP_BEGIN, "setupbegin", GF_DOM_EVENT_MEDIA},
 138	{ GF_EVENT_MEDIA_SETUP_DONE, "setupdone", GF_DOM_EVENT_MEDIA},
 139
 140	{ GF_EVENT_MEDIA_LOAD_START, "loadstart", GF_DOM_EVENT_MEDIA },
 141	{ GF_EVENT_MEDIA_LOAD_DONE, "loaddone", GF_DOM_EVENT_MEDIA },
 142	{ GF_EVENT_MEDIA_PROGRESS, "progress", GF_DOM_EVENT_MEDIA },
 143	{ GF_EVENT_MEDIA_SUSPEND, "suspend", GF_DOM_EVENT_MEDIA },
 144	{ GF_EVENT_ABORT, "abort", GF_DOM_EVENT_MEDIA },
 145	{ GF_EVENT_ERROR, "error", GF_DOM_EVENT_MEDIA },
 146	{ GF_EVENT_MEDIA_EMPTIED, "emptied", GF_DOM_EVENT_MEDIA },
 147	{ GF_EVENT_MEDIA_STALLED, "stalled", GF_DOM_EVENT_MEDIA },
 148	{ GF_EVENT_MEDIA_LOADED_METADATA, "loadedmetadata", GF_DOM_EVENT_MEDIA },
 149	{ GF_EVENT_MEDIA_LODADED_DATA, "loadeddata", GF_DOM_EVENT_MEDIA },
 150	{ GF_EVENT_MEDIA_CANPLAY, "canplay", GF_DOM_EVENT_MEDIA },
 151	{ GF_EVENT_MEDIA_CANPLAYTHROUGH, "canplaythrough", GF_DOM_EVENT_MEDIA },
 152	{ GF_EVENT_MEDIA_PLAYING, "playing", GF_DOM_EVENT_MEDIA },
 153	{ GF_EVENT_MEDIA_WAITING, "waiting", GF_DOM_EVENT_MEDIA },
 154	{ GF_EVENT_MEDIA_SEEKING, "seeking", GF_DOM_EVENT_MEDIA },
 155	{ GF_EVENT_MEDIA_SEEKED, "seeked", GF_DOM_EVENT_MEDIA },
 156	{ GF_EVENT_MEDIA_ENDED, "ended", GF_DOM_EVENT_MEDIA },
 157	{ GF_EVENT_MEDIA_DURATION_CHANGED, "durationchanged", GF_DOM_EVENT_MEDIA },
 158	{ GF_EVENT_MEDIA_TIME_UPDATE, "timeupdate", GF_DOM_EVENT_MEDIA },
 159	{ GF_EVENT_PLAY, "play", GF_DOM_EVENT_MEDIA },
 160	{ GF_EVENT_PAUSE, "pause", GF_DOM_EVENT_MEDIA },
 161	{ GF_EVENT_MEDIA_RATECHANGE, "ratechange", GF_DOM_EVENT_MEDIA },
 162	{ GF_EVENT_MEDIA_VOLUME_CHANGED, "volumechange", GF_DOM_EVENT_MEDIA },
 163
 164	/* Media Source Events */
 165	{ GF_EVENT_HTML_MSE_SOURCE_OPEN, "sourceopen", GF_DOM_EVENT_MEDIASOURCE },
 166	{ GF_EVENT_HTML_MSE_SOURCE_ENDED, "sourceended", GF_DOM_EVENT_MEDIASOURCE },
 167	{ GF_EVENT_HTML_MSE_SOURCE_CLOSE, "sourceclose", GF_DOM_EVENT_MEDIASOURCE },
 168	{ GF_EVENT_HTML_MSE_APPEND_START, "appendstart", GF_DOM_EVENT_MEDIASOURCE },
 169	{ GF_EVENT_HTML_MSE_APPEND_END, "appendend", GF_DOM_EVENT_MEDIASOURCE },
 170	{ GF_EVENT_HTML_MSE_APPEND_ERROR, "error", GF_DOM_EVENT_MEDIASOURCE },
 171	{ GF_EVENT_HTML_MSE_APPEND_ABORT, "abort", GF_DOM_EVENT_MEDIASOURCE },
 172	{ GF_EVENT_HTML_MSE_ADD_SOURCE_BUFFER, "addsourcebuffer", GF_DOM_EVENT_MEDIASOURCE },
 173	{ GF_EVENT_HTML_MSE_REMOVE_SOURCE_BUFFER, "removesourcebuffer", GF_DOM_EVENT_MEDIASOURCE },
 174
 175	/*GPAC internals*/
 176	{ GF_EVENT_SCENE_ATTACHED, "gpac_scene_attached", GF_DOM_EVENT_DOM },
 177	{ GF_EVENT_VP_RESIZE, "gpac_vp_changed", GF_DOM_EVENT_DOM },
 178};
 179
 180GF_EXPORT
 181u32 gf_dom_event_type_by_name(const char *name)
 182{
 183	u32 i, count;
 184	count = sizeof(defined_dom_events) / sizeof(struct dom_event_def);
 185	if (!name) return GF_EVENT_UNKNOWN;
 186	if ((name[0]=='o') && (name[1]=='n')) name += 2;
 187	for (i=0;i<count;i++) {
 188		if (!strcmp(name, defined_dom_events[i].name))
 189			return defined_dom_events[i].event;
 190	}
 191	return GF_EVENT_UNKNOWN;
 192}
 193
 194const char *gf_dom_event_get_name(u32 type)
 195{
 196	u32 i, count;
 197	count = sizeof(defined_dom_events) / sizeof(struct dom_event_def);
 198	for (i=0;i<count;i++) {
 199		if (defined_dom_events[i].event == type)
 200			return defined_dom_events[i].name;
 201	}
 202	return "unknown";
 203}
 204
 205u32 gf_dom_event_get_category(u32 type)
 206{
 207	u32 i, count;
 208	count = sizeof(defined_dom_events) / sizeof(struct dom_event_def);
 209	for (i=0;i<count;i++) {
 210		if (defined_dom_events[i].event == type)
 211			return defined_dom_events[i].category;
 212	}
 213	return 0;
 214}
 215
 216
 217static const struct predef_keyid {u32 key_code;  const char *name; } predefined_key_identifiers[] =
 218{
 219	{ GF_KEY_ACCEPT, "Accept" },
 220	{ GF_KEY_AGAIN, "Again" },
 221	{ GF_KEY_ALLCANDIDATES, "AllCandidates" },
 222	{ GF_KEY_ALPHANUM, "Alphanumeric" },
 223	{ GF_KEY_ALT, "Alt" },
 224	{ GF_KEY_ALTGRAPH, "AltGraph" },
 225	{ GF_KEY_APPS, "Apps" },
 226	{ GF_KEY_ATTN, "Attn" },
 227	{ GF_KEY_BROWSERBACK, "BrowserBack" },
 228	{ GF_KEY_BROWSERFAVORITES, "BrowserFavorites" },
 229	{ GF_KEY_BROWSERFORWARD, "BrowserForward" },
 230	{ GF_KEY_BROWSERHOME, "BrowserHome" },
 231	{ GF_KEY_BROWSERREFRESH, "BrowserRefresh" },
 232	{ GF_KEY_BROWSERSEARCH, "BrowserSearch" },
 233	{ GF_KEY_BROWSERSTOP, "BrowserStop" },
 234	{ GF_KEY_CAPSLOCK, "CapsLock" },
 235	{ GF_KEY_CLEAR, "Clear" },
 236	{ GF_KEY_CODEINPUT, "CodeInput" },
 237	{ GF_KEY_COMPOSE, "Compose" },
 238	{ GF_KEY_CONTROL, "Control" },
 239	{ GF_KEY_CRSEL, "Crsel" },
 240	{ GF_KEY_CONVERT, "Convert" },
 241	{ GF_KEY_COPY, "Copy"  },
 242	{ GF_KEY_CUT, "Cut" },
 243	{ GF_KEY_DOWN, "Down" },
 244	{ GF_KEY_END, "End" },
 245	{ GF_KEY_ENTER, "Enter" },
 246	{ GF_KEY_ERASEEOF, "EraseEof" },
 247	{ GF_KEY_EXECUTE, "Execute" },
 248	{ GF_KEY_EXSEL, "Exsel" },
 249	{ GF_KEY_F1, "F1" },
 250	{ GF_KEY_F2, "F2" },
 251	{ GF_KEY_F3, "F3" },
 252	{ GF_KEY_F4, "F4" },
 253	{ GF_KEY_F5, "F5" },
 254	{ GF_KEY_F6, "F6" },
 255	{ GF_KEY_F7, "F7" },
 256	{ GF_KEY_F8, "F8" },
 257	{ GF_KEY_F9, "F9" },
 258	{ GF_KEY_F10, "F10" },
 259	{ GF_KEY_F11, "F11" },
 260	{ GF_KEY_F12, "F12" },
 261	{ GF_KEY_F13, "F13" },
 262	{ GF_KEY_F14, "F14" },
 263	{ GF_KEY_F15, "F15" },
 264	{ GF_KEY_F16, "F16" },
 265	{ GF_KEY_F17, "F17" },
 266	{ GF_KEY_F18, "F18" },
 267	{ GF_KEY_F19, "F19" },
 268	{ GF_KEY_F20, "F20" },
 269	{ GF_KEY_F21, "F21" },
 270	{ GF_KEY_F22, "F22" },
 271	{ GF_KEY_F23, "F23" },
 272	{ GF_KEY_F24, "F24" },
 273	{ GF_KEY_FINALMODE, "FinalMode" },
 274	{ GF_KEY_FIND, "Find" },
 275	{ GF_KEY_FULLWIDTH, "FullWidth" },
 276	{ GF_KEY_HALFWIDTH, "HalfWidth" },
 277	{ GF_KEY_HANGULMODE, "HangulMode" },
 278	{ GF_KEY_HANJAMODE, "HanjaMode"   },
 279	{ GF_KEY_HELP, "Help" },
 280	{ GF_KEY_HIRAGANA, "Hiragana" },
 281	{ GF_KEY_HOME, "Home" },
 282	{ GF_KEY_INSERT, "Insert" },
 283	{ GF_KEY_JAPANESEHIRAGANA, "JapaneseHiragana" },
 284	{ GF_KEY_JAPANESEKATAKANA, "JapaneseKatakana" },
 285	{ GF_KEY_JAPANESEROMAJI, "JapaneseRomaji" },
 286	{ GF_KEY_JUNJAMODE, "JunjaMode" },
 287	{ GF_KEY_KANAMODE, "KanaMode"   },
 288	{ GF_KEY_KANJIMODE, "KanjiMode" },
 289	{ GF_KEY_KATAKANA, "Katakana"   },
 290	{ GF_KEY_LAUNCHAPPLICATION1, "LaunchApplication1" },
 291	{ GF_KEY_LAUNCHAPPLICATION2, "LaunchApplication2" },
 292	{ GF_KEY_LAUNCHMAIL, "LaunchMail" },
 293	{ GF_KEY_LEFT, "Left" },
 294	{ GF_KEY_META, "Meta" },
 295	{ GF_KEY_MEDIANEXTTRACK, "MediaNextTrack" },
 296	{ GF_KEY_MEDIAPLAYPAUSE, "MediaPlayPause" },
 297	{ GF_KEY_MEDIAPREVIOUSTRACK, "MediaPreviousTrack" },
 298	{ GF_KEY_MEDIASTOP, "MediaStop" },
 299	{ GF_KEY_MODECHANGE, "ModeChange" },
 300	{ GF_KEY_NONCONVERT, "Nonconvert" },
 301	{ GF_KEY_NUMLOCK, "NumLock" },
 302	{ GF_KEY_PAGEDOWN, "PageDown" },
 303	{ GF_KEY_PAGEUP, "PageUp" },
 304	{ GF_KEY_PASTE, "Paste" },
 305	{ GF_KEY_PAUSE, "Pause" },
 306	{ GF_KEY_PLAY, "Play" },
 307	{ GF_KEY_PREVIOUSCANDIDATE, "PreviousCandidate" },
 308	{ GF_KEY_PRINTSCREEN, "PrintScreen" },
 309	{ GF_KEY_PROCESS, "Process" },
 310	{ GF_KEY_PROPS, "Props" },
 311	{ GF_KEY_RIGHT, "Right" },
 312	{ GF_KEY_ROMANCHARACTERS, "RomanCharacters" },
 313	{ GF_KEY_SCROLL, "Scroll" },
 314	{ GF_KEY_SELECT, "Select" },
 315	{ GF_KEY_SELECTMEDIA, "SelectMedia" },
 316	{ GF_KEY_SHIFT, "Shift" },
 317	{ GF_KEY_STOP, "Stop" },
 318	{ GF_KEY_UP, "Up" },
 319	{ GF_KEY_UNDO, "Undo" },
 320	{ GF_KEY_VOLUMEDOWN, "VolumeDown" },
 321	{ GF_KEY_VOLUMEMUTE, "VolumeMute" },
 322	{ GF_KEY_VOLUMEUP, "VolumeUp" },
 323	{ GF_KEY_WIN, "Win" },
 324	{ GF_KEY_ZOOM, "Zoom" },
 325	{ GF_KEY_BACKSPACE, "U+0008" },
 326	{ GF_KEY_TAB, "U+0009" },
 327	{ GF_KEY_CANCEL, "U+0018" },
 328	{ GF_KEY_ESCAPE, "U+001B" },
 329	{ GF_KEY_SPACE, "U+0020" },
 330	{ GF_KEY_EXCLAMATION, "U+0021" },
 331	{ GF_KEY_QUOTATION, "U+0022" },
 332	{ GF_KEY_NUMBER, "U+0023" },
 333	{ GF_KEY_DOLLAR, "U+0024" },
 334	{ GF_KEY_AMPERSAND, "U+0026" },
 335	{ GF_KEY_APOSTROPHE, "U+0027" },
 336	{ GF_KEY_LEFTPARENTHESIS, "U+0028" },
 337	{ GF_KEY_RIGHTPARENTHESIS, "U+0029" },
 338	{ GF_KEY_STAR, "U+002A" },
 339	{ GF_KEY_PLUS, "U+002B" },
 340	{ GF_KEY_COMMA, "U+002C" },
 341	{ GF_KEY_HYPHEN, "U+002D" },
 342	{ GF_KEY_FULLSTOP, "U+002E" },
 343	{ GF_KEY_SLASH, "U+002F" },
 344	{ GF_KEY_0, "U+0030" },
 345	{ GF_KEY_1, "U+0031" },
 346	{ GF_KEY_2, "U+0032" },
 347	{ GF_KEY_3, "U+0033" },
 348	{ GF_KEY_4, "U+0034" },
 349	{ GF_KEY_5, "U+0035" },
 350	{ GF_KEY_6, "U+0036" },
 351	{ GF_KEY_7, "U+0037" },
 352	{ GF_KEY_8, "U+0038" },
 353	{ GF_KEY_9, "U+0039" },
 354	{ GF_KEY_COLON, "U+003A" },
 355	{ GF_KEY_SEMICOLON, "U+003B" },
 356	{ GF_KEY_LESSTHAN, "U+003C" },
 357	{ GF_KEY_EQUALS, "U+003D" },
 358	{ GF_KEY_GREATERTHAN, "U+003E" },
 359	{ GF_KEY_QUESTION, "U+003F" },
 360	{ GF_KEY_AT, "U+0040" },
 361	{ GF_KEY_A, "U+0041" },
 362	{ GF_KEY_B, "U+0042" },
 363	{ GF_KEY_C, "U+0043" },
 364	{ GF_KEY_D, "U+0044" },
 365	{ GF_KEY_E, "U+0045" },
 366	{ GF_KEY_F, "U+0046" },
 367	{ GF_KEY_G, "U+0047" },
 368	{ GF_KEY_H, "U+0048" },
 369	{ GF_KEY_I, "U+0049" },
 370	{ GF_KEY_J, "U+004A" },
 371	{ GF_KEY_K, "U+004B" },
 372	{ GF_KEY_L, "U+004C" },
 373	{ GF_KEY_M, "U+004D" },
 374	{ GF_KEY_N, "U+004E" },
 375	{ GF_KEY_O, "U+004F" },
 376	{ GF_KEY_P, "U+0050" },
 377	{ GF_KEY_Q, "U+0051" },
 378	{ GF_KEY_R, "U+0052" },
 379	{ GF_KEY_S, "U+0053" },
 380	{ GF_KEY_T, "U+0054" },
 381	{ GF_KEY_U, "U+0055" },
 382	{ GF_KEY_V, "U+0056" },
 383	{ GF_KEY_W, "U+0057" },
 384	{ GF_KEY_X, "U+0058" },
 385	{ GF_KEY_Y, "U+0059" },
 386	{ GF_KEY_Z, "U+005A" },
 387	{ GF_KEY_LEFTSQUAREBRACKET, "U+005B" },
 388	{ GF_KEY_BACKSLASH, "U+005C" },
 389	{ GF_KEY_RIGHTSQUAREBRACKET, "U+005D" },
 390	{ GF_KEY_CIRCUM, "U+005E" },
 391	{ GF_KEY_UNDERSCORE, "U+005F" },
 392	{ GF_KEY_GRAVEACCENT, "U+0060" },
 393	{ GF_KEY_LEFTCURLYBRACKET, "U+007B" },
 394	{ GF_KEY_PIPE, "U+007C" },
 395	{ GF_KEY_RIGHTCURLYBRACKET, "U+007D" },
 396	{ GF_KEY_DEL, "U+007F" },
 397	{ GF_KEY_INVERTEXCLAMATION, "U+00A1" },
 398	{ GF_KEY_DEADGRAVE, "U+0300" },
 399	{ GF_KEY_DEADEACUTE, "U+0301" },
 400	{ GF_KEY_DEADCIRCUM, "U+0302" },
 401	{ GF_KEY_DEADTILDE, "U+0303" },
 402	{ GF_KEY_DEADMACRON, "U+0304" },
 403	{ GF_KEY_DEADBREVE, "U+0306" },
 404	{ GF_KEY_DEADABOVEDOT, "U+0307" },
 405	{ GF_KEY_DEADDIARESIS, "U+0308" },
 406	{ GF_KEY_DEADRINGABOVE, "U+030A" },
 407	{ GF_KEY_DEADDOUBLEACUTE, "U+030B" },
 408	{ GF_KEY_DEADCARON, "U+030C" },
 409	{ GF_KEY_DEADCEDILLA, "U+0327" },
 410	{ GF_KEY_DEADOGONEK, "U+0328" },
 411	{ GF_KEY_DEADIOTA, "U+0345" },
 412	{ GF_KEY_EURO, "U+20AC" },
 413	{ GF_KEY_DEADVOICESOUND, "U+3099" },
 414	{ GF_KEY_DEADSEMIVOICESOUND, "U+309A" },
 415	{ GF_KEY_CHANNELUP, "ChannelUp" },
 416	{ GF_KEY_CHANNELDOWN, "ChannelDown" },
 417	{ GF_KEY_TEXT, "Text" },
 418	{ GF_KEY_INFO, "Info" },
 419	{ GF_KEY_EPG, "EPG" },
 420	{ GF_KEY_RECORD, "Record" },
 421	{ GF_KEY_BEGINPAGE, "BeginPage" }
 422};
 423
 424
 425GF_EXPORT
 426const char *gf_dom_get_key_name(u32 key_identifier)
 427{
 428	u32 count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid);
 429	if (!key_identifier || count<=key_identifier) return "Unknown";
 430	return predefined_key_identifiers[key_identifier-1].name;
 431}
 432
 433
 434u32 gf_dom_get_key_type(char *key_name)
 435{
 436	if (strlen(key_name) == 1) {
 437		char c[2];
 438		c[0] = key_name[0];
 439		c[1] = 0;
 440		strupr(c);
 441		if (c[0] >= 'A' && c[0] <= 'Z')
 442			return (GF_KEY_A + (c[0] - 'A') );
 443
 444		if (c[0] >= '0' && c[0] <= '9')
 445			return ( GF_KEY_0 + (c[0] - '0') );
 446
 447		switch (c[0]) {
 448		case '@': return GF_KEY_AT;
 449		case '*': return GF_KEY_STAR;
 450		case '#': return GF_KEY_NUMBER;
 451		case ' ': return GF_KEY_SPACE;
 452		case '!': return GF_KEY_EXCLAMATION;
 453		case '"': return GF_KEY_QUOTATION;
 454		case '$': return GF_KEY_DOLLAR;
 455		case '&': return GF_KEY_AMPERSAND;
 456		case '\'': return GF_KEY_APOSTROPHE;
 457		case '(': return GF_KEY_LEFTPARENTHESIS;
 458		case ')': return GF_KEY_RIGHTPARENTHESIS;
 459		case '+': return GF_KEY_PLUS;
 460		case ',': return GF_KEY_COMMA;
 461		case '-': return GF_KEY_HYPHEN;
 462		case '.': return GF_KEY_FULLSTOP;
 463		case '/': return GF_KEY_SLASH;
 464		case ':': return GF_KEY_COLON;
 465		case ';': return GF_KEY_SEMICOLON;
 466		case '<': return GF_KEY_LESSTHAN;
 467		case '=': return GF_KEY_EQUALS;
 468		case '>': return GF_KEY_GREATERTHAN;
 469		case '?': return GF_KEY_QUESTION;
 470		case '[': return GF_KEY_LEFTSQUAREBRACKET;
 471		case '\\': return GF_KEY_BACKSLASH;
 472		case ']': return GF_KEY_RIGHTSQUAREBRACKET;
 473		case '^': return GF_KEY_CIRCUM;
 474		case '_': return GF_KEY_UNDERSCORE;
 475		case '`': return GF_KEY_GRAVEACCENT;
 476		case '{': return GF_KEY_LEFTCURLYBRACKET;
 477		case '|': return GF_KEY_PIPE;
 478		case '}': return GF_KEY_RIGHTCURLYBRACKET;
 479		case 'Ą': return GF_KEY_INVERTEXCLAMATION;
 480		default: return GF_KEY_UNIDENTIFIED;
 481		}
 482	} else {
 483		u32 i, count;
 484		count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid);
 485		for (i=0; i<count; i++) {
 486			if (!stricmp(key_name, predefined_key_identifiers[i].name)) {
 487				return predefined_key_identifiers[i].key_code;
 488			}
 489		}
 490		return GF_KEY_UNIDENTIFIED;
 491	}
 492}
 493
 494/* Basic SVG datatype parsing functions */
 495static const struct predef_col { const char *name; u8 r; u8 g; u8 b; } predefined_colors[] =
 496{
 497	{"aliceblue",240, 248, 255},
 498	{"antiquewhite",250, 235, 215},
 499	{"aqua", 0, 255, 255},
 500	{"aquamarine",127, 255, 212},
 501	{"azure",240, 255, 255},
 502	{"beige",245, 245, 220},
 503	{"bisque",255, 228, 196},
 504	{"black", 0, 0, 0},
 505	{"blanchedalmond",255, 235, 205},
 506	{"blue", 0, 0, 255},
 507	{"blueviolet",138, 43, 226},
 508	{"brown",165, 42, 42},
 509	{"burlywood",222, 184, 135},
 510	{"cadetblue", 95, 158, 160},
 511	{"chartreuse",127, 255, 0},
 512	{"chocolate",210, 105, 30},
 513	{"coral",255, 127, 80},
 514	{"lightpink",255, 182, 193},
 515	{"lightsalmon",255, 160, 122},
 516	{"lightseagreen", 32, 178, 170},
 517	{"lightskyblue",135, 206, 250},
 518	{"lightslategray",119, 136, 153},
 519	{"lightslategrey",119, 136, 153},
 520	{"lightsteelblue",176, 196, 222},
 521	{"lightyellow",255, 255, 224},
 522	{"lime", 0, 255, 0},
 523	{"limegreen", 50, 205, 50},
 524	{"linen",250, 240, 230},
 525	{"magenta",255, 0, 255},
 526	{"maroon",128, 0, 0},
 527	{"mediumaquamarine",102, 205, 170},
 528	{"mediumblue", 0, 0, 205},
 529	{"mediumorchid",186, 85, 211},
 530	{"cornflowerblue",100, 149, 237},
 531	{"cornsilk",255, 248, 220},
 532	{"crimson",220, 20, 60},
 533	{"cyan", 0, 255, 255},
 534	{"darkblue", 0, 0, 139},
 535	{"darkcyan", 0, 139, 139},
 536	{"darkgoldenrod",184, 134, 11},
 537	{"darkgray",169, 169, 169},
 538	{"darkgreen", 0, 100, 0},
 539	{"darkgrey",169, 169, 169},
 540	{"darkkhaki",189, 183, 107},
 541	{"darkmagenta",139, 0, 139},
 542	{"darkolivegreen", 85, 107, 47},
 543	{"darkorange",255, 140, 0},
 544	{"darkorchid",153, 50, 204},
 545	{"darkred",139, 0, 0},
 546	{"darksalmon",233, 150, 122},
 547	{"darkseagreen",143, 188, 143},
 548	{"darkslateblue", 72, 61, 139},
 549	{"darkslategray", 47, 79, 79},
 550	{"darkslategrey", 47, 79, 79},
 551	{"darkturquoise", 0, 206, 209},
 552	{"darkviolet",148, 0, 211},
 553	{"deeppink",255, 20, 147},
 554	{"deepskyblue", 0, 191, 255},
 555	{"dimgray",105, 105, 105},
 556	{"dimgrey",105, 105, 105},
 557	{"dodgerblue", 30, 144, 255},
 558	{"firebrick",178, 34, 34},
 559	{"floralwhite",255, 250, 240},
 560	{"forestgreen", 34, 139, 34},
 561	{"fuchsia",255, 0, 255},
 562	{"gainsboro",220, 220, 220},
 563	{"ghostwhite",248, 248, 255},
 564	{"gold",255, 215, 0},
 565	{"goldenrod",218, 165, 32},
 566	{"gray",128, 128, 128},
 567	{"grey",128, 128, 128},
 568	{"green", 0, 128, 0},
 569	{"greenyellow",173, 255, 47},
 570	{"honeydew",240, 255, 240},
 571	{"hotpink",255, 105, 180},
 572	{"indianred",205, 92, 92},
 573	{"indigo", 75, 0, 130},
 574	{"ivory",255, 255, 240},
 575	{"khaki",240, 230, 140},
 576	{"lavender",230, 230, 25},
 577	{"lavenderblush",255, 240, 245},
 578	{"mediumpurple",147, 112, 219},
 579	{"mediumseagreen", 60, 179, 113},
 580	{"mediumslateblue",123, 104, 238},
 581	{"mediumspringgreen", 0, 250, 154},
 582	{"mediumturquoise", 72, 209, 204},
 583	{"mediumvioletred",199, 21, 133},
 584	{"midnightblue", 25, 25, 112},
 585	{"mintcream",245, 255, 250},
 586	{"mistyrose",255, 228, 225},
 587	{"moccasin",255, 228, 181},
 588	{"navajowhite",255, 222, 173},
 589	{"navy", 0, 0, 128},
 590	{"oldlace",253, 245, 230},
 591	{"olive",128, 128, 0},
 592	{"olivedrab",107, 142, 35},
 593	{"orange",255, 165, 0},
 594	{"orangered",255, 69, 0},
 595	{"orchid",218, 112, 214},
 596	{"palegoldenrod",238, 232, 170},
 597	{"palegreen",152, 251, 152},
 598	{"paleturquoise",175, 238, 238},
 599	{"palevioletred",219, 112, 147},
 600	{"papayawhip",255, 239, 213},
 601	{"peachpuff",255, 218, 185},
 602	{"peru",205, 133, 63},
 603	{"pink",255, 192, 203},
 604	{"plum",221, 160, 221},
 605	{"powderblue",176, 224, 230},
 606	{"purple",128, 0, 128},
 607	{"red",255, 0, 0},
 608	{"rosybrown",188, 143, 143},
 609	{"royalblue", 65, 105, 225},
 610	{"saddlebrown",139, 69, 19},
 611	{"salmon",250, 128, 114},
 612	{"sandybrown",244, 164, 96},
 613	{"seagreen", 46, 139, 87},
 614	{"seashell",255, 245, 238},
 615	{"sienna",160, 82, 45},
 616	{"silver",192, 192, 192},
 617	{"skyblue",135, 206, 235},
 618	{"slateblue",106, 90, 205},
 619	{"slategray",112, 128, 144},
 620	{"slategrey",112, 128, 144},
 621	{"snow",255, 250, 250},
 622	{"springgreen", 0, 255, 127},
 623	{"steelblue", 70, 130, 180},
 624	{"tan",210, 180, 140},
 625	{"teal", 0, 128, 128},
 626	{"lawngreen",124, 252, 0},
 627	{"lemonchiffon",255, 250, 205},
 628	{"lightblue",173, 216, 230},
 629	{"lightcoral",240, 128, 128},
 630	{"lightcyan",224, 255, 255},
 631	{"lightgoldenrodyellow",250, 250, 210},
 632	{"lightgray",211, 211, 211},
 633	{"lightgreen",144, 238, 144},
 634	{"lightgrey",211, 211, 211},
 635	{"thistle",216, 191, 216},
 636	{"tomato",255, 99, 71},
 637	{"turquoise", 64, 224, 208},
 638	{"violet",238, 130, 238},
 639	{"wheat",245, 222, 179},
 640	{"white",255, 255, 255},
 641	{"whitesmoke",245, 245, 245},
 642	{"yellow",255, 255, 0},
 643	{"yellowgreen",154, 205, 50}
 644
 645};
 646
 647
 648/* Basic SVG datatype parsing functions */
 649static const struct sys_col { const char *name; u8 type; } system_colors[] =
 650{
 651	{"ActiveBorder", SVG_COLOR_ACTIVE_BORDER},
 652	{"ActiveCaption", SVG_COLOR_ACTIVE_CAPTION},
 653	{"AppWorkspace", SVG_COLOR_APP_WORKSPACE},
 654	{"Background", SVG_COLOR_BACKGROUND},
 655	{"ButtonFace", SVG_COLOR_BUTTON_FACE},
 656	{"ButtonHighlight", SVG_COLOR_BUTTON_HIGHLIGHT},
 657	{"ButtonShadow", SVG_COLOR_BUTTON_SHADOW},
 658	{"ButtonText", SVG_COLOR_BUTTON_TEXT},
 659	{"CaptionText", SVG_COLOR_CAPTION_TEXT},
 660	{"GrayText", SVG_COLOR_GRAY_TEXT},
 661	{"Highlight", SVG_COLOR_HIGHLIGHT},
 662	{"HighlightText", SVG_COLOR_HIGHLIGHT_TEXT},
 663	{"InactiveBorder", SVG_COLOR_INACTIVE_BORDER},
 664	{"InactiveCaption", SVG_COLOR_INACTIVE_CAPTION},
 665	{"InactiveCaptionText", SVG_COLOR_INACTIVE_CAPTION_TEXT},
 666	{"InfoBackground", SVG_COLOR_INFO_BACKGROUND},
 667	{"InfoText", SVG_COLOR_INFO_TEXT},
 668	{"Menu", SVG_COLOR_MENU},
 669	{"MenuText", SVG_COLOR_MENU_TEXT},
 670	{"Scrollbar", SVG_COLOR_SCROLLBAR},
 671	{"ThreeDDarkShadow", SVG_COLOR_3D_DARK_SHADOW},
 672	{"ThreeDFace", SVG_COLOR_3D_FACE},
 673	{"ThreeDHighlight", SVG_COLOR_3D_HIGHLIGHT},
 674	{"ThreeDLightShadow", SVG_COLOR_3D_LIGHT_SHADOW},
 675	{"ThreeDShadow", SVG_COLOR_3D_SHADOW},
 676	{"Window", SVG_COLOR_WINDOW},
 677	{"WindowFrame", SVG_COLOR_WINDOW_FRAME},
 678	{"WindowText", SVG_COLOR_WINDOW_TEXT},
 679};
 680
 681/* parses an color from a named color HTML or CSS 2 */
 682static void svg_parse_named_color(SVG_Color *col, char *attribute_content)
 683{
 684	u32 i, count;
 685	count = sizeof(predefined_colors) / sizeof(struct predef_col);
 686	for (i=0; i<count; i++) {
 687		if (!strcmp(attribute_content, predefined_colors[i].name)) {
 688			col->red = INT2FIX(predefined_colors[i].r) / 255;
 689			col->green = INT2FIX(predefined_colors[i].g) / 255;
 690			col->blue = INT2FIX(predefined_colors[i].b) / 255;
 691			col->type = SVG_COLOR_RGBCOLOR;
 692			return;
 693		}
 694	}
 695	count = sizeof(system_colors) / sizeof(struct sys_col);
 696	for (i=0; i<count; i++) {
 697		if (!strcmp(attribute_content, system_colors[i].name)) {
 698			col->type = system_colors[i].type;
 699			return;
 700		}
 701	}
 702}
 703
 704const char *gf_svg_get_system_paint_server_name(u32 paint_type)
 705{
 706	u32 i, count;
 707	count = sizeof(system_colors) / sizeof(struct sys_col);
 708	for (i=0; i<count; i++) {
 709		if (paint_type == system_colors[i].type) return system_colors[i].name;
 710	}
 711	return "undefined";
 712}
 713
 714u32 gf_svg_get_system_paint_server_type(const char *name)
 715{
 716	u32 i, count;
 717	count = sizeof(system_colors) / sizeof(struct sys_col);
 718	for (i=0; i<count; i++) {
 719		if (!strcmp(name, system_colors[i].name)) return system_colors[i].type;
 720	}
 721	return 0;
 722}
 723
 724/* Reads an SVG Color
 725   either #RRGGBB, #RGB, rgb(r,g,b) in [0,255] , colorname, or 'r g b' in [0,1]
 726   ignores any space, comma, semi-column before and any space after
 727   TODO:
 728	transform the char into char and duplicate the input, instead of modifying it
 729		be more robust to errors in color description ex rgb(0 0 0)
 730*/
 731static void svg_parse_color(SVG_Color *col, char *attribute_content)
 732{
 733	char *str = attribute_content;
 734	while (str[strlen(attribute_content)-1] == ' ') str[strlen(attribute_content)-1] = 0;
 735	while (*str != 0 && (*str == ' ' || *str == ',' || *str == ';')) str++;
 736
 737	if (!strcmp(str, "currentColor")) {
 738		col->type = SVG_COLOR_CURRENTCOLOR;
 739		return;
 740	} else if (!strcmp(str, "inherit")) {
 741		col->type = SVG_COLOR_INHERIT;
 742		return;
 743	} else if (str[0]=='#') {
 744		u32 val;
 745		sscanf(str+1, "%x", &val);
 746		if (strlen(str) == 7) {
 747			col->red = INT2FIX((val>>16) & 0xFF) / 255;
 748			col->green = INT2FIX((val>>8) & 0xFF) / 255;
 749			col->blue = INT2FIX(val & 0xFF) / 255;
 750		} else {
 751			col->red = INT2FIX((val>>8) & 0xF) / 15;
 752			col->green = INT2FIX((val>>4) & 0xF) / 15;
 753			col->blue = INT2FIX(val & 0xF) / 15;
 754		}
 755		col->type = SVG_COLOR_RGBCOLOR;
 756	} else if (strstr(str, "rgb(") || strstr(str, "RGB(")) {
 757		Float _val;
 758		u8 is_percentage= 0;
 759		if (strstr(str, "%")) is_percentage = 1;
 760		str = strstr(str, "(");
 761		str++;
 762		sscanf(str, "%f", &_val); col->red = FLT2FIX(_val);
 763		str = strstr(str, ",");
 764		if (!str) {
 765			/* space separated colors/percentages are not allowed neither in SVG 1.1 nor in SVG T1.2 */
 766			col->red = col->green = col->blue = 0;
 767			return;
 768		}
 769		str++;
 770		sscanf(str, "%f", &_val); col->green = FLT2FIX(_val);
 771		str = strstr(str, ",");
 772		if (!str) {
 773			/* space separated colors/percentages are not allowed neither in SVG 1.1 nor in SVG T1.2 */
 774			col->red = col->green = col->blue = 0;
 775			return;
 776		}
 777		str++;
 778		sscanf(str, "%f", &_val); col->blue = FLT2FIX(_val);
 779		if (is_percentage) {
 780			col->red /= 100;
 781			col->green /= 100;
 782			col->blue /= 100;
 783		} else {
 784			col->red /= 255;
 785			col->green /= 255;
 786			col->blue /= 255;
 787		}
 788		col->type = SVG_COLOR_RGBCOLOR;
 789	} else if ((str[0] >= 'a' && str[0] <= 'z')
 790		|| (str[0] >= 'A' && str[0] <= 'Z')) {
 791		svg_parse_named_color(col, str);
 792	} else {
 793		Float _r, _g, _b;
 794		sscanf(str, "%f %f %f", &_r, &_g, &_b);
 795		col->red = FLT2FIX(_r);
 796		col->green = FLT2FIX(_g);
 797		col->blue = FLT2FIX(_b);
 798		col->type = SVG_COLOR_RGBCOLOR;
 799	}
 800}
 801
 802/*
 803	Reads a number (i.e. without unit) according to the CSS syntax (same as SVG paths and transforms)
 804		trims any space, comma, semi-column before or after (TODO: fix this)
 805		reads an optional + or -
 806		then reads a digit between 0 and 9
 807		optionally followed by an '.' and digits between 0 and 9
 808		optionally followed by e or E and digits between 0 and 9
 809	Returns the number of chars read in d
 810*/
 811static u32 svg_parse_number(char *d, Fixed *f, Bool is_angle)
 812{
 813    u32 nb_digit_before = 0;
 814	u32 nb_digit_after = 0;
 815    Bool has_fractional = 0;
 816	Bool is_negative = 0;
 817	Float _val = 0;
 818	u32 i = 0;
 819
 820    /* warning the comma and semicolumn should not be there when parsing a number in a path */
 821	while ((d[i] != 0) && strchr(" ,;\r\n\t", d[i])) i++;
 822
 823    if (!d[i]) {
 824        GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Parsing] Parsing number with empty string or only spaces: %s\n", d));
 825        return 0;
 826    }
 827    if (d[i] == '+') {
 828        i++;
 829    } else if (d[i] == '-') {
 830		is_negative = 1;
 831		i++;
 832	}
 833    /* Warning: this is not normal, should be detected somehow by checking the BNF */
 834	/* if ((d[i]=='N') && (d[i+1]=='a') && (d[i+2]=='N')) {
 835		i+= 3;
 836		_val = 0;
 837		goto end;
 838	}*/
 839    /* read the digit-sequence token of the BNF */
 840	while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) {
 841		_val = _val*10 + (d[i]-'0');
 842        nb_digit_before++;
 843		i++;
 844	}
 845	if (d[i] == '.') {
 846        has_fractional = 1;
 847		i++;
 848		while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) {
 849			_val = _val*10 + (d[i]-'0');
 850			nb_digit_after++;
 851			i++;
 852		}
 853        if (nb_digit_after) {
 854            _val /= (Float)pow(10,nb_digit_after);
 855        } else if (nb_digit_before == 0) {
 856            GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing number (expecting digits before or after a '.': %s\n", d));
 857            return 0;
 858        } else {
 859            /* dangling '.' without digits after. This is allowed by the BNF */
 860        }
 861	}
 862    if ((nb_digit_before == 0) && (has_fractional == 0)) {
 863        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing number (expecting digits):%s\n", d));
 864        return 0;
 865    }
 866    /* reading the exponent */
 867	if (d[i] == 'e' || d[i] == 'E') {
 868		Bool neg_exp = 0;
 869		u32 nb_exp_digits = 0;
 870        s32 exp = 0;
 871		i++;
 872		if (d[i] == '+') i++;
 873		else if (d[i] == '-') {
 874			i++;
 875			neg_exp=1;
 876		}
 877		while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) {
 878			exp = exp*10 + (d[i]-'0');
 879            nb_exp_digits++;
 880			i++;
 881		}
 882        if (nb_exp_digits) {
 883            _val *= (Float)pow(10, neg_exp ? -exp : exp);
 884        } else {
 885            GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing exponent, 'e' or 'E' should be followed by digits: %s\n", d));
 886            return 0;
 887        }
 888	}
 889    /* We can now produce the final number */
 890	if (is_negative) _val *= -1;
 891	if (is_angle) {
 892		_val/=180;
 893		(*f) = gf_mulfix(FLT2FIX(_val), GF_PI);
 894	} else {
 895		(*f) = FLT2FIX(_val);
 896	}
 897
 898    /* warning the comma and semicolumn should not be there when parsing a path number */
 899	while (d[i] != 0 && (d[i] == ' ' || d[i] == ',' || d[i] == ';')) i++;
 900	return i;
 901}
 902
 903/*
 904   Parse an Offset Value, i.e +/- Clock Value
 905*/
 906static GF_Err svg_parse_clock_value(char *d, Double *clock_value)
 907{
 908	char *tmp;
 909	s32 sign = 1;
 910
 911	if (!d) return GF_BAD_PARAM;
 912
 913	if (!d[0]) return GF_BAD_PARAM;
 914
 915	if (d[0] == '+') d++;
 916	else if (d[0] == '-') { sign = -1; d++; }
 917
 918	if (!d[0]) return GF_BAD_PARAM;
 919
 920	/* According to SVG, the following are invalid syntaxes (see animate-elem-225-t.svg)
 921		'+-2s'
 922		'1++s' even though sscanf returns the right values
 923	*/
 924	if (strchr(d, '+') || strchr(d, '-')) return GF_BAD_PARAM;
 925
 926	/* No embedded white space is allowed in clock values,
 927	   although leading and trailing white space characters will be ignored.*/
 928	while (*d == ' ') d++;
 929
 930	if ((tmp = strchr(d, ':'))) {
 931		/* Full or Partial Clock value */
 932		tmp++;
 933		if ((tmp = strchr(tmp, ':'))) {
 934			/* Full Clock value : hh:mm:ss(.frac) */
 935			u32 hours;
 936			u32 minutes;
 937			Float seconds;
 938			if (sscanf(d, "%u:%u:%f", &hours, &minutes, &seconds) < 3) return GF_BAD_PARAM;
 939			*clock_value = hours*3600 + minutes*60 + seconds;
 940		} else {
 941			/* Partial Clock value : mm:ss(.frac) */
 942			s32 minutes;
 943			Float seconds;
 944			if (sscanf(d, "%d:%f", &minutes, &seconds) < 2) return GF_BAD_PARAM;
 945			*clock_value = minutes*60 + seconds;
 946		}
 947	} else if ((tmp = strstr(d, "h"))) {
 948		Float f;
 949		if (sscanf(d, "%fh", &f) == 0) return GF_BAD_PARAM;
 950		*clock_value = 3600*f;
 951	} else if (strstr(d, "min")) {
 952		Float f;
 953		if (sscanf(d, "%fmin", &f) == 0) return GF_BAD_PARAM;
 954		*clock_value = 60*f;
 955	} else if ((tmp = strstr(d, "ms"))) {
 956		Float f;
 957		if (sscanf(d, "%fms", &f) == 0) return GF_BAD_PARAM;
 958		*clock_value = f/1000;
 959	} else if (strchr(d, 's')) {
 960		Float f;
 961		if (sscanf(d, "%fs", &f) == 0) return GF_BAD_PARAM;
 962		*clock_value = f;
 963	} else {
 964		Float f;
 965		if (sscanf(d, "%f", &f) == 0) return GF_BAD_PARAM;
 966		*clock_value = f;
 967	}
 968	*clock_value *= sign;
 969	return GF_OK;
 970}
 971/* Parses one SVG time value:
 972	  indefinite,
 973	  element_id.event_name
 974	  wallclock,
 975	  accessKey,
 976	  events,
 977	  clock value.
 978 */
 979static GF_Err smil_parse_time(GF_Node *elt, SMIL_Time *v, char *d)
 980{
 981	GF_Err e = GF_OK;
 982	char *tmp;
 983
 984	/* Offset Values */
 985	if ((d[0] >= '0' && d[0] <= '9') || d[0] == '+' || d[0] == '-'){
 986		v->type = GF_SMIL_TIME_CLOCK;
 987		return svg_parse_clock_value(d, &(v->clock));
 988	}
 989
 990	/* Indefinite Values */
 991	else if (!strcmp(d, "indefinite")) {
 992		v->type = GF_SMIL_TIME_INDEFINITE;
 993		return GF_OK;
 994	}
 995
 996	/* Wallclock Values */
 997	else if ((tmp = strstr(d, "wallclock("))) {
 998		u32 year, month, day;
 999		u32 hours, minutes;
1000		u32 nhours, nminutes;
1001		Float seconds;
1002		char *tmp1, *tmp2;
1003
1004		v->type = GF_SMIL_TIME_WALLCLOCK;
1005		tmp += 10;
1006		if ((tmp1 = strchr(tmp, 'T')) ) {
1007			/* From tmp to wallStartTime, we parse a date */
1008			sscanf(tmp, "%u-%u-%dT", &year, &month, &day);
1009			tmp1++;
1010			tmp = tmp1;
1011		}
1012		if ((tmp1 = strchr(tmp, ':')) ) {
1013			if ((tmp2 = strchr(tmp1, ':')) ) {
1014				/* HHMMSS */
1015				sscanf(tmp, "%u:%u:%f", &hours, &minutes, &seconds);
1016			} else {
1017				/* HHMM */
1018				sscanf(tmp, "%u:%u", &hours, &minutes);
1019			}
1020		}
1021		if (strchr(tmp, 'Z')) {
1022			return GF_OK;
1023		} else {
1024			if ( (tmp1 = strchr(tmp, '+')) ) {
1025				sscanf(tmp1, "%u:%u", &nhours, &nminutes);
1026			} else if ( (tmp1 = strchr(tmp, '-')) ) {
1027				sscanf(tmp1, "%u:%u", &nhours, &nminutes);
1028			}
1029		}
1030		return GF_OK;
1031	}
1032
1033	/* AccessKey Values */
1034	else if ((tmp = strstr(d, "accessKey("))) {
1035		char *sep;
1036		v->type = GF_SMIL_TIME_EVENT;
1037		v->event.type = GF_EVENT_KEYDOWN;
1038		v->element = elt->sgprivate->scenegraph->RootNode;
1039		tmp+=10;
1040		sep = strchr(d, ')');
1041		sep[0] = 0;
1042		v->event.parameter = gf_dom_get_key_type(tmp);
1043		sep++;
1044		if ((tmp = strchr(sep, '+')) || (tmp = strchr(sep, '-'))) {
1045			char c = *tmp;
1046			tmp++;
1047			e = svg_parse_clock_value(tmp, &(v->clock));
1048			if (c == '-') v->clock *= -1;
1049		}
1050		return e;
1051	}
1052
1053	else {
1054		Bool had_param = 0;
1055		char *tmp2;
1056		v->type = GF_SMIL_TIME_EVENT;
1057		if ((tmp = strchr(d, '.'))) {
1058			tmp[0] = 0;
1059			if (strlen(d) == 0) {
1060				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] expecting an id before '.' in SMIL Time .%s\n", tmp+1));
1061				return GF_BAD_PARAM;
1062			}
1063			v->element_id = gf_strdup(d);
1064			tmp[0] = '.';
1065			tmp++;
1066		} else {
1067			tmp = d;
1068		}
1069		if ((tmp2 = strchr(tmp, '('))) {
1070			tmp2[0] = 0;
1071			v->event.type = gf_dom_event_type_by_name(tmp);
1072			tmp2[0] = '(';
1073			tmp2++;
1074			had_param = 1;
1075			v->event.parameter = atoi(tmp2);
1076			tmp = strchr(tmp2, ')');
1077			if (!tmp) {
1078				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] expecting ')' in SMIL Time %s\n", d));
1079				return GF_BAD_PARAM;
1080			}
1081			tmp++;
1082		}
1083		if ((tmp2 = strchr(tmp, '+')) || (tmp2 = strchr(tmp, '-'))) {
1084			char c = *tmp2;
1085			char *tmp3 = tmp2;
1086			tmp2[0] = 0;
1087			tmp3--;
1088			while (*tmp3==' ') { *tmp3=0; tmp3--; }
1089			if (v->event.type == 0) v->event.type = gf_dom_event_type_by_name(tmp);
1090			if (!had_param && (v->event.type == GF_EVENT_REPEAT || v->event.type == GF_EVENT_REPEAT_EVENT))
1091				v->event.parameter = 1;
1092			tmp2[0] = c;
1093			tmp2++;
1094			e = svg_parse_clock_value(tmp2, &(v->clock));
1095			if (c == '-') v->clock *= -1;
1096			return e;
1097		} else {
1098			if (v->event.type == 0) v->event.type = gf_dom_event_type_by_name(tmp);
1099			if (!had_param && (v->event.type == GF_EVENT_REPEAT || v->event.type == GF_EVENT_REPEAT_EVENT))
1100				v->event.parameter = 1;
1101		}
1102	}
1103	return GF_OK;
1104}
1105
1106/* Parses a list of SVG transformations and collapses them in the given matrix */
1107Bool gf_svg_parse_transformlist(GF_Matrix2D *mat, char *attribute_content)
1108{
1109	GF_Matrix2D tmp;
1110
1111	char *str;
1112    u32 read_chars;
1113	u32 i;
1114
1115	gf_mx2d_init(*mat);
1116
1117	str = attribute_content;
1118	i = 0;
1119	while (str[i] != 0) {
1120		while (str[i] == ' ') i++;
1121		if (str[i] == ',') i++;
1122		while (str[i] == ' ') i++;
1123		if (strstr(str+i, "scale")==str+i) {
1124			i += 5;
1125			while(str[i] == ' ') i++;
1126			if (str[i] == '(') {
1127				Fixed sx, sy;
1128				i++;
1129				read_chars = svg_parse_number(&(str[i]), &sx, 0);
1130                if (!read_chars) {
1131                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading sx component in scale: %s\n", attribute_content));
1132                    return 0;
1133                }
1134                i += read_chars;
1135
1136				if (str[i] == ')') {
1137					sy = sx;
1138				} else {
1139					read_chars = svg_parse_number(&(str[i]), &sy, 0);
1140                    if (!read_chars) {
1141                        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading sy component in scale: %s\n", attribute_content));
1142                        return 0;
1143                    }
1144                    i += read_chars;
1145				}
1146				gf_mx2d_init(tmp);
1147				gf_mx2d_add_scale(&tmp, sx, sy);
1148				gf_mx2d_add_matrix(&tmp, mat);
1149				gf_mx2d_copy(*mat, tmp);
1150
1151				while(str[i] == ' ') i++;
1152				if (str[i] == ')') i++;
1153				else {
1154                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1155                    return 0;
1156				}
1157			} else {
1158				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
1159                return 0;
1160			}
1161		} else if (strstr(str+i, "translate")==str+i) {
1162			i += 9;
1163			while(str[i] == ' ') i++;
1164			if (str[i] == '(') {
1165				Fixed tx, ty;
1166				i++;
1167				read_chars = svg_parse_number(&(str[i]), &tx, 0);
1168                if (!read_chars) {
1169                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading tx component in translate: %s\n", attribute_content));
1170                    return 0;
1171                }
1172                i += read_chars;
1173				if (str[i] == ')') {
1174					ty = 0;
1175				} else {
1176					read_chars = svg_parse_number(&(str[i]), &ty, 0);
1177                    if (!read_chars) {
1178                        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading ty component in translate: %s\n", attribute_content));
1179                        return 0;
1180                    }
1181                    i += read_chars;
1182				}
1183				gf_mx2d_init(tmp);
1184				gf_mx2d_add_translation(&tmp, tx, ty);
1185				gf_mx2d_add_matrix(&tmp, mat);
1186				gf_mx2d_copy(*mat, tmp);
1187				while(str[i] == ' ') i++;
1188				if (str[i] == ')') i++;
1189				else {
1190                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1191                    return 0;
1192				}
1193			} else {
1194				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
1195                return 0;
1196			}
1197		} else if (strstr(str+i, "rotate")==str+i) {
1198			i += 6;
1199			while(str[i] == ' ') i++;
1200			if (str[i] == '(') {
1201				Fixed angle, cx, cy;
1202				i++;
1203				read_chars = svg_parse_number(&(str[i]), &angle, 1);
1204                if (!read_chars) {
1205                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading angle component in rotate: %s\n", attribute_content));
1206                    return 0;
1207                }
1208                i += read_chars;
1209				if (str[i] == ')') {
1210					cx = cy = 0;
1211				} else {
1212					read_chars = svg_parse_number(&(str[i]), &cx, 0);
1213                    if (!read_chars) {
1214                        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading cx component in rotate: %s\n", attribute_content));
1215                        return 0;
1216                    }
1217                    i += read_chars;
1218					read_chars = svg_parse_number(&(str[i]), &cy, 0);
1219                    if (!read_chars) {
1220                        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading cy component in rotate: %s\n", attribute_content));
1221                        return 0;
1222                    }
1223                    i += read_chars;
1224				}
1225				gf_mx2d_init(tmp);
1226				gf_mx2d_add_rotation(&tmp, cx, cy, angle);
1227				gf_mx2d_add_matrix(&tmp, mat);
1228				gf_mx2d_copy(*mat, tmp);
1229				while(str[i] == ' ') i++;
1230				if (str[i] == ')') i++;
1231				else {
1232                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1233                    return 0;
1234				}
1235			} else {
1236				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
1237                return 0;
1238			}
1239		} else if (strstr(str+i, "skewX")==str+i) {
1240			i += 5;
1241			while(str[i] == ' ') i++;
1242			if (str[i] == '(') {
1243				Fixed angle;
1244				i++;
1245				read_chars = svg_parse_number(&(str[i]), &angle, 1);
1246                if (!read_chars) {
1247                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading angle in skewX: %s\n", attribute_content));
1248                    return 0;
1249                }
1250                i += read_chars;
1251				gf_mx2d_init(tmp);
1252				gf_mx2d_add_skew_x(&tmp, angle);
1253				gf_mx2d_add_matrix(&tmp, mat);
1254				gf_mx2d_copy(*mat, tmp);
1255				while(str[i] == ' ') i++;
1256				if (str[i] == ')') i++;
1257				else {
1258                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1259                    return 0;
1260				}
1261			} else {
1262				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
1263                return 0;
1264			}
1265		} else if (strstr(str+i, "skewY")==str+i) {
1266			i += 5;
1267			while(str[i] == ' ') i++;
1268			if (str[i] == '(') {
1269				Fixed angle;
1270				i++;
1271				read_chars = svg_parse_number(&(str[i]), &angle, 1);
1272                if (!read_chars) {
1273                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading angle component in skewY: %s\n", attribute_content));
1274                    return 0;
1275                }
1276                i += read_chars;
1277				gf_mx2d_init(tmp);
1278				gf_mx2d_add_skew_y(&tmp, angle);
1279				gf_mx2d_add_matrix(&tmp, mat);
1280				gf_mx2d_copy(*mat, tmp);
1281				while(str[i] == ' ') i++;
1282				if (str[i] == ')') i++;
1283				else {
1284                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1285                    return 0;
1286				}
1287			} else {
1288				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
1289                return 0;
1290			}
1291		} else if (strstr(str+i, "matrix")==str+i) {
1292			i+=6;
1293			while(str[i] == ' ') i++;
1294			if (str[i] == '(') {
1295				i++;
1296				read_chars = svg_parse_number(&(str[i]), &(tmp.m[0]), 0);
1297                if (!read_chars) {
1298                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient a in matrix: %s\n", attribute_content));
1299                    return 0;
1300                }
1301                i += read_chars;
1302				read_chars = svg_parse_number(&(str[i]), &(tmp.m[3]), 0);
1303                if (!read_chars) {
1304                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient b in matrix: %s\n", attribute_content));
1305                    return 0;
1306                }
1307                i += read_chars;
1308				read_chars = svg_parse_number(&(str[i]), &(tmp.m[1]), 0);
1309                if (!read_chars) {
1310                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient c in matrix: %s\n", attribute_content));
1311                    return 0;
1312                }
1313                i += read_chars;
1314				read_chars = svg_parse_number(&(str[i]), &(tmp.m[4]), 0);
1315                if (!read_chars) {
1316                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient d in matrix: %s\n", attribute_content));
1317                    return 0;
1318                }
1319                i += read_chars;
1320				read_chars = svg_parse_number(&(str[i]), &(tmp.m[2]), 0);
1321                if (!read_chars) {
1322                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient e in matrix: %s\n", attribute_content));
1323                    return 0;
1324                }
1325                i += read_chars;
1326				read_chars = svg_parse_number(&(str[i]), &(tmp.m[5]), 0);
1327                if (!read_chars) {
1328                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient f in matrix: %s\n", attribute_content));
1329                    return 0;
1330                }
1331                i += read_chars;
1332				gf_mx2d_add_matrix(&tmp, mat);
1333				gf_mx2d_copy(*mat, tmp);
1334				while(str[i] == ' ') i++;
1335				if (str[i] == ')') i++;
1336				else {
1337                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1338                    return 0;
1339				}
1340			} else {
1341				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
1342                return 0;
1343			}
1344		} else {
1345			GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Unrecognized transofrm type in attribute %s\n", attribute_content));
1346            return 0;
1347		}
1348		/*for svgView parsing*/
1349		if (str[i] == ')') i++;
1350	}
1351    return 1;
1352}
1353
1354/* Parses an SVG transform attribute and collapses all in the given matrix */
1355static Bool svg_parse_transform(SVG_Transform *t, char *attribute_content)
1356{
1357	char *str;
1358	u32 i;
1359    u32 read_chars;
1360	str = attribute_content;
1361	i = 0;
1362
1363	if ((str = strstr(attribute_content, "ref"))) {
1364		t->is_ref = 1;
1365		gf_mx2d_init(t->mat);
1366		str+=2;
1367		while (str[i] == ' ') i++;
1368		if (str[i] == '(') {
1369			i++;
1370			while (str[i] == ' ') i++;
1371			if (str[i] == 's' && str[i+1] == 'v' && str[i+2] == 'g') {
1372				i+=3;
1373				while (str[i] == ' ') i++;
1374                if (str[i] == ',') {
1375                    i++;
1376                } else if (str[i] == ')') {
1377					i++;
1378					return GF_OK;
1379				}
1380				read_chars = svg_parse_number(&(str[i]), &(t->mat.m[2]), 0);
1381                if (!read_chars) {
1382                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient tx in ref transform: %s\n", attribute_content));
1383                    return GF_BAD_PARAM;
1384                }
1385                i += read_chars;
1386				read_chars = svg_parse_number(&(str[i]), &(t->mat.m[5]), 0);
1387                if (!read_chars) {
1388                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient ty in ref transform: %s\n", attribute_content));
1389                    return GF_BAD_PARAM;
1390                }
1391                i += read_chars;
1392            } else {
1393				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Unsupported syntax for ref transform attribute"));
1394            }
1395			while (str[i] == ' ') i++;
1396			if (str[i] == ')') i++;
1397			else {
1398                GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1399			}
1400			return GF_OK;
1401		} else {
1402            GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in ref transform attribute: %s\n", attribute_content));
1403			return GF_BAD_PARAM;
1404		}
1405	} else {
1406		read_chars = gf_svg_parse_transformlist(&t->mat, attribute_content);
1407        if (!read_chars) {
1408            GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error parsing transform list: %s\n", attribute_content));
1409            return GF_BAD_PARAM;
1410        }
1411	}
1412	return GF_OK;
1413}
1414
1415#undef REMOVE_ALLOC
1416
1417#if USE_GF_PATH
1418
1419//#define PARSE_PATH_ONLY
1420
1421static void svg_parse_path(SVG_PathData *path, char *attribute_content)
1422{
1423	char *d = attribute_content;
1424
1425    /* used to detect end of BNF production:
1426    "The processing of the BNF must consume as much of a given BNF production as possible,
1427    stopping at the point when a character is encountered which no longer satisfies the production." */
1428    u32 read_chars = 0;
1429
1430	/* Point used to start a new subpath when the previous subpath is closed */
1431	SVG_Point prev_m_pt;
1432	/* Point used to convert relative 'lower-case commands' into absolute */
1433	SVG_Point rel_ref_pt;
1434	/* Points used to convert S, T commands into C, Q */
1435	SVG_Point orig, ct_orig, ct_end, end;
1436	/* Used by elliptical arcs */
1437	Fixed x_axis_rotation, large_arc_flag, sweep_flag;
1438
1439	char c, prev_c;
1440	u32 i;
1441
1442	if (*d == 0) return;
1443
1444	i = 0;
1445	prev_c = 'M';
1446	orig.x = orig.y = ct_orig.x = ct_orig.y = prev_m_pt.x = prev_m_pt.y = rel_ref_pt.x = rel_ref_pt.y = end.x = end.y = 0;
1447	while(1) {
1448		while ( (d[i]==' ') || (d[i] =='\t') || (d[i] =='\r') || (d[i] =='\n') ) i++;
1449		c = d[i];
1450		if (! c) break;
1451next_command:
1452		switch (c) {
1453		case 'm':
1454		case 'M':
1455			i++;
1456			read_chars = svg_parse_number(&(d[i]), &(orig.x), 0);
1457            if (!read_chars) return;
1458            i += read_chars;
1459			read_chars = svg_parse_number(&(d[i]), &(orig.y), 0);
1460            if (!read_chars) return;
1461            i += read_chars;
1462			if (c == 'm') {
1463				orig.x += rel_ref_pt.x;
1464				orig.y += rel_ref_pt.y;
1465			}
1466#ifndef PARSE_PATH_ONLY
1467			gf_path_add_move_to(path, orig.x, orig.y);
1468#endif
1469			rel_ref_pt = orig;
1470			prev_m_pt = orig;
1471			/*provision for nextCurveTo when no curve is specified:
1472				"If there is no previous command or if the previous command was not an C, c, S or s,
1473				assume the first control point is coincident with the current point.
1474			*/
1475			ct_orig = orig;
1476			prev_c = c;
1477			break;
1478		case 'L':
1479		case 'l':
1480			i++;
1481			read_chars = svg_parse_number(&(d[i]), &(orig.x), 0);
1482            if (!read_chars) return;
1483            i += read_chars;
1484			read_chars = svg_parse_number(&(d[i]), &(orig.y), 0);
1485            if (!read_chars) return;
1486            i += read_chars;
1487			if (c == 'l') {
1488				orig.x += rel_ref_pt.x;
1489				orig.y += rel_ref_pt.y;
1490			}
1491#ifndef PARSE_PATH_ONLY
1492			gf_path_add_line_to(path, orig.x, orig.y);
1493#endif
1494			rel_ref_pt = orig;
1495			orig = end;
1496			/*cf above*/
1497			ct_orig = orig;
1498			prev_c = c;
1499			break;
1500		case 'H':
1501		case 'h':
1502			i++;
1503			read_chars = svg_parse_number(&(d[i]), &(orig.x), 0);
1504            if (!read_chars) return;
1505            i += read_chars;
1506			if (c == 'h') {
1507				orig.x += rel_ref_pt.x;
1508			}
1509			orig.y = rel_ref_pt.y;
1510#ifndef PARSE_PATH_ONLY
1511			gf_path_add_line_to(path, orig.x, orig.y);
1512#endif
1513			rel_ref_pt.x = orig.x;
1514			orig = end;
1515			/*cf above*/
1516			ct_orig = orig;
1517			prev_c = c;
1518			break;
1519		case 'V':
1520		case 'v':
1521			i++;
1522			read_chars = svg_parse_number(&(d[i]), &(orig.y), 0);
1523            if (!read_chars) return;
1524            i += read_chars;
1525			if (c == 'v') {
1526				orig.y += rel_ref_pt.y;
1527			}
1528			orig.x = rel_ref_pt.x;
1529#ifndef PARSE_PATH_ONLY
1530			gf_path_add_line_to(path, orig.x, orig.y);
1531#endif
1532			rel_ref_pt.y = orig.y;
1533			orig = end;
1534			/*cf above*/
1535			ct_orig = orig;
1536			prev_c = c;
1537			break;
1538		case 'C':
1539		case 'c':
1540			i++;
1541			read_chars = svg_parse_number(&(d[i]), &(ct_orig.x), 0);
1542            if (!read_chars) return;
1543            i += read_chars;
1544			read_chars = svg_parse_number(&(d[i]), &(ct_orig.y), 0);
1545            if (!read_chars) return;
1546            i += read_chars;
1547			if (c == 'c') {
1548				ct_orig.x += rel_ref_pt.x;
1549				ct_orig.y += rel_ref_pt.y;
1550			}
1551			read_chars = svg_parse_number(&(d[i]), &(ct_end.x), 0);
1552            if (!read_chars) return;
1553            i += read_chars;
1554			read_chars = svg_parse_number(&(d[i]), &(ct_end.y), 0);
1555            if (!read_chars) return;
1556            i += read_chars;
1557			if (c == 'c') {
1558				ct_end.x += rel_ref_pt.x;
1559				ct_end.y += rel_ref_pt.y;
1560			}
1561			read_chars = svg_parse_number(&(d[i]), &(end.x), 0);
1562            if (!read_chars) return;
1563            i += read_chars;
1564			read_chars = svg_parse_number(&(d[i]), &(end.y), 0);
1565            if (!read_chars) return;
1566            i += read_chars;
1567			if (c == 'c') {
1568				end.x += rel_ref_pt.x;
1569				end.y += rel_ref_pt.y;
1570			}
1571#ifndef PARSE_PATH_ONLY
1572			gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
1573#endif
1574			rel_ref_pt = end;
1575			ct_orig = ct_end;
1576			orig = end;
1577			prev_c = c;
1578			break;
1579		case 'S':
1580		case 's':
1581			i++;
1582			ct_orig.x = 2*orig.x - ct_orig.x;
1583			ct_orig.y = 2*orig.y - ct_orig.y;
1584			read_chars = svg_parse_number(&(d[i]), &(ct_end.x), 0);
1585            if (!read_chars) return;
1586            i += read_chars;
1587			read_chars = svg_parse_number(&(d[i]), &(ct_end.y), 0);
1588            if (!read_chars) return;
1589            i += read_chars;
1590			if (c == 's') {
1591				ct_end.x += rel_ref_pt.x;
1592				ct_end.y += rel_ref_pt.y;
1593			}
1594			read_chars = svg_parse_number(&(d[i]), &(end.x), 0);
1595            if (!read_chars) return;
1596            i += read_chars;
1597			read_chars = svg_parse_number(&(d[i]), &(end.y), 0);
1598            if (!read_chars) return;
1599            i += read_chars;
1600			if (c == 's') {
1601				end.x += rel_ref_pt.x;
1602				end.y += rel_ref_pt.y;
1603			}
1604#ifndef PARSE_PATH_ONLY
1605			gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
1606#endif
1607			rel_ref_pt = end;
1608			ct_orig = ct_end;
1609			orig = end;
1610			prev_c = c;
1611			break;
1612		case 'Q':
1613		case 'q':
1614			i++;
1615			read_chars = svg_parse_number(&(d[i]), &(ct_orig.x), 0);
1616            if (!read_chars) return;
1617            i += read_chars;
1618			read_chars = svg_parse_number(&(d[i]), &(ct_orig.y), 0);
1619            if (!read_chars) return;
1620            i += read_chars;
1621			if (c == 'q') {
1622				ct_orig.x += rel_ref_pt.x;
1623				ct_orig.y += rel_ref_pt.y;
1624			}
1625			read_chars = svg_parse_number(&(d[i]), &(end.x), 0);
1626            if (!read_chars) return;
1627            i += read_chars;
1628			read_chars = svg_parse_number(&(d[i]), &(end.y), 0);
1629            if (!read_chars) return;
1630            i += read_chars;
1631			if (c == 'q') {
1632				end.x += rel_ref_pt.x;
1633				end.y += rel_ref_pt.y;
1634			}
1635#ifndef PARSE_PATH_ONLY
1636			gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y);
1637#endif
1638			rel_ref_pt = end;
1639			orig = end;
1640			prev_c = c;
1641			break;
1642		case 'T':
1643		case 't':
1644			i++;
1645			ct_orig.x = 2*orig.x - ct_orig.x;
1646			ct_orig.y = 2*orig.y - ct_orig.y;
1647			read_chars = svg_parse_number(&(d[i]), &(end.x), 0);
1648            if (!read_chars) return;
1649            i += read_chars;
1650			read_chars = svg_parse_number(&(d[i]), &(end.y), 0);
1651            if (!read_chars) return;
1652            i += read_chars;
1653			if (c == 't') {
1654				end.x += rel_ref_pt.x;
1655				end.y += rel_ref_pt.y;
1656			}
1657#ifndef PARSE_PATH_ONLY
1658			gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y);
1659#endif
1660			rel_ref_pt = end;
1661			orig = end;
1662			prev_c = c;
1663			break;
1664		case 'A':
1665		case 'a':
1666			i++;
1667
1668			read_chars = svg_parse_number(&(d[i]), &(orig.x), 0);
1669            if (!read_chars) return;
1670            i += read_chars;
1671			read_chars = svg_parse_number(&(d[i]), &(orig.y), 0);
1672            if (!read_chars) return;
1673            i += read_chars;
1674
1675			read_chars = svg_parse_number(&(d[i]), &(x_axis_rotation), 0);
1676            if (!read_chars) return;
1677            i += read_chars;
1678			read_chars = svg_parse_number(&(d[i]), &(large_arc_flag), 0);
1679            if (!read_chars) return;
1680            i += read_chars;
1681			read_chars = svg_parse_number(&(d[i]), &(sweep_flag), 0);
1682            if (!read_chars) return;
1683            i += read_chars;
1684
1685			read_chars = svg_parse_number(&(d[i]), &(end.x), 0);
1686            if (!read_chars) return;
1687            i += read_chars;
1688			read_chars = svg_parse_number(&(d[i]), &(end.y), 0);
1689            if (!read_chars) return;
1690            i += read_chars;
1691			if (c == 'a') {
1692				end.x += rel_ref_pt.x;
1693				end.y += rel_ref_pt.y;
1694			}
1695#ifndef PARSE_PATH_ONLY
1696			gf_path_add_svg_arc_to(path, end.x, end.y, orig.x, orig.y, x_axis_rotation , (large_arc_flag == FIX_ONE ? 1 : 0), (sweep_flag == FIX_ONE ? 1 : 0));
1697#endif
1698			rel_ref_pt = end;
1699			ct_orig = end;
1700			prev_c = c;
1701			break;
1702		case 'Z':
1703		case 'z':
1704			i++;
1705#ifndef PARSE_PATH_ONLY
1706			gf_path_close(path);
1707#endif
1708			prev_c = c;
1709			rel_ref_pt = prev_m_pt;
1710			break;
1711		default:
1712			i--;
1713			switch (prev_c) {
1714			case 'M':
1715				c = 'L';
1716				break;
1717			case 'm':
1718				c = 'l';
1719				break;
1720			default:
1721				c = prev_c;
1722			}
1723			goto next_command;
1724		}
1725	}
1726}
1727#else
1728/* TODO: Change the function to handle elliptical arcs, requires changing data structure */
1729static void svg_parse_path(SVG_PathData *d_attribute, char *attribute_content)
1730{
1731	GF_List *d_commands = d_attribute->commands;
1732	GF_List *d_points = d_attribute->points;
1733	char *d = attribute_content;
1734
1735	if (strlen(d)) {
1736		SVG_Point *pt, cur_pt, prev_m_pt;
1737		u8 *command;
1738		u32 i, k;
1739		char c, prev_c = 'M';
1740#ifdef REMOVE_ALLOC
1741		GF_SAFEALLOC(pt, SVG_Point)
1742#endif
1743		i = 0;
1744		cur_pt.x = cur_pt.y = 0;
1745		prev_m_pt.x = prev_m_pt.y = 0;
1746		while(1) {
1747			while ( (d[i]==' ') || (d[i] =='\t') ) i++;
1748			c = d[i];
1749			if (! c) break;
1750next_command:
1751			switch (c) {
1752			case 'm':
1753			case 'M':
1754				i++;
1755#ifndef REMOVE_ALLOC
1756				GF_SAFEALLOC(command, u8)
1757				gf_list_add(d_commands, command);
1758				*command = SVG_PATHCOMMAND_M;
1759
1760				GF_SAFEALLOC(pt, SVG_Point)
1761				gf_list_add(d_points, pt);
1762#endif
1763				i += svg_parse_number(&(d[i]), &(pt->x), 0);
1764				i += svg_parse_number(&(d[i]), &(pt->y), 0);
1765				if (c == 'm') {
1766					pt->x += cur_pt.x;
1767					pt->y += cur_pt.y;
1768				}
1769				cur_pt.x = pt->x;
1770				cur_pt.y = pt->y;
1771				prev_m_pt = cur_pt;
1772				prev_c = c;
1773				break;
1774			case 'L':
1775			case 'l':
1776				i++;
1777#ifndef REMOVE_ALLOC
1778				GF_SAFEALLOC(command, u8)
1779				gf_list_add(d_commands, command);
1780				*command = SVG_PATHCOMMAND_L;
1781
1782				GF_SAFEALLOC(pt, SVG_Point)
1783				gf_list_add(d_points, pt);
1784#endif
1785				i += svg_parse_number(&(d[i]), &(pt->x), 0);
1786				i += svg_parse_number(&(d[i]), &(pt->y), 0);
1787				if (c == 'l') {
1788					pt->x += cur_pt.x;
1789					pt->y += cur_pt.y;
1790				}
1791				cur_pt.x = pt->x;
1792				cur_pt.y = pt->y;
1793				prev_c = c;
1794				break;
1795			case 'H':
1796			case 'h':
1797				i++;
1798#ifndef REMOVE_ALLOC
1799				GF_SAFEALLOC(command, u8)
1800				gf_list_add(d_commands, command);
1801				*command = SVG_PATHCOMMAND_L;
1802
1803				GF_SAFEALLOC(pt, SVG_Point)
1804				gf_list_add(d_points, pt);
1805#endif
1806				i += svg_parse_number(&(d[i]), &(pt->x), 0);
1807				if (c == 'h') {
1808					pt->x += cur_pt.x;
1809				}
1810				pt->y = cur_pt.y;
1811				cur_pt.x = pt->x;
1812				prev_c = c;
1813				break;
1814			case 'V':
1815			case 'v':
1816				i++;
1817#ifndef REMOVE_ALLOC
1818				GF_SAFEALLOC(command, u8)
1819				gf_list_add(d_commands, command);
1820				*command = SVG_PATHCOMMAND_L;
1821
1822				GF_SAFEALLOC(pt, SVG_Point)
1823				gf_list_add(d_points, pt);
1824#endif
1825				i += svg_parse_number(&(d[i]), &(pt->y), 0);
1826				if (c == 'v') {
1827					pt->y += cur_pt.y;
1828				}
1829				pt->x = cur_pt.x;
1830				cur_pt.y = pt->y;
1831				prev_c = c;
1832				break;
1833			case 'C':
1834			case 'c':
1835				i++;
1836#ifndef REMOVE_ALLOC
1837				GF_SAFEALLOC(command, u8)
1838				gf_list_add(d_commands, command);
1839				*command = SVG_PATHCOMMAND_C;
1840#endif
1841
1842				for (k=0; k<3; k++) {
1843#ifndef REMOVE_ALLOC
1844					GF_SAFEALLOC(pt, SVG_Point)
1845					gf_list_add(d_points, pt);
1846#endif
1847					i += svg_parse_number(&(d[i]), &(pt->x), 0);
1848					i += svg_parse_number(&(d[i]), &(pt->y), 0);
1849					if (c == 'c') {
1850						pt->x += cur_pt.x;
1851						pt->y += cur_pt.y;
1852					}
1853				}
1854				cur_pt.x = pt->x;
1855				cur_pt.y = pt->y;
1856				prev_c = c;
1857				break;
1858			case 'S':
1859			case 's':
1860				i++;
1861#ifndef REMOVE_ALLOC
1862				GF_SAFEALLOC(command, u8)
1863				gf_list_add(d_commands, command);
1864				*command = SVG_PATHCOMMAND_S;
1865#endif
1866
1867				for (k=0; k<2; k++) {
1868#ifndef REMOVE_ALLOC
1869					GF_SAFEALLOC(pt, SVG_Point)
1870					gf_list_add(d_points, pt);
1871#endif
1872					i += svg_parse_number(&(d[i]), &(pt->x), 0);
1873					i += svg_parse_number(&(d[i]), &(pt->y), 0);
1874					if (c == 's') {
1875						pt->x += cur_pt.x;
1876						pt->y += cur_pt.y;
1877					}
1878				}
1879				cur_pt.x = pt->x;
1880				cur_pt.y = pt->y;
1881				prev_c = c;
1882				break;
1883			case 'Q':
1884			case 'q':
1885				i++;
1886#ifndef REMOVE_ALLOC
1887				GF_SAFEALLOC(command, u8)
1888				gf_list_add(d_commands, command);
1889				*command = SVG_PATHCOMMAND_Q;
1890#endif
1891
1892				for (k=0; k<2; k++) {
1893#ifndef REMOVE_ALLOC
1894					GF_SAFEALLOC(pt, SVG_Point)
1895					gf_list_add(d_points, pt);
1896#endif
1897					i += svg_parse_number(&(d[i]), &(pt->x), 0);
1898					i += svg_parse_number(&(d[i]), &(pt->y), 0);
1899					if (c == 'q') {
1900						pt->x += cur_pt.x;
1901						pt->y += cur_pt.y;
1902					}
1903				}
1904				cur_pt.x = pt->x;
1905				cur_pt.y = pt->y;
1906				prev_c = c;
1907				break;
1908			case 'T':
1909			case 't':
1910				i++;
1911#ifndef REMOVE_ALLOC
1912				GF_SAFEALLOC(command, u8)
1913				gf_list_add(d_commands, command);
1914				*command = SVG_PATHCOMMAND_T;
1915
1916				GF_SAFEALLOC(pt, SVG_Point)
1917				gf_list_add(d_points, pt);
1918#endif
1919				i += svg_parse_number(&(d[i]), &(pt->x), 0);
1920				i += svg_parse_number(&(d[i]), &(pt->y), 0);
1921				if (c == 't') {
1922					pt->x += cur_pt.x;
1923					pt->y += cur_pt.y;
1924				}
1925				cur_pt.x = pt->x;
1926				cur_pt.y = pt->y;
1927				prev_c = c;
1928				break;
1929			case 'A':
1930			case 'a':
1931				{
1932					Fixed tmp;
1933					i++;
1934#ifndef REMOVE_ALLOC
1935					GF_SAFEALLOC(command, u8)
1936					gf_list_add(d_commands, command);
1937					*command = SVG_PATHCOMMAND_A;
1938
1939					GF_SAFEALLOC(pt, SVG_Point)
1940					gf_list_add(d_points, pt);
1941#endif
1942					i += svg_parse_number(&(d[i]), &(pt->x), 0);
1943					i += svg_parse_number(&(d[i]), &(pt->y), 0);
1944
1945					i += svg_parse_number(&(d[i]), &(tmp), 0);
1946					i += svg_parse_number(&(d[i]), &(tmp), 0);
1947					i += svg_parse_number(&(d[i]), &(tmp), 0);
1948
1949#ifndef REMOVE_ALLOC
1950					GF_SAFEALLOC(pt, SVG_Point)
1951					gf_list_add(d_points, pt);
1952#endif
1953					i += svg_parse_number(&(d[i]), &(pt->x), 0);
1954					i += svg_parse_number(&(d[i]), &(pt->y), 0);
1955					if (c == 'a') {
1956						pt->x += cur_pt.x;
1957						pt->y += cur_pt.y;
1958					}
1959					cur_pt.x = pt->x;
1960					cur_pt.y = pt->y;
1961				}
1962				prev_c = c;
1963				break;
1964			case 'Z':
1965			case 'z':
1966				i++;
1967#ifndef REMOVE_ALLOC
1968				GF_SAFEALLOC(command, u8)
1969				gf_list_add(d_commands, command);
1970				*command = SVG_PATHCOMMAND_Z;
1971#endif
1972				prev_c = c;
1973				cur_pt = prev_m_pt;
1974				break;
1975			default:
1976				i--;
1977				switch (prev_c) {
1978				case 'M':
1979					c = 'L';
1980					break;
1981				case 'm':
1982					c = 'l';
1983					break;
1984				default:
1985					c = prev_c;
1986				}
1987				goto next_command;
1988			}
1989		}
1990	}
1991}
1992#endif
1993
1994static void svg_parse_iri(GF_Node *elt, XMLRI *iri, char *attribute_content)
1995{
1996	if (iri->string) {
1997		gf_free(iri->string);
1998		iri->string = NULL;
1999	}
2000	/* TODO: Handle xpointer(id()) syntax */
2001	if (attribute_content[0] == '#') {
2002		iri->string = gf_strdup(attribute_content);
2003		iri->target = gf_sg_find_node_by_name(elt->sgprivate->scenegraph, attribute_content + 1);
2004		if (!iri->target) {
2005			iri->type = XMLRI_STRING;
2006		} else {
2007			iri->type = XMLRI_ELEMENTID;
2008			gf_node_register_iri(elt->sgprivate->scenegraph, iri);
2009		}
2010	} else {
2011		iri->type = XMLRI_STRING;
2012		iri->string = gf_strdup(attribute_content);
2013	}
2014}
2015
2016static void svg_parse_idref(GF_Node *elt, XML_IDREF *iri, char *attribute_content)
2017{
2018	iri->type = XMLRI_ELEMENTID;
2019	iri->target = gf_sg_find_node_by_name(elt->sgprivate->scenegraph, attribute_content);
2020	if (!iri->target) {
2021		iri->string = gf_strdup(attribute_content);
2022	} else {
2023		gf_node_register_iri(elt->sgprivate->scenegraph, iri);
2024	}
2025}
2026
2027/* Parses a paint attribute: none, inherit or color */
2028static void svg_parse_paint(GF_Node *n, SVG_Paint *paint, char *attribute_content)
2029{
2030	if (!strcmp(attribute_content, "none")) {
2031		paint->type = SVG_PAINT_NONE;
2032	} else if (!strcmp(attribute_content, "inherit")) {
2033		paint->type = SVG_PAINT_INHERIT;
2034	} else if (!strncmp(attribute_content, "url(", 4) ) {
2035		char *ext = strrchr(attribute_content, ')');
2036		paint->type = SVG_PAINT_URI;
2037		if (ext) ext[0] = 0;
2038		svg_parse_iri(n, &paint->iri, attribute_content+4);
2039		if (ext) ext[0] = ')';
2040	} else {
2041		paint->type = SVG_PAINT_COLOR;
2042		svg_parse_color(&paint->color, attribute_content);
2043	}
2044}
2045
2046/* Parses a length which is a number with a unit */
2047static u32 svg_parse_length(SVG_Number *number, char *value_string, Bool clamp0to1)
2048{
2049    char c = '\0';
2050    char *unit = NULL;
2051    u32 len = 0;
2052    u32 unit_pos = 0;
2053    u32 unit_len = 0;
2054    u32 read_chars;
2055
2056	if (!strcmp(value_string, "inherit")) {
2057		number->type = SVG_NUMBER_INHERIT;
2058		return 7;
2059	} else if (!strcmp(value_string, "auto")) {
2060		number->type = SVG_NUMBER_AUTO;
2061		return 4;
2062	} else if (!strcmp(value_string, "auto-reverse")) {
2063		number->type = SVG_NUMBER_AUTO_REVERSE;
2064		return 12;
2065	} else if ((unit = strstr(value_string, "%")) ) {
2066		number->type = SVG_NUMBER_PERCENTAGE;
2067        unit_len = 1;
2068	} else if ((unit = strstr(value_string, "em"))) {
2069		number->type = SVG_NUMBER_EMS;
2070	} else if ((unit = strstr(value_string, "ex"))) {
2071		number->type = SVG_NUMBER_EXS;
2072	} else if ((unit = strstr(value_string, "px"))) {
2073		number->type = SVG_NUMBER_PX;
2074	} else if ((unit = strstr(value_string, "cm"))) {
2075		number->type = SVG_NUMBER_CM;
2076	} else if ((unit = strstr(value_string, "mm"))) {
2077		number->type = SVG_NUMBER_MM;
2078	} else if ((unit = strstr(value_string, "in"))) {
2079		number->type = SVG_NUMBER_IN;
2080	} else if ((unit = strstr(value_string, "pt"))) {
2081		number->type = SVG_NUMBER_PT;
2082	} else if ((unit = strstr(value_string, "pc"))) {
2083		number->type = SVG_NUMBER_PC;
2084	} else {
2085		number->type = SVG_NUMBER_VALUE;
2086	}
2087    if (unit) {
2088        if (!unit_len) unit_len = 2;
2089        unit_pos = (u32) (unit - value_string);
2090        /* setting the first unit character to 0 for the svg_parse_number method to finish */
2091        c = value_string[unit_pos];
2092        value_string[unit_pos] = 0;
2093    }
2094	read_chars = svg_parse_number(value_string, &(number->value), 0);
2095    if (unit) {
2096        value_string[unit_pos] = c;
2097    }
2098    if (!read_chars) {
2099        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing: %s\n", value_string));
2100        len = 0;
2101    } else {
2102        len = unit_len + read_chars;
2103    }
2104
2105	if (clamp0to1) number->value = MAX(0, MIN(1, number->value));
2106	return len;
2107}
2108
2109static void svg_parse_visibility(SVG_Visibility *value, char *value_string)
2110{
2111	if (!strcmp(value_string, "inherit")) {
2112		*value = SVG_VISIBILITY_INHERIT;
2113	} else if (!strcmp(value_string, "visible")) {
2114		*value = SVG_VISIBILITY_VISIBLE;
2115	} else if (!strcmp(value_string, "hidden")) {
2116		*value = SVG_VISIBILITY_HIDDEN;
2117	} else if (!strcmp(value_string, "collapse")) {
2118		*value = SVG_VISIBILITY_COLLAPSE;
2119	}
2120}
2121
2122static void svg_parse_display(SVG_Display *value, char *value_string)
2123{
2124	if (!strcmp(value_string, "inherit")) {
2125		*value = SVG_DISPLAY_INHERIT;
2126	} else if (!strcmp(value_string, "none")) {
2127		*value = SVG_DISPLAY_NONE;
2128	} else if (!strcmp(value_string, "inline")) {
2129		*value = SVG_DISPLAY_INLINE;
2130	} else if (!strcmp(value_string, "block")) {
2131		*value = SVG_DISPLAY_BLOCK;
2132	} else if (!strcmp(value_string, "list-item")) {
2133		*value = SVG_DISPLAY_LIST_ITEM;
2134	} else if (!strcmp(value_string, "run-in")) {
2135		*value = SVG_DISPLAY_RUN_IN;
2136	} else if (!strcmp(value_string, "compact")) {
2137		*value = SVG_DISPLAY_COMPACT;
2138	} else if (!strcmp(value_string, "marker")) {
2139		*value = SVG_DISPLAY_MARKER;
2140	} else if (!strcmp(value_string, "table")) {
2141		*value = SVG_DISPLAY_TABLE;
2142	} else if (!strcmp(value_string, "inline-table")) {
2143		*value = SVG_DISPLAY_INLINE_TABLE;
2144	} else if (!strcmp(value_string, "table-row-group")) {
2145		*value = SVG_DISPLAY_TABLE_ROW_GROUP;
2146	} else if (!strcmp(value_string, "table-header-group")) {
2147		*value = SVG_DISPLAY_TABLE_HEADER_GROUP;
2148	} else if (!strcmp(value_string, "table-footer-group")) {
2149		*value = SVG_DISPLAY_TABLE_FOOTER_GROUP;
2150	} else if (!strcmp(value_string, "table-row")) {
2151		*value = SVG_DISPLAY_TABLE_ROW;
2152	} else if (!strcmp(value_string, "table-column-group")) {
2153		*value = SVG_DISPLAY_TABLE_COLUMN_GROUP;
2154	} else if (!strcmp(value_string, "table-column")) {
2155		*value = SVG_DISPLAY_TABLE_COLUMN;
2156	} else if (!strcmp(value_string, "table-cell")) {
2157		*value = SVG_DISPLAY_TABLE_CELL;
2158	} else if (!strcmp(value_string, "table-caption")) {
2159		*value = SVG_DISPLAY_TABLE_CAPTION;
2160	}
2161}
2162
2163static void svg_parse_displayalign(SVG_DisplayAlign *value, char *value_string)
2164{
2165	if (!strcmp(value_string, "inherit")) {
2166		*value = SVG_DISPLAYALIGN_INHERIT;
2167	} else if (!strcmp(value_string, "auto")) {
2168		*value = SVG_DISPLAYALIGN_AUTO;
2169	} else if (!strcmp(value_string, "before")) {
2170		*value = SVG_DISPLAYALIGN_BEFORE;
2171	} else if (!strcmp(value_string, "center")) {
2172		*value = SVG_DISPLAYALIGN_CENTER;
2173	} else if (!strcmp(value_string, "after")) {
2174		*value = SVG_DISPLAYALIGN_AFTER;
2175	}
2176}
2177
2178static void svg_parse_textalign(SVG_TextAlign *value, char *value_string)
2179{
2180	if (!strcmp(value_string, "inherit")) {
2181		*value = SVG_TEXTALIGN_INHERIT;
2182	} else if (!strcmp(value_string, "start")) {
2183		*value = SVG_TEXTALIGN_START;
2184	} else if (!strcmp(value_string, "center")) {
2185		*value = SVG_TEXTALIGN_CENTER;
2186	} else if (!strcmp(value_string, "end")) {
2187		*value = SVG_TEXTALIGN_END;
2188	}
2189}
2190
2191static void svg_parse_pointerevents(SVG_PointerEvents *value, char *value_string)
2192{
2193	if (!strcmp(value_string, "inherit")) {
2194		*value = SVG_POINTEREVENTS_INHERIT;
2195	} else if (!strcmp(value_string, "visiblePainted")) {
2196		*value = SVG_POINTEREVENTS_VISIBLEPAINTED;
2197	} else if (!strcmp(value_string, "visibleFill")) {
2198		*value = SVG_POINTEREVENTS_VISIBLEFILL;
2199	} else if (!strcmp(value_string, "visibleStroke")) {
2200		*value = SVG_POINTEREVENTS_VISIBLESTROKE;
2201	} else if (!strcmp(value_string, "visible")) {
2202		*value = SVG_POINTEREVENTS_VISIBLE;
2203	} else if (!strcmp(value_string, "painted")) {
2204		*value = SVG_POINTEREVENTS_PAINTED;
2205	} else if (!strcmp(value_string, "fill")) {
2206		*value = SVG_POINTEREVENTS_FILL;
2207	} else if (!strcmp(value_string, "stroke")) {
2208		*value = SVG_POINTEREVENTS_STROKE;
2209	} else if (!strcmp(value_string, "all")) {
2210		*value = SVG_POINTEREVENTS_ALL;
2211	} else if (!strcmp(value_string, "boundingBox")) {
2212		*value = SVG_POINTEREVENTS_BOUNDINGBOX;
2213	} else if (!strcmp(value_string, "none")) {
2214		*value = SVG_POINTEREVENTS_NONE;
2215	}
2216}
2217
2218static void svg_parse_renderinghint(SVG_RenderingHint *value, char *value_string)
2219{
2220	if (!strcmp(value_string, "inherit")) {
2221		*value = SVG_RENDERINGHINT_INHERIT;
2222	} else if (!strcmp(value_string, "auto")) {
2223		*value = SVG_RENDERINGHINT_AUTO;
2224	} else if (!strcmp(value_string, "optimizeQuality")) {
2225		*value = SVG_RENDERINGHINT_OPTIMIZEQUALITY;
2226	} else if (!strcmp(value_string, "optimizeSpeed")) {
2227		*value = SVG_RENDERINGHINT_OPTIMIZESPEED;
2228	} else if (!strcmp(value_string, "optimizeLegibility")) {
2229		*value = SVG_RENDERINGHINT_OPTIMIZELEGIBILITY;
2230	} else if (!strcmp(value_string, "crispEdges")) {
2231		*value = SVG_RENDERINGHINT_CRISPEDGES;
2232	} else if (!strcmp(value_string, "geometricPrecision")) {
2233		*value = SVG_RENDERINGHINT_GEOMETRICPRECISION;
2234	}
2235}
2236
2237static void svg_parse_vectoreffect(SVG_VectorEffect *value, char *value_string)
2238{
2239	if (!strcmp(value_string, "inherit")) {
2240		*value = SVG_VECTOREFFECT_INHERIT;
2241	} else if (!strcmp(value_string, "none")) {
2242		*value = SVG_VECTOREFFECT_NONE;
2243	} else if (!strcmp(value_string, "non-scaling-stroke")) {
2244		*value = SVG_VECTOREFFECT_NONSCALINGSTROKE;
2245	}
2246}
2247
2248static void svg_parse_playbackorder(SVG_VectorEffect *value, char *value_string)
2249{
2250	if (!strcmp(value_string, "forwardOnly")) {
2251		*value = SVG_PLAYBACKORDER_FORWARDONLY;
2252	} else if (!strcmp(value_string, "all")) {
2253		*value = SVG_PLAYBACKORDER_ALL;
2254	}
2255}
2256
2257static void svg_parse_timelinebegin(SVG_TimelineBegin *value, char *value_string)
2258{
2259	if (!strcmp(value_string, "onStart")) {
2260		*value = SVG_TIMELINEBEGIN_ONSTART;
2261	} else if (!strcmp(value_string, "onLoad")) {
2262		*value = SVG_TIMELINEBEGIN_ONLOAD;
2263	}
2264}
2265
2266static void svg_parse_xmlspace(XML_Space *value, char *value_string)
2267{
2268	if (!strcmp(value_string, "default")) {
2269		*value = XML_SPACE_DEFAULT;
2270	} else if (!strcmp(value_string, "preserve")) {
2271		*value = XML_SPACE_PRESERVE;
2272	}
2273}
2274
2275static void svg_parse_xmlev_propagate(XMLEV_Propagate *value, char *value_string)
2276{
2277	if (!strcmp(value_string, "continue")) {
2278		*value = XMLEVENT_PROPAGATE_CONTINUE;
2279	} else if (!strcmp(value_string, "stop")) {
2280		*value = XMLEVENT_PROPAGATE_STOP;
2281	}
2282}
2283
2284static void svg_parse_xmlev_defaultAction(XMLEV_DefaultAction *value, char *value_string)
2285{
2286	if (!strcmp(value_string, "cancel")) {
2287		*value = XMLEVENT_DEFAULTACTION_CANCEL;
2288	} else if (!strcmp(value_string, "perform")) {
2289		*value = XMLEVENT_DEFAULTACTION_PERFORM;
2290	}
2291}
2292
2293static void svg_parse_xmlev_phase(XMLEV_Phase *value, char *value_string)
2294{
2295	if (!strcmp(value_string, "default")) {
2296		*value = XMLEVENT_PHASE_DEFAULT;
2297	} else if (!strcmp(value_string, "capture")) {
2298		*value = XMLEVENT_PHASE_CAPTURE;
2299	}
2300}
2301
2302static void svg_parse_overflow(SVG_Overflow *value, char *value_string)
2303{
2304	if (!strcmp(value_string, "inherit")) {
2305		*value = SVG_OVERFLOW_INHERIT;
2306	} else if (!strcmp(value_string, "visible")) {
2307		*value = SVG_OVERFLOW_VISIBLE;
2308	} else if (!strcmp(value_string, "hidden")) {
2309		*value = SVG_OVERFLOW_HIDDEN;
2310	} else if (!strcmp(value_string, "scroll")) {
2311		*value = SVG_OVERFLOW_SCROLL;
2312	} else if (!strcmp(value_string, "auto")) {
2313		*value = SVG_OVERFLOW_AUTO;
2314	}
2315}
2316
2317static void svg_parse_textanchor(SVG_TextAnchor *value, char *value_string)
2318{
2319	if (!strcmp(value_string, "inherit")) {
2320		*value = SVG_TEXTANCHOR_INHERIT;
2321	} else if (!strcmp(value_string, "start")) {
2322		*value = SVG_TEXTANCHOR_START;
2323	} else if (!strcmp(value_string, "middle")) {
2324		*value = SVG_TEXTANCHOR_MIDDLE;
2325	} else if (!strcmp(value_string, "end")) {
2326		*value = SVG_TEXTANCHOR_END;
2327	}
2328}
2329
2330static void svg_parse_clipfillrule(SVG_FillRule *value, char *value_string)
2331{
2332	if (!strcmp(value_string, "inherit")) {
2333		*value = SVG_FILLRULE_INHERIT;
2334	} else if (!strcmp(value_string, "nonzero")) {
2335		*value = SVG_FILLRULE_NONZERO;
2336	} else if (!strcmp(value_string, "evenodd")) {
2337		*value = SVG_FILLRULE_EVENODD;
2338	}
2339}
2340
2341static void svg_parse_strokelinejoin(SVG_StrokeLineJoin *value, char *value_string)
2342{
2343	if (!strcmp(value_string, "inherit")) {
2344		*value = SVG_STROKELINEJOIN_INHERIT;
2345	} else if (!strcmp(value_string, "miter")) {
2346		*value = SVG_STROKELINEJOIN_MITER;
2347	} else if (!strcmp(value_string, "round")) {
2348		*value = SVG_STROKELINEJOIN_ROUND;
2349	} else if (!strcmp(value_string, "bevel")) {
2350		*value = SVG_STROKELINEJOIN_BEVEL;
2351	}
2352}
2353
2354static void svg_parse_strokelinecap(SVG_StrokeLineCap *value, char *value_string)
2355{
2356	if (!strcmp(value_string, "inherit")) {
2357		*value = SVG_STROKELINECAP_INHERIT;
2358	} else if (!strcmp(value_string, "butt")) {
2359		*value = SVG_STROKELINECAP_BUTT;
2360	} else if (!strcmp(value_string, "round")) {
2361		*value = SVG_STROKELINECAP_ROUND;
2362	} else if (!strcmp(value_string, "square")) {
2363		*value = SVG_STROKELINECAP_SQUARE;
2364	}
2365}
2366
2367static void svg_parse_fontfamily(SVG_FontFamily *value, char *value_string)
2368{
2369	if (!strcmp(value_string, "inherit")) {
2370		value->type = SVG_FONTFAMILY_INHERIT;
2371	} else {
2372		value->type = SVG_FONTFAMILY_VALUE;
2373		value->value = gf_strdup(value_string);
2374	}
2375}
2376
2377static void svg_parse_fontstyle(SVG_FontStyle *value, char *value_string)
2378{
2379	if (!strcmp(value_string, "inherit")) {
2380		*value = SVG_FONTSTYLE_INHERIT;
2381	} else if (!strcmp(value_string, "normal")) {
2382		*value = SVG_FONTSTYLE_NORMAL;
2383	} else if (!strcmp(value_string, "italic")) {
2384		*value = SVG_FONTSTYLE_ITALIC;
2385	} else if (!strcmp(value_string, "oblique")) {
2386		*value = SVG_FONTSTYLE_OBLIQUE;
2387	}
2388}
2389
2390static void svg_parse_fontweight(SVG_FontWeight *value, char *value_string)
2391{
2392	if (!strcmp(value_string, "inherit")) {
2393		*value = SVG_FONTWEIGHT_INHERIT;
2394	} else if (!strcmp(value_string, "normal")) {
2395		*value = SVG_FONTWEIGHT_NORMAL;
2396	} else if (!strcmp(value_string, "bold")) {
2397		*value = SVG_FONTWEIGHT_BOLD;
2398	} else if (!strcmp(value_string, "bolder")) {
2399		*value = SVG_FONTWEIGHT_BOLDER;
2400	} else if (!strcmp(value_string, "lighter")) {
2401		*value = SVG_FONTWEIGHT_LIGHTER;
2402	} else if (!strcmp(value_string, "100")) {
2403		*value = SVG_FONTWEIGHT_100;
2404	} else if (!strcmp(value_string, "200")) {
2405		*value = SVG_FONTWEIGHT_200;
2406	} else if (!strcmp(value_string, "300")) {
2407		*value = SVG_FONTWEIGHT_300;
2408	} else if (!strcmp(value_string, "400")) {
2409		*value = SVG_FONTWEIGHT_400;
2410	} else if (!strcmp(value_string, "500")) {
2411		*value = SVG_FONTWEIGHT_500;
2412	} else if (!strcmp(value_string, "600")) {
2413		*value = SVG_FONTWEIGHT_600;
2414	} else if (!strcmp(value_string, "700")) {
2415		*value = SVG_FONTWEIGHT_700;
2416	} else if (!strcmp(value_string, "800")) {
2417		*value = SVG_FONTWEIGHT_800;
2418	} else if (!strcmp(value_string, "900")) {
2419		*value = SVG_FONTWEIGHT_900;
2420	}
2421}
2422
2423static void svg_parse_fontvariant(SVG_FontVariant *value, char *value_string)
2424{
2425	if (!strcmp(value_string, "inherit")) {
2426		*value = SVG_FONTVARIANT_INHERIT;
2427	} else if (!strcmp(value_string, "normal")) {
2428		*value = SVG_FONTVARIANT_NORMAL;
2429	} else if (!strcmp(value_string, "small-caps")) {
2430		*value = SVG_FONTVARIANT_SMALLCAPS;
2431	}
2432}
2433
2434static void svg_parse_boolean(SVG_Boolean *value, char *value_string)
2435{
2436	/*simple for text editable*/
2437	if (!strcmp(value_string, "1") || !strcmp(value_string, "true") || !strcmp(value_string, "simple"))
2438		*value = 1;
2439	else
2440		*value = 0;
2441}
2442
2443
2444static void smil_parse_time_list(GF_Node *e, GF_List *values, char *begin_or_end_list)
2445{
2446	SMIL_Time *value;
2447	char value_string[500];
2448	char *str = begin_or_end_list, *tmp;
2449	u32 len;
2450
2451	/* get rid of leading spaces */
2452	while (*str == ' ') str++;
2453
2454	while (1) {
2455		tmp = strchr(str, ';');
2456		if (tmp) len = (u32) (tmp-str);
2457		else len = (u32) strlen(str);
2458		memcpy(value_string, str, len);
2459		while (value_string[len - 1] == ' ' && len > 0) len--;
2460		value_string[len] = 0;
2461
2462		GF_SAFEALLOC(value, SMIL_Time)
2463 		gf_list_add(values, value);
2464
2465		if (smil_parse_time(e, value, value_string) != GF_OK) goto err;
2466
2467		if (!tmp) break;
2468
2469		str = tmp + 1;
2470		while (*str == ' ') str++;
2471	}
2472
2473	/* sorting timing values */
2474	if (gf_list_count(values) > 1) {
2475		SMIL_Time *v, *sv;
2476		GF_List *sorted = gf_list_new();
2477		u32 i, count;
2478		u8 added = 0;
2479		do {
2480			v = (SMIL_Time*)gf_list_get(values, 0);
2481			gf_list_rem(values, 0);
2482			added = 0;
2483			count = gf_list_count(sorted);
2484			for (i=0; i<count; i++) {
2485				sv = (SMIL_Time*)gf_list_get(sorted, i);
2486				if (v->type >= GF_SMIL_TIME_EVENT) {
2487					/* unresolved or indefinite so add at the end of the sorted list */
2488					gf_list_add(sorted, v);
2489					added = 1;
2490					break;
2491				} else {
2492					if (sv->type >= GF_SMIL_TIME_EVENT) {
2493						gf_list_insert(sorted, v, i);
2494						added = 1;
2495						break;
2496					} else {
2497						if (v->clock <= sv->clock) {
2498							gf_list_insert(sorted, v, i);
2499							added = 1;
2500							break;
2501						}
2502					}
2503				}
2504			}
2505			if (!added) gf_list_add(sorted, v);
2506		} while (gf_list_count(values) > 0);
2507
2508		count = gf_list_count(sorted);
2509		for (i = 0; i < count; i++) {
2510			gf_list_add(values, gf_list_get(sorted, i));
2511		}
2512		gf_list_del(sorted);
2513	}
2514	return;
2515
2516err:
2517	/* See SVG spec:
2518	"If the 'begin' attribute is
2519	syntactically invalid, in the list itself or in any of the individual
2520	list values, it is equivalent to a single 'begin' value of 'indefinite'."*/
2521	len = gf_list_count(values);
2522	while (len) {
2523		SMIL_Time *v = (SMIL_Time*)gf_list_get(values, 0);
2524		if (v->element_id) gf_free(v->element_id);
2525		gf_list_rem(values, 0);
2526		gf_free(v);
2527		len--;
2528	}
2529
2530	GF_SAFEALLOC(value, SMIL_Time)
2531	gf_list_add(values, value);
2532
2533	switch (e->sgprivate->tag) {
2534	case TAG_SVG_discard:
2535		value->type = GF_SMIL_TIME_CLOCK;
2536		value->clock = 0;
2537		break;
2538	default:
2539		value->type = GF_SMIL_TIME_INDEFINITE;
2540		break;
2541	}
2542	return;
2543}
2544
2545static void smil_parse_attributeType(SMIL_AttributeType *value, char *value_string)
2546{
2547	if (!strcmp(value_string, "auto")) {
2548		*value = SMIL_ATTRIBUTETYPE_AUTO;
2549	} else if (!strcmp(value_string, "XML")) {
2550		*value = SMIL_ATTRIBUTETYPE_XML;
2551	} else if (!strcmp(value_string, "CSS")) {
2552		*value = SMIL_ATTRIBUTETYPE_CSS;
2553	}
2554}
2555
2556static void smil_parse_min_max_dur_repeatdur(SMIL_Duration *value, char *value_string)
2557{
2558	if (!strcmp(value_string, "indefinite")) {
2559		value->type = SMIL_DURATION_INDEFINITE;
2560	} else if (!strcmp(value_string, "media")) {
2561		value->type = SMIL_DURATION_MEDIA;
2562	} else {
2563		Double ftime;
2564		if ((svg_parse_clock_value(value_string, &ftime) == GF_OK) && (ftime >= 0)) {
2565			value->clock_value = ftime;
2566			value->type = SMIL_DURATION_DEFINED;
2567		} else {
2568			/* WARNING: Should this attribute in error be removed ? */
2569			value->type = SMIL_DURATION_INDEFINITE;
2570		}
2571	}
2572}
2573
2574static void smil_parse_repeatcount(SMIL_RepeatCount *value, char *value_string)
2575{
2576	if (!strcmp(value_string, "indefinite")) {
2577		value->type = SMIL_REPEATCOUNT_INDEFINITE;
2578	} else {
2579		Float _val;
2580		sscanf(value_string, "%f", &_val);
2581		value->type = SMIL_REPEATCOUNT_DEFINED;
2582		value->count = FLT2FIX(_val);
2583	}
2584}
2585
2586static void smil_parse_fill(SMIL_Fill *value, char *value_string)
2587{
2588	if (!strcmp(value_string, "freeze")) {
2589		*value = SMIL_FILL_FREEZE;
2590	} else if (!strcmp(value_string, "remove")) {
2591		*value = SMIL_FILL_REMOVE;
2592	}
2593}
2594
2595static void smil_parse_restart(SMIL_Restart *value, char *value_string)
2596{
2597	if (!strcmp(value_string, "always")) {
2598		*value = SMIL_RESTART_ALWAYS;
2599	} else if (!strcmp(value_string, "whenNotActive")) {
2600		*value = SMIL_RESTART_WHENNOTACTIVE;
2601	} else if (!strcmp(value_string, "never")) {
2602		*value = SMIL_RESTART_NEVER;
2603	}
2604}
2605
2606static void smil_parse_calcmode(SMIL_CalcMode *value, char *value_string)
2607{
2608	if (!strcmp(value_string, "discrete")) {
2609		*value = SMIL_CALCMODE_DISCRETE;
2610	} else if (!strcmp(value_string, "linear")) {
2611		*value = SMIL_CALCMODE_LINEAR;
2612	} else if (!strcmp(value_string, "paced")) {
2613		*value = SMIL_CALCMODE_PACED;
2614	} else if (!strcmp(value_string, "spline")) {
2615		*value = SMIL_CALCMODE_SPLINE;
2616	}
2617}
2618
2619static void smil_parse_additive(SMIL_Additive *value, char *value_string)
2620{
2621	if (!strcmp(value_string, "replace")) {
2622		*value = SMIL_ADDITIVE_REPLACE;
2623	} else if (!strcmp(value_string, "sum")) {
2624		*value = SMIL_ADDITIVE_SUM;
2625	}
2626}
2627
2628static void smil_parse_accumulate(SMIL_Accumulate *value, char *value_string)
2629{
2630	if (!strcmp(value_string, "none")) {
2631		*value = SMIL_ACCUMULATE_NONE;
2632	} else if (!strcmp(value_string, "sum")) {
2633		*value = SMIL_ACCUMULATE_SUM;
2634	}
2635}
2636
2637static void smil_parse_syncBehaviorOrDefault(SMIL_SyncBehavior *value, char *value_string)
2638{
2639	if (!strcmp(value_string, "inherit")) {
2640		*value = SMIL_SYNCBEHAVIOR_INHERIT;
2641	} else if (!strcmp(value_string, "default")) {
2642		*value = SMIL_SYNCBEHAVIOR_DEFAULT;
2643	} else if (!strcmp(value_string, "locked")) {
2644		*value = SMIL_SYNCBEHAVIOR_LOCKED;
2645	} else if (!strcmp(value_string, "canSlip")) {
2646		*value = SMIL_SYNCBEHAVIOR_CANSLIP;
2647	} else if (!strcmp(value_string, "independent")) {
2648		*value = SMIL_SYNCBEHAVIOR_INDEPENDENT;
2649	}
2650}
2651
2652static void smil_parse_syncToleranceOrDefault(SMIL_SyncTolerance *value, char *value_string)
2653{
2654	if (!strcmp(value_string, "inherit")) {
2655		value->type = SMIL_SYNCTOLERANCE_INHERIT;
2656	} else if (!strcmp(value_string, "default")) {
2657		value->type = SMIL_SYNCTOLERANCE_DEFAULT;
2658	} else {
2659		value->type = SMIL_SYNCBEHAVIOR_LOCKED;
2660		svg_parse_clock_value(value_string, &(value->value));
2661	}
2662}
2663
2664static void svg_parse_viewbox(SVG_ViewBox *value, char *value_string)
2665{
2666    u32 read_chars;
2667	char *str = value_string;
2668	if (!strcmp(str, "none")) {
2669		value->is_set = 0;
2670	} else {
2671		u32 i = 0;
2672		value->is_set = 1;
2673		read_chars = svg_parse_number(&(str[i]), &(value->x), 0);
2674        if (!read_chars) return;
2675        i += read_chars;
2676		read_chars = svg_parse_number(&(str[i]), &(value->y), 0);
2677        if (!read_chars) return;
2678        i += read_chars;
2679		read_chars = svg_parse_number(&(str[i]), &(value->width), 0);
2680        if (!read_chars) return;
2681        i += read_chars;
2682		read_chars = svg_parse_number(&(str[i]), &(value->height), 0);
2683        if (!read_chars) return;
2684        i += read_chars;
2685	}
2686}
2687
2688/* Parses a list of coordinates or a list of lengths (in SVG, length and coordinate is the same type )*/
2689static void svg_parse_coordinates(GF_List *values, char *value_string)
2690{
2691	SVG_Coordinate *c;
2692	u32 i = 0;
2693	char *str = value_string;
2694	u32 len = (u32) strlen(str);
2695
2696	while (gf_list_count(values)) {
2697		c = (SVG_Coordinate*)gf_list_get(values, 0);
2698		gf_list_rem(values, 0);
2699		gf_free(c);
2700	}
2701	while (i < len) {
2702		u32 sub;
2703		GF_SAFEALLOC(c, SVG_Coordinate)
2704		sub = svg_parse_length(c, &(str[i]), 0);
2705		if (!sub) {
2706			gf_free(c);
2707			return;
2708		}
2709		i+=sub;
2710		gf_list_add(values, c);
2711	}
2712}
2713
2714/* Parse a point as a pair of number without units */
2715u32 svg_parse_point(SVG_Point *p, char *value_string)
2716{
2717	u32 i = 0, j = 0;
2718	i = svg_parse_number(&(value_string[i]), &(p->x), 0);
2719    /* TODO: handle cases where a point has an invalid syntax */
2720	j = svg_parse_number(&(value_string[i]), &(p->y), 0);
2721	/* we need to detect an odd number of coordinates in polygon points list
2722	   cf. http://www.w3.org/TR/SVGMobile12/shapes.html#PolygonElement
2723	   see svg_parse_points */
2724	if (j == 0) return 0;
2725	else return i+j;
2726}
2727
2728static u32 svg_parse_point_into_matrix(GF_Matrix2D *p, char *value_string)
2729{
2730	u32 i = 0, j = 0;
2731	gf_mx2d_init(*p);
2732	i = svg_parse_number(&(value_string[i]), &(p->m[2]), 0);
2733    if (i == 0) return 0;
2734	j = svg_parse_number(&(value_string[i]), &(p->m[5]), 0);
2735    if (j == 0) return 0;
2736	return i+j;
2737}
2738
2739/* Parses the points attribute of a polygon or polyline element */
2740static void svg_parse_points(GF_List *values, char *value_string)
2741{
2742	u32 i = 0, j;
2743	char *str = value_string;
2744	u32 len = (u32) strlen(str);
2745	while (i < len) {
2746		SVG_Point *p;
2747		GF_SAFEALLOC(p, SVG_Point)
2748		j = svg_parse_point(p, &str[i]);
2749		if (j == 0) {
2750			/* cf. http://www.w3.org/TR/SVGMobile12/shapes.html#PolygonElement
2751			   If an odd number of coordinates is provided, then the element
2752			   is treated as if the attribute had not been specified.*/
2753			while (gf_list_count(values)) {
2754				p = (SVG_Point *)gf_list_get(values, 0);
2755				gf_free(p);
2756				gf_list_rem(values, 0);
2757			}
2758			return;
2759		}
2760		i += j;
2761		gf_list_add(values, p);
2762	}
2763}
2764
2765/* Parses a list of numbers */
2766static void svg_parse_numbers(GF_List *values, char *value_string, Bool is_angle)
2767{
2768    u32 read_chars;
2769	u32 i = 0;
2770	char *str = value_string;
2771	u32 len = (u32) strlen(str);
2772	while (i < len) {
2773		Fixed *f;
2774		GF_SAFEALLOC(f, Fixed)
2775		read_chars = svg_parse_number(&(str[i]), f, is_angle);
2776		if (!read_chars) {
2777			gf_free(f);
2778			return;
2779		}
2780        i += read_chars;
2781		gf_list_add(values, f);
2782	}
2783}
2784
2785static void svg_string_list_add(GF_List *values, char *string, u32 string_type)
2786{
2787	XMLRI *iri;
2788	switch (string_type) {
2789	case 1:
2790		iri = (XMLRI*)gf_malloc(sizeof(XMLRI));
2791		iri->type = XMLRI_STRING;
2792		iri->string = gf_strdup(string);
2793		gf_list_add(values, iri);
2794		break;
2795	default:
2796		gf_list_add(values, gf_strdup(string));
2797		break;
2798	}
2799}
2800
2801static void svg_parse_strings(GF_List *values, char *value_string, u32 string_type)
2802{
2803	char *next, *sep = value_string;
2804
2805	while (gf_list_count(values)) {
2806		next = (char*)gf_list_last(values);
2807		gf_list_rem_last(values);
2808		gf_free(next);
2809	}
2810
2811	while (1) {
2812		while (sep && sep[0]==' ') sep++;
2813		if (!sep) break;
2814		next = sep+1;
2815		while (next[0]) {
2816			if (strchr(" ;,", next[0])) break;
2817			next++;
2818		}
2819		if (!next[0]) {
2820			svg_string_list_add(values, sep, string_type);
2821			break;
2822		}
2823		next[0]=0;
2824		svg_string_list_add(values, sep, string_type);
2825		next[0]=';';
2826		sep = next+1;
2827		while (strchr(" ,;", sep[0])) sep++;
2828	}
2829}
2830
2831static void svg_parse_strokedasharray(SVG_StrokeDashArray *value, char *value_string)
2832{
2833    u32 read_chars;
2834	if (!strcmp(value_string, "none")) {
2835		value->type = SVG_STROKEDASHARRAY_NONE;
2836	} else if (!strcmp(value_string, "inherit")) {
2837		value->type = SVG_STROKEDASHARRAY_INHERIT;
2838	} else {
2839		UnitArray *vals = &(value->array);
2840		GF_List *values = gf_list_new();
2841		u32 i = 0;
2842		u32 len = (u32) strlen(value_string);
2843		char *str = value_string;
2844		while (i < len) {
2845			SVG_Length *f;
2846			GF_SAFEALLOC(f, SVG_Length)
2847			read_chars = svg_parse_length(f, &(str[i]), 0);
2848            if (!read_chars) {
2849                gf_free(f);
2850                return;
2851            }
2852            i += read_chars;
2853			gf_list_add(values, f);
2854		}
2855		vals->count = gf_list_count(values);
2856		vals->units = (u8 *) gf_malloc(sizeof(u8)*vals->count);
2857		vals->vals = (Fixed *) gf_malloc(sizeof(Fixed)*vals->count);
2858		for (i = 0; i < vals->count; i++) {
2859			SVG_Length *f = (SVG_Length *)gf_list_get(values, i);
2860			vals->vals[i] = f->value;
2861            vals->units[i] = f->type;
2862			gf_free(f);
2863		}
2864		gf_list_del(values);
2865		value->type = SVG_STROKEDASHARRAY_ARRAY;
2866	}
2867}
2868
2869static void svg_parse_zoomandpan(SVG_ZoomAndPan *value, char *value_string)
2870{
2871	if (!strcmp(value_string, "disable")) {
2872		*value = SVG_ZOOMANDPAN_DISABLE;
2873	} else if (!strcmp(value_string, "magnify")) {
2874		*value = SVG_ZOOMANDPAN_MAGNIFY;
2875	}
2876}
2877
2878static void svg_parse_preserveaspectratio(SVG_PreserveAspectRatio *par, char *attribute_content)
2879{
2880	char *content = attribute_content;
2881	while (*content == ' ') content++;
2882	if (strstr(content, "defer")) {
2883		par->defer = 1;
2884		content += 4;
2885	} else {
2886		content = attribute_content;
2887	}
2888	while (*content == ' ') content++;
2889	if (strstr(content, "none")) {
2890		par->align = SVG_PRESERVEASPECTRATIO_NONE;
2891		content+=4;
2892	} else if (strstr(content, "xMinYMin")) {
2893		par->align = SVG_PRESERVEASPECTRATIO_XMINYMIN;
2894		content+=8;
2895	} else if (strstr(content, "xMidYMin")) {
2896		par->align = SVG_PRESERVEASPECTRATIO_XMIDYMIN;
2897		content+=8;
2898	} else if (strstr(content, "xMaxYMin")) {
2899		par->align = SVG_PRESERVEASPECTRATIO_XMAXYMIN;
2900		content+=8;
2901	} else if (strstr(content, "xMinYMid")) {
2902		par->align = SVG_PRESERVEASPECTRATIO_XMINYMID;
2903		content+=8;
2904	} else if (strstr(content, "xMidYMid")) {
2905		par->align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
2906		content+=8;
2907	} else if (strstr(content, "xMaxYMid")) {
2908		par->align = SVG_PRESERVEASPECTRATIO_XMAXYMID;
2909		content+=8;
2910	} else if (strstr(content, "xMinYMax")) {
2911		par->align = SVG_PRESERVEASPECTRATIO_XMINYMAX;
2912		content+=8;
2913	} else if (strstr(content, "xMidYMax")) {
2914		par->align = SVG_PRESERVEASPECTRATIO_XMIDYMAX;
2915		content+=8;
2916	} else if (strstr(content, "xMaxYMax")) {
2917		par->align = SVG_PRESERVEASPECTRATIO_XMAXYMAX;
2918		content+=8;
2919	}
2920	while (*content == ' ') content++;
2921	if (*content == 0) return;
2922	if (strstr(content, "meet")) {
2923		par->meetOrSlice = SVG_MEETORSLICE_MEET;
2924	} else if (strstr(content, "slice")) {
2925		par->meetOrSlice = SVG_MEETORSLICE_SLICE;
2926	}
2927}
2928
2929static void svg_parse_animatetransform_type(SVG_TransformType *anim_transform_type, char *attribute_content)
2930{
2931	*anim_transform_type = SVG_TRANSFORM_MATRIX;
2932	if (!strcmp(attribute_content, "scale")) {
2933		*anim_transform_type = SVG_TRANSFORM_SCALE;
2934	} else if (!strcmp(attribute_content, "rotate")) {
2935		*anim_transform_type = SVG_TRANSFORM_ROTATE;
2936	} else if (!strcmp(attribute_content, "translate")) {
2937		*anim_transform_type = SVG_TRANSFORM_TRANSLATE;
2938	} else if (!strcmp(attribute_content, "skewX")) {
2939		*anim_transform_type = SVG_TRANSFORM_SKEWX;
2940	} else if (!strcmp(attribute_content, "skewY")) {
2941		*anim_transform_type = SVG_TRANSFORM_SKEWY;
2942	}
2943}
2944
2945static void svg_parse_focushighlight(SVG_FocusHighlight *fh, char *attribute_content)
2946{
2947	if (!strcmp(attribute_content, "auto")) {
2948		*fh = SVG_FOCUSHIGHLIGHT_AUTO;
2949	} else if (!strcmp(attribute_content, "none")) {
2950		*fh = SVG_FOCUSHIGHLIGHT_NONE;
2951	}
2952}
2953
2954static void svg_parse_focusable(SVG_Focusable *f, char *attribute_content)
2955{
2956	if (!strcmp(attribute_content, "true")) {
2957		*f = SVG_FOCUSABLE_TRUE;
2958	} else if (!strcmp(attribute_content, "false")) {
2959		*f = SVG_FOCUSABLE_FALSE;
2960	} else {
2961		*f = SVG_FOCUSABLE_AUTO;
2962	}
2963}
2964
2965static void svg_parse_initialvisibility(SVG_InitialVisibility *iv, char *attribute_content)
2966{
2967	if (!strcmp(attribute_content, "whenStarted")) {
2968		*iv = SVG_INITIALVISIBILTY_WHENSTARTED;
2969	} else if (!strcmp(attribute_content, "always")) {
2970		*iv = SVG_INITIALVISIBILTY_ALWAYS;
2971	}
2972}
2973
2974static void svg_parse_overlay(SVG_Overlay *o, char *attribute_content)
2975{
2976	if (!strcmp(attribute_content, "none")) {
2977		*o = SVG_OVERLAY_NONE;
2978	} else if (!strcmp(attribute_content, "top")) {
2979		*o = SVG_OVERLAY_TOP;
2980	}
2981}
2982
2983static void svg_parse_transformbehavior(SVG_TransformBehavior *tb, char *attribute_content)
2984{
2985	if (!strcmp(attribute_content, "geometric")) {
2986		*tb = SVG_TRANSFORMBEHAVIOR_GEOMETRIC;
2987	} else if (!strcmp(attribute_content, "pinned")) {
2988		*tb = SVG_TRANSFORMBEHAVIOR_PINNED;
2989	} else if (!strcmp(attribute_content, "pinned90")) {
2990		*tb = SVG_TRANSFORMBEHAVIOR_PINNED90;
2991	} else if (!strcmp(attribute_content, "pinned180")) {
2992		*tb = SVG_TRANSFORMBEHAVIOR_PINNED180;
2993	} else if (!strcmp(attribute_content, "pinned270")) {
2994		*tb = SVG_TRANSFORMBEHAVIOR_PINNED270;
2995	}
2996}
2997
2998static void svg_parse_focus(GF_Node *e,  SVG_Focus *o, char *attribute_content)
2999{
3000	if (o->target.string) gf_free(o->target.string);
3001	o->target.string = NULL;
3002	o->target.target = NULL;
3003
3004	if (!strcmp(attribute_content, "self")) o->type = SVG_FOCUS_SELF;
3005	else if (!strcmp(attribute_content, "auto")) o->type = SVG_FOCUS_AUTO;
3006	else if (!strnicmp(attribute_content, "url(", 4)) {
3007		char *sep = strrchr(attribute_content, ')');
3008		if (sep) sep[0] = 0;
3009		o->type = SVG_FOCUS_IRI;
3010		svg_parse_iri(e, &o->target, attribute_content+4);
3011		if (sep) sep[0] = ')';
3012	}
3013}
3014
3015/* end of Basic SVG datatype parsing functions */
3016
3017void svg_parse_one_anim_value(GF_Node *n, SMIL_AnimateValue *anim_value, char *attribute_content, u8 anim_value_type)
3018{
3019	GF_FieldInfo info;
3020	info.fieldType = anim_value_type;
3021	info.far_ptr = gf_svg_create_attribute_value(anim_value_type);
3022	if (info.far_ptr) gf_svg_parse_attribute(n, &info, attribute_content, 0);
3023
3024	anim_value->value = info.far_ptr;
3025	anim_value->type = anim_value_type;
3026}
3027
3028void svg_parse_anim_values(GF_Node *n, SMIL_AnimateValues *anim_values, char *anim_values_string, u8 anim_value_type)
3029{
3030	u32 i = 0;
3031	char *str;
3032	s32 psemi = -1;
3033	GF_FieldInfo info;
3034	info.fieldType = anim_value_type;
3035	anim_values->type = anim_value_type;
3036
3037	str = anim_values_string;
3038	while (1) {
3039		if (str[i] == ';' || str[i] == 0) {
3040			u32 single_value_len = 0;
3041			char c;
3042			single_value_len = i - (psemi+1);
3043			c = str [ (psemi+1) + single_value_len];
3044			str [ (psemi+1) + single_value_len] = 0;
3045			info.far_ptr = gf_svg_create_attribute_value(anim_value_type);
3046			if (info.far_ptr) {
3047				gf_svg_parse_attribute(n, &info, str + (psemi+1), anim_value_type);
3048				gf_list_add(anim_values->values, info.far_ptr);
3049			}
3050			str [ (psemi+1) + single_value_len] = c;
3051			psemi = i;
3052			if (!str[i]) return;
3053		}
3054		i++;
3055	}
3056}
3057
3058GF_Err laser_parse_choice(LASeR_Choice *choice, char *attribute_content)
3059{
3060	if (!strcmp(attribute_content, "none")) {
3061		choice->type = LASeR_CHOICE_NONE;
3062	} else if (!strcmp(attribute_content, "all")) {
3063		choice->type = LASeR_CHOICE_ALL;
3064	} else {
3065		choice->type = LASeR_CHOICE_N;
3066		choice->choice_index = atoi(attribute_content);
3067	}
3068	return GF_OK;
3069}
3070
3071GF_Err laser_parse_size(LASeR_Size *size, char *attribute_content)
3072{
3073	char *str = attribute_content;
3074	u32 i = 0;
3075	i+=svg_parse_number(&(str[i]), &(size->width), 0);
3076	i+=svg_parse_number(&(str[i]), &(size->height), 0);
3077	return GF_OK;
3078}
3079
3080GF_Err gf_svg_parse_element_id(GF_Node *n, const char *nodename, Bool warning_if_defined)
3081{
3082	GF_SceneGraph *sg = gf_node_get_graph((GF_Node *)n);
3083	u32 id = gf_sg_get_max_node_id(sg) + 1;
3084	gf_node_set_id(n, id, nodename);
3085	return GF_OK;
3086}
3087
3088/* Parse an SVG attribute */
3089GF_EXPORT
3090GF_Err gf_svg_parse_attribute(GF_Node *n, GF_FieldInfo *info, char *attribute_content, u8 anim_value_type)
3091{
3092    /* for all attributes, except strings, apply some sort of white space normalization*/
3093	if (info->fieldType != DOM_String_datatype && strlen(attribute_content)) {
3094		u32 i, len;
3095		/*remove spaces at the begining*/
3096		while (attribute_content[0] && (strchr("\r\n\t ", attribute_content[0])))
3097			attribute_content++;
3098
3099		/*change all special chars in spaces*/
3100		i=0;
3101		len = (u32) strlen(attribute_content);
3102		while (i<len) {
3103			if (strchr("\r\n\t", attribute_content[i]))
3104				attribute_content[i] = ' ';
3105			i++;
3106		}
3107		/*remove spaces in the end*/
3108		while (len && attribute_content[len-1]==' ') {
3109			attribute_content[len-1] = 0;
3110			len--;
3111		}
3112	}
3113
3114	switch (info->fieldType) {
3115	case SVG_Boolean_datatype:
3116		svg_parse_boolean((SVG_Boolean *)info->far_ptr, attribute_content);
3117	    break;
3118	case SVG_Color_datatype:
3119		svg_parse_color((SVG_Color *)info->far_ptr, attribute_content);
3120	    break;
3121	case SVG_Paint_datatype:
3122		svg_parse_paint(n, (SVG_Paint *)info->far_ptr, attribute_content);
3123		break;
3124
3125/* beginning of keyword type parsing */
3126	case SVG_FillRule_datatype:
3127		svg_parse_clipfillrule((SVG_FillRule *)info->far_ptr, attribute_content);
3128		break;
3129	case SVG_StrokeLineJoin_datatype:
3130		svg_parse_strokelinejoin((SVG_StrokeLineJoin *)info->far_ptr, attribute_content);
3131		break;
3132	case SVG_StrokeLineCap_datatype:
3133		svg_parse_strokelinecap((SVG_StrokeLineCap *)info->far_ptr, attribute_content);
3134		break;
3135	case SVG_FontStyle_datatype:
3136		svg_parse_fontstyle((SVG_FontStyle *)info->far_ptr, attribute_content);
3137		break;
3138	case SVG_FontWeight_datatype:
3139		svg_parse_fontweight((SVG_FontWeight *)info->far_ptr, attribute_content);
3140		break;
3141	case SVG_FontVariant_datatype:
3142		svg_parse_fontvariant((SVG_FontVariant *)info->far_ptr, attribute_content);
3143		break;
3144	case SVG_TextAnchor_datatype:
3145		svg_parse_textanchor((SVG_TextAnchor *)info->far_ptr, attribute_content);
3146		break;
3147	case SVG_Display_datatype:
3148		svg_parse_display((SVG_Display *)info->far_ptr, attribute_content);
3149		break;
3150	case SVG_Visibility_datatype:
3151		svg_parse_visibility((SVG_Visibility *)info->far_ptr, attribute_content);
3152		break;
3153	case SVG_Overflow_datatype:
3154		svg_parse_overflow((SVG_Overflow *)info->far_ptr, attribute_content);
3155		break;
3156	case SVG_ZoomAndPan_datatype:
3157		svg_parse_zoomandpan((SVG_ZoomAndPan *)info->far_ptr, attribute_content);
3158		break;
3159	case SVG_DisplayAlign_datatype:
3160		svg_parse_displayalign((SVG_DisplayAlign *)info->far_ptr, attribute_content);
3161		break;
3162	case SVG_TextAlign_datatype:
3163		svg_parse_textalign((SVG_TextAlign *)info->far_ptr, attribute_content);
3164		break;
3165	case SVG_PointerEvents_datatype:
3166		svg_parse_pointerevents((SVG_PointerEvents *)info->far_ptr, attribute_content);
3167		break;
3168	case SVG_RenderingHint_datatype:
3169		svg_parse_renderinghint((SVG_RenderingHint *)info->far_ptr, attribute_content);
3170		break;
3171	case SVG_VectorEffect_datatype:
3172		svg_parse_vectoreffect((SVG_VectorEffect *)info->far_ptr, attribute_content);
3173		break;
3174	case SVG_PlaybackOrder_datatype:
3175		svg_parse_playbackorder((SVG_PlaybackOrder *)info->far_ptr, attribute_content);
3176		break;
3177	case SVG_TimelineBegin_datatype:
3178		svg_parse_timelinebegin((SVG_TimelineBegin *)info->far_ptr, attribute_content);
3179		break;
3180	case XML_Space_datatype:
3181		svg_parse_xmlspace((XML_Space *)info->far_ptr, attribute_content);
3182		break;
3183	case XMLEV_Propagate_datatype:
3184		svg_parse_xmlev_propagate((XMLEV_Propagate *)info->far_ptr, attribute_content);
3185		break;
3186	case XMLEV_DefaultAction_datatype:
3187		svg_parse_xmlev_defaultAction((XMLEV_DefaultAction *)info->far_ptr, attribute_content);
3188		break;
3189	case XMLEV_Phase_datatype:
3190		svg_parse_xmlev_phase((XMLEV_Phase *)info->far_ptr, attribute_content);
3191		break;
3192	case SMIL_SyncBehavior_datatype:
3193		smil_parse_syncBehaviorOrDefault((SMIL_SyncBehavior *)info->far_ptr, attribute_content);
3194		break;
3195	case SMIL_SyncTolerance_datatype:
3196		smil_parse_syncToleranceOrDefault((SMIL_SyncTolerance *)info->far_ptr, attribute_content);
3197		break;
3198	case SMIL_AttributeType_datatype:
3199		smil_parse_attributeType((SMIL_AttributeType *)info->far_ptr, attribute_content);
3200		break;
3201	case SMIL_CalcMode_datatype:
3202		smil_parse_calcmode((SMIL_CalcMode *)info->far_ptr, attribute_content);
3203		break;
3204	case SMIL_Additive_datatype:
3205		smil_parse_additive((SMIL_CalcMode *)info->far_ptr, attribute_content);
3206		break;
3207	case SMIL_Accumulate_datatype:
3208		smil_parse_accumulate((SMIL_Accumulate *)info->far_ptr, attribute_content);
3209		break;
3210	case SMIL_Restart_datatype:
3211		smil_parse_restart((SMIL_Restart *)info->far_ptr, attribute_content);
3212		break;
3213	case SMIL_Fill_datatype:
3214		smil_parse_fill((SMIL_Fill *)info->far_ptr, attribute_content);
3215		break;
3216	case SVG_GradientUnit_datatype:
3217		*((SVG_GradientUnit *)info->far_ptr) = !strcmp(attribute_content, "userSpaceOnUse") ? SVG_GRADIENTUNITS_USER : SVG_GRADIENTUNITS_OBJECT;
3218		break;
3219	case SVG_FocusHighlight_datatype:
3220		svg_parse_focushighlight((SVG_FocusHighlight*)info->far_ptr, attribute_content);
3221		break;
3222	case SVG_Focusable_datatype:
3223		svg_parse_focusable((SVG_Focusable*)info->far_ptr, attribute_content);
3224		break;
3225
3226	case SVG_InitialVisibility_datatype:
3227		svg_parse_initialvisibility((SVG_InitialVisibility*)info->far_ptr, attribute_content);
3228		break;
3229	case SVG_Overlay_datatype:
3230		svg_parse_overlay((SVG_Overlay*)info->far_ptr, attribute_content);
3231		break;
3232	case SVG_TransformBehavior_datatype:
3233		svg_parse_transformbehavior((SVG_TransformBehavior*)info->far_ptr, attribute_content);
3234		break;
3235	case SVG_SpreadMethod_datatype:
3236		if (!strcmp(attribute_content, "reflect")) *(u8*)info->far_ptr = SVG_SPREAD_REFLECT;
3237		else if (!strcmp(attribute_content, "repeat")) *(u8*)info->far_ptr = SVG_SPREAD_REPEAT;
3238		else *(u8*)info->far_ptr = SVG_SPREAD_PAD;
3239		break;
3240	case SVG_Filter_TransferType_datatype:
3241		if (!strcmp(attribute_content, "table")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_TABLE;
3242		else if (!strcmp(attribute_content, "discrete")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_DISCRETE;
3243		else if (!strcmp(attribute_content, "linear")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_LINEAR;
3244		else if (!strcmp(attribute_content, "gamma")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_GAMMA;
3245		else *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_IDENTITY;
3246		break;
3247
3248/* end of keyword type parsing */
3249
3250	/* keyword | numbers (with possibly units) */
3251	case SVG_Length_datatype:
3252	case SVG_Coordinate_datatype:
3253	case SVG_FontSize_datatype:
3254	case SVG_Rotate_datatype:
3255    case SVG_Number_datatype:
3256		svg_parse_length((SVG_Number*)info->far_ptr, attribute_content, 0);
3257		break;
3258
3259	case SMIL_AnimateValue_datatype:
3260		svg_parse_one_anim_value(n, (SMIL_AnimateValue*)info->far_ptr, attribute_content, anim_value_type);
3261		break;
3262	case SMIL_AnimateValues_datatype:
3263		svg_parse_anim_values(n, (SMIL_AnimateValues*)info->far_ptr, attribute_content, anim_value_type);
3264		break;
3265
3266	case XMLRI_datatype:
3267		svg_parse_iri(n, (XMLRI*)info->far_ptr, attribute_content);
3268		break;
3269	case XML_IDREF_datatype:
3270		svg_parse_idref(n, (XMLRI*)info->far_ptr, attribute_content);
3271		break;
3272	case SMIL_AttributeName_datatype:
3273		((SMIL_AttributeName *)info->far_ptr)->name = gf_strdup(attribute_content);
3274		break;
3275	case SMIL_Times_datatype:
3276		smil_parse_time_list(n, *(GF_List **)info->far_ptr, attribute_content);
3277		break;
3278	case SMIL_Duration_datatype:
3279		smil_parse_min_max_dur_repeatdur((SMIL_Duration*)info->far_ptr, attribute_content);
3280		break;
3281	case SMIL_RepeatCount_datatype:
3282		smil_parse_repeatcount((SMIL_RepeatCount*)info->far_ptr, attribute_content);
3283		break;
3284	case SVG_PathData_datatype:
3285		svg_parse_path((SVG_PathData*)info->far_ptr, attribute_content);
3286		break;
3287	case SVG_Points_datatype:
3288		svg_parse_points(*(GF_List **)(info->far_ptr), attribute_content);
3289		break;
3290	case SMIL_KeyTimes_datatype:
3291	case SMIL_KeyPoints_datatype:
3292	case SMIL_KeySplines_datatype:
3293	case SVG_Numbers_datatype:
3294		svg_parse_numbers(*(GF_List **)(info->far_ptr), attribute_content, 0);
3295		break;
3296	case SVG_Coordinates_datatype:
3297		svg_parse_coordinates(*(GF_List **)(info->far_ptr), attribute_content);
3298		break;
3299	case SVG_ViewBox_datatype:
3300		svg_parse_viewbox((SVG_ViewBox*)info->far_ptr, attribute_content);
3301		break;
3302	case SVG_StrokeDashArray_datatype:
3303		svg_parse_strokedasharray((SVG_StrokeDashArray*)info->far_ptr, attribute_content);
3304		break;
3305	case SVG_FontFamily_datatype:
3306		svg_parse_fontfamily((SVG_FontFamily*)info->far_ptr, attribute_content);
3307		break;
3308	case SVG_Motion_datatype:
3309		svg_parse_point_into_matrix((GF_Matrix2D*)info->far_ptr, attribute_content);
3310		break;
3311	case SVG_Transform_datatype:
3312		svg_parse_transform((SVG_Transform*)info->far_ptr, attribute_content);
3313		break;
3314	case SVG_Transform_Translate_datatype:
3315		{
3316			u32 i = 0;
3317			SVG_Point *p = (SVG_Point *)info->far_ptr;;
3318			i+=svg_parse_number(&(attribute_content[i]), &(p->x), 0);
3319			if (attribute_content[i] == 0) {
3320				p->y = 0;
3321			} else {
3322				i+=svg_parse_number(&(attribute_content[i]), &(p->y), 0);
3323			}
3324		}
3325		break;
3326	case SVG_Transform_Scale_datatype:
3327		{
3328			u32 i = 0;
3329			SVG_Point *p = (SVG_Point *)info->far_ptr;;
3330			i+=svg_parse_number(&(attribute_content[i]), &(p->x), 0);
3331			if (attribute_content[i] == 0) {
3332				p->y = p->x;
3333			} else {
3334				i+=svg_parse_number(&(attribute_content[i]), &(p->y), 0);
3335			}
3336		}
3337		break;
3338	case SVG_Transform_SkewX_datatype:
3339	case SVG_Transform_SkewY_datatype:
3340		{
3341			Fixed *p = (Fixed *)info->far_ptr;
3342			svg_parse_number(attribute_content, p, 1);
3343		}
3344		break;
3345	case SVG_Transform_Rotate_datatype:
3346		{
3347			u32 i = 0;
3348			SVG_Point_Angle *p = (SVG_Point_Angle *)info->far_ptr;;
3349			i+=svg_parse_number(&(attribute_content[i]), &(p->angle), 1);
3350			if (attribute_content[i] == 0) {
3351				p->y = p->x = 0;
3352			} else {
3353				i+=svg_parse_number(&(attribute_content[i]), &(p->x), 0);
3354				i+=svg_parse_number(&(attribute_content[i]), &(p->y), 0);
3355			}
3356		}
3357		break;
3358	case SVG_PreserveAspectRatio_datatype:
3359		svg_parse_preserveaspectratio((SVG_PreserveAspectRatio*)info->far_ptr, attribute_content);
3360		break;
3361	case SVG_TransformType_datatype:
3362		svg_parse_animatetransform_type((SVG_TransformType*)info->far_ptr, attribute_content);
3363		break;
3364
3365	case SVG_ID_datatype:
3366	case DOM_String_datatype:
3367	case SVG_ContentType_datatype:
3368	case SVG_LanguageID_datatype:
3369		if (*(SVG_String *)info->far_ptr) gf_free(*(SVG_String *)info->far_ptr);
3370
3371		*(SVG_String *)info->far_ptr = gf_strdup(attribute_content);
3372		break;
3373
3374	case DOM_StringList_datatype:
3375		svg_parse_strings(*(GF_List **)info->far_ptr, attribute_content, 0);
3376		break;
3377	case XMLRI_List_datatype:
3378		svg_parse_strings(*(GF_List **)info->far_ptr, attribute_content, 1);
3379		break;
3380
3381	case XMLEV_Event_datatype:
3382	{
3383		XMLEV_Event *xml_ev = (XMLEV_Event *)info->far_ptr;
3384		char *sep = strchr(attribute_content, '(');
3385		if (sep) {
3386			sep[0] = 0;
3387			xml_ev->type = gf_dom_event_type_by_name(attribute_content);
3388			sep[0] = '(';
3389			if ((xml_ev->type == GF_EVENT_REPEAT) || (xml_ev->type == GF_EVENT_REPEAT_EVENT)) {
3390				char _v;
3391				sscanf(sep, "(%c)", &_v);
3392				xml_ev->parameter = _v;
3393			} else { /* key events ... */
3394				char *sep2 = strchr(attribute_content, ')');
3395				sep2[0] = 0;
3396				xml_ev->parameter = gf_dom_get_key_type(sep+1);
3397				sep2[0] = ')';
3398			}
3399		} else {
3400			xml_ev->parameter = 0;
3401			xml_ev->type = gf_dom_event_type_by_name(attribute_content);
3402		}
3403	}
3404		break;
3405
3406	case SVG_Focus_datatype:
3407		svg_parse_focus(n, (SVG_Focus*)info->far_ptr, attribute_content);
3408		break;
3409	case LASeR_Choice_datatype:
3410		laser_parse_choice((LASeR_Choice*)info->far_ptr, attribute_content);
3411		break;
3412	case LASeR_Size_datatype:
3413		laser_parse_size((LASeR_Size*)info->far_ptr, attribute_content);
3414		break;
3415	case SVG_Clock_datatype:
3416		svg_parse_clock_value(attribute_content, (SVG_Clock*)info->far_ptr);
3417		break;
3418	case SVG_Unknown_datatype:
3419		if (*(SVG_String *)info->far_ptr) gf_free(*(SVG_String *)info->far_ptr);
3420		*(SVG_String *)info->far_ptr = gf_strdup(attribute_content);
3421		break;
3422	default:
3423		GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Parsing] Cannot parse attribute %s\n", info->name, gf_svg_attribute_type_to_string(info->fieldType)));
3424		break;
3425	}
3426	return GF_OK;
3427}
3428
3429void svg_parse_one_style(GF_Node *n, char *one_style)
3430{
3431	GF_FieldInfo info;
3432	char *c, sep;
3433	u32 attributeNameLen;
3434
3435	while (*one_style == ' ') one_style++;
3436	c = strchr(one_style, ':');
3437	if (!c) return;
3438	attributeNameLen = (u32) (c - one_style);
3439	sep = one_style[attributeNameLen];
3440	one_style[attributeNameLen] = 0;
3441	while (strchr("\r\n\t ", one_style[0]))
3442		one_style++;
3443	if (!gf_node_get_field_by_name(n, one_style, &info)) {
3444		c++;
3445		gf_svg_parse_attribute(n, &info, c, 0);
3446	} else {
3447		GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Attribute %s does not belong to element %s.\n", one_style, gf_node_get_class_name(n)));
3448	}
3449	one_style[attributeNameLen] = sep;
3450}
3451
3452void gf_svg_parse_style(GF_Node *n, char *style)
3453{
3454	u32 i = 0;
3455	char *str = style;
3456	s32 psemi = -1;
3457
3458	while (1) {
3459		if (str[i] == ';' || str[i] == 0) {
3460			u32 single_value_len = 0;
3461			single_value_len = i - (psemi+1);
3462			if (single_value_len) {
3463				char c = str[psemi+1 + single_value_len];
3464				str[psemi+1 + single_value_len] = 0;
3465				svg_parse_one_style(n, str + psemi+1);
3466				str[psemi+1 + single_value_len] = c;
3467				psemi = i;
3468			}
3469			if (!str[i]) return;
3470		}
3471		i++;
3472	}
3473
3474}
3475
3476GF_EXPORT
3477void *gf_svg_create_attribute_value(u32 attribute_type)
3478{
3479	switch (attribute_type) {
3480	case SVG_Boolean_datatype:
3481		{
3482			SVG_Boolean *b;
3483			GF_SAFEALLOC(b, SVG_Boolean)
3484			return b;
3485		}
3486		break;
3487	case SVG_Color_datatype:
3488		{
3489			SVG_Color *color;
3490			GF_SAFEALLOC(color, SVG_Color)
3491			return color;
3492		}
3493		break;
3494	case SVG_Paint_datatype:
3495		{
3496			SVG_Paint *paint;
3497			GF_SAFEALLOC(paint, SVG_Paint)
3498			return paint;
3499		}
3500		break;
3501
3502	/* keyword types */
3503	case SVG_FillRule_datatype:
3504	case SVG_StrokeLineJoin_datatype:
3505	case SVG_StrokeLineCap_datatype:
3506	case SVG_FontStyle_datatype:
3507	case SVG_FontWeight_datatype:
3508	case SVG_FontVariant_datatype:
3509	case SVG_TextAnchor_datatype:
3510	case SVG_Display_datatype:
3511	case SVG_Visibility_datatype:
3512	case SVG_Overflow_datatype:
3513	case SVG_ZoomAndPan_datatype:
3514	case SVG_DisplayAlign_datatype:
3515	case SVG_TextAlign_datatype:
3516	case SVG_PointerEvents_datatype:
3517	case SVG_RenderingHint_datatype:
3518	case SVG_VectorEffect_datatype:
3519	case SVG_PlaybackOrder_datatype:
3520	case SVG_TimelineBegin_datatype:
3521	case XML_Space_datatype:
3522	case XMLEV_Propagate_datatype:
3523	case XMLEV_DefaultAction_datatype:
3524	case XMLEV_Phase_datatype:
3525	case SMIL_SyncBehavior_datatype:
3526	case SMIL_AttributeType_datatype:
3527	case SMIL_CalcMode_datatype:
3528	case SMIL_Additive_datatype:
3529	case SMIL_Accumulate_datatype:
3530	case SMIL_Restart_datatype:
3531	case SMIL_Fill_datatype:
3532	case SVG_TransformType_datatype:
3533	case SVG_FocusHighlight_datatype:
3534	case SVG_InitialVisibility_datatype:
3535	case SVG_GradientUnit_datatype:
3536	case SVG_Overlay_datatype:
3537	case SVG_TransformBehavior_datatype:
3538	case SVG_SpreadMethod_datatype:
3539	case SVG_Focusable_datatype:
3540	case SVG_Filter_TransferType_datatype:
3541		{
3542			u8 *keyword;
3543			GF_SAFEALLOC(keyword, u8)
3544			return keyword;
3545		}
3546		break;
3547	case SMIL_SyncTolerance_datatype:
3548		{
3549			SMIL_SyncTolerance *st;
3550			GF_SAFEALLOC(st, SMIL_SyncTolerance)
3551			return st;
3552		}
3553		break;
3554
3555	/* inheritable floats */
3556	case SVG_FontSize_datatype:
3557	case SVG_Length_datatype:
3558	case SVG_Coordinate_datatype:
3559	case SVG_Rotate_datatype:
3560	case SVG_Number_datatype:
3561		{
3562			SVG_Number *number;
3563			GF_SAFEALLOC(number, SVG_Number)
3564			return number;
3565		}
3566		break;
3567
3568	case SVG_StrokeDashArray_datatype:
3569		{
3570			SVG_StrokeDashArray *array;
3571			GF_SAFEALLOC(array, SVG_StrokeDashArray)
3572			return array;
3573		}
3574		break;
3575
3576	case SVG_Motion_datatype:
3577		{
3578			GF_Matrix2D *p;
3579			GF_SAFEALLOC(p, GF_Matrix2D)
3580			gf_mx2d_init(*p);
3581			return p;
3582		}
3583		break;
3584
3585	case SVG_Transform_datatype:
3586		{
3587			SVG_Transform *p;
3588			GF_SAFEALLOC(p, SVG_Transform)
3589			gf_mx2d_init(p->mat);
3590			return p;
3591		}
3592		break;
3593
3594	case SVG_Transform_Translate_datatype:
3595	case SVG_Transform_Scale_datatype:
3596		{
3597			SVG_Point *p;
3598			GF_SAFEALLOC(p, SVG_Point)
3599			return p;
3600		}
3601		break;
3602
3603	case SVG_Transform_SkewX_datatype:
3604	case SVG_Transform_SkewY_datatype:
3605		{
3606			Fixed *p;
3607			GF_SAFEALLOC(p, Fixed)
3608			return p;
3609		}
3610		break;
3611
3612	case SVG_Transform_Rotate_datatype:
3613		{
3614			SVG_Point_Angle *p;
3615			GF_SAFEALLOC(p, SVG_Point_Angle)
3616			return p;
3617		}
3618		break;
3619
3620	case SVG_ViewBox_datatype:
3621		{
3622			SVG_ViewBox *viewbox;
3623			GF_SAFEALLOC(viewbox, SVG_ViewBox)
3624			return viewbox;
3625		}
3626		break;
3627	case XMLRI_datatype:
3628	case XML_IDREF_datatype:
3629		{
3630			XMLRI *iri;
3631			GF_SAFEALLOC(iri, XMLRI)
3632			return iri;
3633		}
3634		break;
3635	case SVG_FontFamily_datatype:
3636		{
3637			SVG_FontFamily *fontfamily;
3638			GF_SAFEALLOC(fontfamily, SVG_FontFamily)
3639			return fontfamily;
3640		}
3641		break;
3642	case DOM_String_datatype:
3643	case SVG_ContentType_datatype:
3644	case SVG_LanguageID_datatype:
3645	case SVG_ID_datatype:
3646		{
3647			SVG_String *string;
3648			GF_SAFEALLOC(string, SVG_String)
3649			return string;
3650		}
3651		break;
3652	case DOM_StringList_datatype:
3653	case XMLRI_List_datatype:
3654	case SVG_Points_datatype:
3655	case SVG_Coordinates_datatype:
3656	case SMIL_Times_datatype:
3657	case SMIL_KeySplines_datatype:
3658	case SMIL_KeyTimes_datatype:
3659	case SMIL_KeyPoints_datatype:
3660	case SVG_Numbers_datatype:
3661		{
3662			ListOfXXX *list;
3663			GF_SAFEALLOC(list, ListOfXXX)
3664			*list = gf_list_new();
3665			return list;
3666		}
3667		break;
3668	case SVG_PreserveAspectRatio_datatype:
3669		{
3670			SVG_PreserveAspectRatio *par;
3671			GF_SAFEALLOC(par, SVG_PreserveAspectRatio)
3672			return par;
3673		}
3674		break;
3675	case SVG_PathData_datatype:
3676		{
3677			SVG_PathData *path;
3678			GF_SAFEALLOC(path, SVG_PathData);
3679#if USE_GF_PATH
3680			gf_path_reset(path);
3681			path->fineness = FIX_ONE;
3682#else
3683			path->commands = gf_list_new();
3684			path->points = gf_list_new();
3685#endif
3686			return path;
3687		}
3688		break;
3689	case LASeR_Choice_datatype:
3690		{
3691			LASeR_Choice *ch;
3692			GF_SAFEALLOC(ch, LASeR_Choice)
3693			return ch;
3694		}
3695	case SVG_Focus_datatype:
3696		{
3697			SVG_Focus *foc;
3698			GF_SAFEALLOC(foc, SVG_Focus)
3699			return foc;
3700		}
3701	case SMIL_AttributeName_datatype:
3702		{
3703			SMIL_AttributeName *an;
3704			GF_SAFEALLOC(an, SMIL_AttributeName)
3705			return an;
3706		}
3707	case SMIL_RepeatCount_datatype:
3708		{
3709			SMIL_RepeatCount *rc;
3710			GF_SAFEALLOC(rc, SMIL_RepeatCount)
3711			return rc;
3712		}
3713	case SMIL_Duration_datatype:
3714		{
3715			SMIL_Duration *sd;
3716			GF_SAFEALLOC(sd, SMIL_Duration)
3717			return sd;
3718		}
3719	case SMIL_AnimateValue_datatype:
3720		{
3721			SMIL_AnimateValue *av;
3722			GF_SAFEALLOC(av, SMIL_AnimateValue)
3723			return av;
3724		}
3725		break;
3726	case SMIL_AnimateValues_datatype:
3727		{
3728			SMIL_AnimateValues *av;
3729			GF_SAFEALLOC(av, SMIL_AnimateValues)
3730			av->values = gf_list_new();
3731			return av;
3732		}
3733		break;
3734	case SVG_Clock_datatype:
3735		{
3736			SVG_Clock *ck;
3737			GF_SAFEALLOC(ck, SVG_Clock)
3738			return ck;
3739		}
3740		break;
3741
3742	case XMLEV_Event_datatype:
3743		{
3744			XMLEV_Event *e;
3745			GF_SAFEALLOC(e, XMLEV_Event);
3746			return e;
3747		}
3748		break;
3749	case LASeR_Size_datatype:
3750		{
3751			LASeR_Size *s;
3752			GF_SAFEALLOC(s, LASeR_Size);
3753			return s;
3754		}
3755		break;
3756
3757	case 0:
3758		{
3759			SVG_String *string;
3760			GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Attributes] Unspecified attribute type - defaulting to string.\n"));
3761			GF_SAFEALLOC(string, SVG_String);
3762			return string;
3763		}
3764
3765
3766	default:
3767		GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Attributes] Cannot create attribute value: Type %s not supported.\n", gf_svg_attribute_type_to_string(attribute_type)));
3768		break;
3769	}
3770	return NULL;
3771}
3772
3773static char *svg_dump_color(SVG_Color *col)
3774{
3775	char *res;
3776	if (col->type == SVG_COLOR_CURRENTCOLOR) return gf_strdup("currentColor");
3777	else if (col->type == SVG_COLOR_INHERIT) return gf_strdup("inherit");
3778	else if (col->type !=SVG_COLOR_RGBCOLOR) {
3779		u32 i, count;
3780		count = sizeof(system_colors) / sizeof(struct sys_col);
3781		for (i=0; i<count; i++) {
3782			if (col->type == system_colors[i].type) {
3783				return gf_strdup(system_colors[i].name);
3784			}
3785		}
3786	} else {
3787		u32 i, count = sizeof(predefined_colors) / sizeof(struct predef_col);
3788		u32 r, g, b;
3789		r = FIX2INT(255*col->red);
3790		g = FIX2INT(255*col->green);
3791		b = FIX2INT(255*col->blue);
3792		for (i=0; i<count; i++) {
3793			if (
3794				(r == predefined_colors[i].r)
3795				&& (g == predefined_colors[i].g)
3796				&& (b == predefined_colors[i].b)
3797			) {
3798				return gf_strdup(predefined_colors[i].name);
3799			}
3800		}
3801		res = gf_malloc(sizeof(char)*8);
3802		sprintf(res, "#%02X%02X%02X", r, g, b);
3803		/*compress it...*/
3804		if ( (res[1]==res[2]) && (res[3]==res[4]) && (res[5]==res[6]) )
3805			sprintf(res, "#%c%c%c", res[1], res[3], res[5]);
3806		return res;
3807	}
3808	return NULL;
3809}
3810
3811static char *svg_dump_number(SVG_Number *l)
3812{
3813	char tmp[100];
3814	if (l->type==SVG_NUMBER_INHERIT) return gf_strdup("inherit");
3815	else if (l->type == SVG_NUMBER_AUTO) return gf_strdup("auto");
3816	else if (l->type == SVG_NUMBER_AUTO_REVERSE) return gf_strdup("auto-reverse");
3817	else {
3818		sprintf(tmp, "%g", FIX2FLT(l->value) );
3819		if (l->type == SVG_NUMBER_PERCENTAGE) strcat(tmp, "%");
3820		else if (l->type == SVG_NUMBER_EMS) strcat(tmp, "em");
3821		else if (l->type == SVG_NUMBER_EXS) strcat(tmp, "ex");
3822		else if (l->type == SVG_NUMBER_PX) strcat(tmp, "px");
3823		else if (l->type == SVG_NUMBER_CM) strcat(tmp, "cm");
3824		else if (l->type == SVG_NUMBER_MM) strcat(tmp, "mm");
3825		else if (l->type == SVG_NUMBER_IN) strcat(tmp, "in");
3826		else if (l->type == SVG_NUMBER_PT) strcat(tmp, "pt");
3827		else if (l->type == SVG_NUMBER_PC) strcat(tmp, "pc");
3828
3829		return gf_strdup(tmp);
3830	}
3831}
3832
3833static char *svg_dump_iri(XMLRI*iri)
3834{
3835	if (iri->type == XMLRI_ELEMENTID) {
3836		const char *name;
3837		char *res;
3838		name = gf_node_get_name((GF_Node *)iri->target);
3839
3840		if (name) {
3841			res = gf_malloc(sizeof(char)*(strlen(name)+2));
3842			sprintf(res, "#%s", name);
3843		} else if (iri->target) {
3844			res = gf_malloc(sizeof(char)*32);
3845			sprintf(res, "#N%d", gf_node_get_id((GF_Node *)iri->target) - 1);
3846		} else {
3847			res = gf_strdup("");
3848		}
3849		return res;
3850	}
3851	else if ((iri->type == XMLRI_STRING) && iri->string)
3852		return gf_strdup(iri->string);
3853	else
3854		return gf_strdup("");
3855}
3856
3857static char *svg_dump_idref(XMLRI*iri)
3858{
3859	const char *name;
3860	if (iri->target) {
3861		name = gf_node_get_name((GF_Node *)iri->target);
3862		if (name) return gf_strdup(name);
3863		else {
3864			char tmp[50];
3865			sprintf(tmp, "N%d", gf_node_get_id((GF_Node *)iri->target) - 1);
3866			return gf_strdup(tmp);
3867		}
3868	}
3869	if (iri->string) return gf_strdup(iri->string);
3870	return gf_strdup("");
3871}
3872
3873#if USE_GF_PATH
3874static char *svg_dump_path(SVG_PathData *path)
3875{
3876	char szT[1000];
3877	GF_Point2D *pt, last_pt, *ct1, *ct2, *end;
3878	u32 i, *contour;
3879	char *res = gf_malloc(sizeof(char));
3880	res[0] = 0;
3881
3882	contour = path->contours;
3883	last_pt.x = last_pt.y = 0;
3884
3885	for (i=0; i<path->n_points; ) {
3886		szT[0] = 0;
3887
3888		switch (path->tags[i]) {
3889		case GF_PATH_CURVE_ON:
3890		case GF_PATH_CLOSE:
3891			pt = &path->points[i];
3892			if (!i || (*contour == i-1) ) {
3893				sprintf(szT, "M%g %g", FIX2FLT(pt->x), FIX2FLT(pt->y));
3894				if (i) contour++;
3895			} else if (path->tags[i]==GF_PATH_CLOSE) {
3896				sprintf(szT, "z");
3897			} else {
3898				if (i && (last_pt.x==pt->x)) sprintf(szT, "V%g", FIX2FLT(pt->y));
3899				else if (i && (last_pt.y==pt->y)) sprintf(szT, "H%g", FIX2FLT(pt->x));
3900				else sprintf(szT, "L%g %g", FIX2FLT(pt->x), FIX2FLT(pt->y));
3901			}
3902			last_pt = *pt;
3903			i++;
3904			break;
3905		case GF_PATH_CURVE_CONIC:
3906			ct1 = &path->points[i];
3907			end = &path->points[i+1];
3908			sprintf(szT, "Q%g %g %g %g", FIX2FLT(ct1->x), FIX2FLT(ct1->y), FIX2FLT(end->x), FIX2FLT(end->y));
3909
3910			last_pt = *end;
3911			if (path->tags[i+2]==GF_PATH_CLOSE)  {
3912				strcat(szT, "z");
3913			}
3914			i+=2;
3915			break;
3916		case GF_PATH_CURVE_CUBIC:
3917			ct1 = &path->points[i];
3918			ct2 = &path->points[i+1];
3919			end = &path->points[i+2];
3920			sprintf(szT, "C%g %g %g %g %g %g", FIX2FLT(ct1->x), FIX2FLT(ct1->y), FIX2FLT(ct2->x), FIX2FLT(ct2->y), FIX2FLT(end->x), FIX2FLT(end->y));
3921			last_pt = *end;
3922			if (path->tags[i+2]==GF_PATH_CLOSE) {
3923				strcat(szT, "z");
3924			}
3925			i+=3;
3926			break;
3927		}
3928		if (szT[0]) {
3929			res = gf_realloc(res, sizeof(char)*(strlen(szT)+strlen(res)+1));
3930			strcat(res, szT);
3931		}
3932	}
3933	return res;
3934}
3935#else
3936static void svg_dump_point(SVG_Point *pt, char *attValue)
3937{
3938	if (pt) sprintf(attValue, "%g %g ", FIX2FLT(pt->x), FIX2FLT(pt->y) );
3939}
3940static void svg_dump_path(SVG_PathData *path, char *attValue)
3941{
3942	char szT[1000];
3943	u32 i, pt_i, count;
3944	count = gf_list_count(path->commands);
3945	pt_i = 0;
3946	strcpy(attValue, "");
3947	for (i = 0; i < count; i++) {
3948		u8 command = *(u8 *)gf_list_get(path->commands, i);
3949		switch(command) {
3950		case SVG_PATHCOMMAND_M:
3951			strcat(attValue, "M");
3952			svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
3953			strcat(attValue, szT);
3954			pt_i++;
3955			break;
3956		case SVG_PATHCOMMAND_L:
3957			strcat(attValue, "L");
3958			svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
3959			strcat(attValue, szT);
3960			pt_i++;
3961			break;
3962		case SVG_PATHCOMMAND_C:
3963			strcat(attValue, "C");
3964			svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
3965			strcat(attValue, szT);
3966			pt_i++;
3967			svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
3968			strcat(attValue, szT);
3969			pt_i++;
3970			svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
3971			strcat(attValue, szT);
3972			pt_i++;
3973			break;
3974		case SVG_PATHCOMMAND_S:
3975			strcat(attValue, "S");
3976			svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
3977			strcat(attValue, szT);
3978			pt_i++;
3979			svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
3980			strcat(attValue, szT);
3981			pt_i++;
3982			break;
3983		case SVG_PATHCOMMAND_Q:
3984			strcat(attValue, "Q");
3985			svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
3986			strcat(attValue, szT);
3987			pt_i++;
3988			svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
3989			strcat(attValue, szT);
3990			pt_i++;
3991			break;
3992		case SVG_PATHCOMMAND_T:
3993			strcat(attValue, "T");
3994			svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
3995			strcat(attValue, szT);
3996			pt_i++;
3997			break;
3998		case SVG_PATHCOMMAND_A:
3999			strcat(attValue, "A");
4000			svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
4001			strcat(attValue, szT);
4002			pt_i++;
4003			strcat(attValue, "0 0 0 ");
4004			svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
4005			strcat(attValue, szT);
4006			pt_i++;
4007			break;
4008		case SVG_PATHCOMMAND_Z:
4009			strcat(attValue, "Z");
4010			break;
4011		default:
4012			GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Dumping] unknown path command %d\n", command));
4013			break;
4014		}
4015	}
4016}
4017#endif
4018
4019static void svg_dump_access_key(XMLEV_Event *evt, char *attValue)
4020{
4021	u32 i, count;
4022	strcpy(attValue, "accessKey(");
4023	count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid);
4024	for (i=0; i<count; i++) {
4025		if (evt->parameter == predefined_key_identifiers[i].key_code) {
4026			strcat(attValue, predefined_key_identifiers[i].name);
4027			break;
4028		}
4029	}
4030	/* OLD LASeR CODE
4031	switch (evt->parameter) {
4032	case 0: strcat(attValue, "UP"); break;
4033	case 1: strcat(attValue, "DOWN"); break;
4034	case 2: strcat(attValue, "LEFT"); break;
4035	case 3: strcat(attValue, "RIGHT"); break;
4036	case 4: strcat(attValue, "FIRE"); break;
4037	case 5: strcat(attValue, "NO_KEY"); break;
4038	case 6: strcat(attValue, "ANY_KEY"); break;
4039	case 7: strcat(attValue, "SOFT_KEY_1"); break;
4040	case 8: strcat(attValue, "SOFT_KEY_2"); break;
4041	case 35: strcat(attValue, "#"); break;
4042	case 42: strcat(attValue, "*"); break;
4043	case 48: strcat(attValue, "0"); break;
4044	case 49: strcat(attValue, "1"); break;
4045	case 50: strcat(attValue, "2"); break;
4046	case 51: strcat(attValue, "3"); break;
4047	case 52: strcat(attValue, "4"); break;
4048	case 53: strcat(attValue, "5"); break;
4049	case 54: strcat(attValue, "6"); break;
4050	case 55: strcat(attValue, "7"); break;
4051	case 56: strcat(attValue, "8"); break;
4052	case 57: strcat(attValue, "9"); break;
4053	*/
4054	strcat(attValue, ")");
4055}
4056
4057static char *gf_svg_dump_matrix(GF_Matrix2D *matrix)
4058{
4059	char attValue[1024];
4060	attValue[0]=0;
4061	/*try to do a simple decomposition...*/
4062	if (!matrix->m[1] && !matrix->m[3]) {
4063		if (matrix->m[2] != 0 || matrix->m[5] != 0) sprintf(attValue, "translate(%g,%g)", FIX2FLT(matrix->m[2]), FIX2FLT(matrix->m[5]) );
4064		if ((matrix->m[0]!=FIX_ONE) || (matrix->m[4]!=FIX_ONE)) {
4065			char szT[1024];
4066			if ((matrix->m[0]==-FIX_ONE) && (matrix->m[4]==-FIX_ONE)) {
4067				strcpy(szT, " rotate(180)");
4068			} else {
4069				sprintf(szT, " scale(%g,%g)", FIX2FLT(matrix->m[0]), FIX2FLT(matrix->m[4]) );
4070			}
4071			strcat(attValue, szT);
4072		}
4073	} else if (matrix->m[1] == - matrix->m[3]) {
4074		Fixed angle = gf_asin(matrix->m[3]);
4075		Fixed cos_a = gf_cos(angle);
4076		if (ABS(cos_a)>FIX_EPSILON) {
4077			Fixed sx, sy;
4078			sx = gf_divfix(matrix->m[0], cos_a);
4079			sy = gf_divfix(matrix->m[4], cos_a);
4080			angle = gf_divfix(180*angle, GF_PI);
4081			if ((sx==sy) && ( ABS(FIX_ONE - ABS(sx) ) < FIX_ONE/100)) {
4082				if (matrix->m[2] != 0 || matrix->m[5] != 0)
4083					sprintf(attValue, "translate(%g,%g) rotate(%g)", FIX2FLT(matrix->m[2]), FIX2FLT(matrix->m[5]), FIX2FLT(gf_divfix(angle*180, GF_PI) ) );
4084				else
4085					sprintf(attValue, "rotate(%g)", FIX2FLT(gf_divfix(angle*180, GF_PI) ) );
4086			} else {
4087				if (matrix->m[2] != 0 || matrix->m[5] != 0)
4088					sprintf(attValue, "translate(%g,%g) scale(%g,%g) rotate(%g)", FIX2FLT(matrix->m[2]), FIX2FLT(matrix->m[5]), FIX2FLT(sx), FIX2FLT(sy), FIX2FLT(gf_divfix(angle*180, GF_PI) ) );
4089				else
4090					sprintf(attValue, "scale(%g,%g) rotate(%g)", FIX2FLT(sx), FIX2FLT(sy), FIX2FLT(gf_divfix(angle*180, GF_PI) ) );
4091			}
4092		} else {
4093			Fixed a = angle;
4094			if (a<0) a += GF_2PI;
4095			if (matrix->m[2] != 0 || matrix->m[5] != 0)
4096				sprintf(attValue, "translate(%g,%g) rotate(%g)", FIX2FLT(matrix->m[2]), FIX2FLT(matrix->m[5]), FIX2FLT(gf_divfix(a*180, GF_PI) ) );
4097			else
4098				sprintf(attValue, "rotate(%g)", FIX2FLT(gf_divfix(a*180, GF_PI) ) );
4099		}
4100	}
4101	/*default*/
4102	if (!strlen(attValue))
4103		sprintf(attValue, "matrix(%g %g %g %g %g %g)", FIX2FLT(matrix->m[0]), FIX2FLT(matrix->m[3]), FIX2FLT(matrix->m[1]), FIX2FLT(matrix->m[4]), FIX2FLT(matrix->m[2]), FIX2FLT(matrix->m[5]) );
4104
4105	return gf_strdup(attValue);
4106}
4107
4108char *gf_svg_dump_attribute(GF_Node *elt, GF_FieldInfo *info)
4109{
4110	char tmp[1024];
4111	u8 intVal;
4112
4113	if (!info->far_ptr) return gf_strdup("");
4114	intVal = *(u8 *)info->far_ptr;
4115
4116	switch (info->fieldType) {
4117	case SVG_Boolean_datatype:
4118		return gf_strdup( *(SVG_Boolean *)info->far_ptr ? "true" : "false");
4119
4120	case SVG_Color_datatype:
4121		return svg_dump_color((SVG_Color *)info->far_ptr);
4122
4123	case SVG_Paint_datatype:
4124	{
4125		SVG_Paint *paint = (SVG_Paint *)info->far_ptr;
4126		if (paint->type == SVG_PAINT_NONE) return gf_strdup("none");
4127		else if (paint->type == SVG_PAINT_INHERIT) return gf_strdup("inherit");
4128		else if (paint->type == SVG_PAINT_URI) {
4129			char *tmp = svg_dump_iri(&paint->iri);
4130			char *res = gf_malloc(sizeof(char)*(strlen(tmp)+6));
4131			sprintf(res, "url(%s)", tmp);
4132			gf_free(tmp);
4133			return res;
4134		} else {
4135			return svg_dump_color(&paint->color);
4136		}
4137	}
4138		break;
4139
4140/* beginning of keyword type parsing */
4141	case SVG_FillRule_datatype:
4142		if (intVal == SVG_FILLRULE_INHERIT) return gf_strdup("inherit");
4143		else if (intVal == SVG_FILLRULE_NONZERO) return gf_strdup("nonzero");
4144		else return gf_strdup("evenodd");
4145		break;
4146
4147	case SVG_StrokeLineJoin_datatype:
4148		if (intVal==SVG_STROKELINEJOIN_INHERIT) return gf_strdup("inherit");
4149		else if (intVal==SVG_STROKELINEJOIN_MITER) return gf_strdup("miter");
4150		else if (intVal==SVG_STROKELINEJOIN_ROUND) return gf_strdup("round");
4151		else if (intVal==SVG_STROKELINEJOIN_BEVEL) return gf_strdup("bevel");
4152		break;
4153	case SVG_StrokeLineCap_datatype:
4154		if (intVal==SVG_STROKELINECAP_INHERIT) return gf_strdup("inherit");
4155		else if (intVal==SVG_STROKELINECAP_BUTT) return gf_strdup("butt");
4156		else if (intVal==SVG_STROKELINECAP_ROUND) return gf_strdup("round");
4157		else if (intVal==SVG_STROKELINECAP_SQUARE) return gf_strdup("square");
4158		break;
4159	case SVG_FontStyle_datatype:
4160		if (intVal==SVG_FONTSTYLE_INHERIT) return gf_strdup("inherit");
4161		else if (intVal==SVG_FONTSTYLE_NORMAL) return gf_strdup("normal");
4162		else if (intVal==SVG_FONTSTYLE_ITALIC) return gf_strdup("italic");
4163		else if (intVal==SVG_FONTSTYLE_OBLIQUE) return gf_strdup("oblique");
4164		break;
4165	case SVG_FontWeight_datatype:
4166		if (intVal==SVG_FONTWEIGHT_INHERIT) return gf_strdup("inherit");
4167		else if (intVal==SVG_FONTWEIGHT_NORMAL) return gf_strdup("normal");
4168		else if (intVal==SVG_FONTWEIGHT_BOLD) return gf_strdup("bold");
4169		else if (intVal==SVG_FONTWEIGHT_BOLDER) return gf_strdup("bolder");
4170		else if (intVal==SVG_FONTWEIGHT_LIGHTER) return gf_strdup("lighter");
4171		else if (intVal==SVG_FONTWEIGHT_100) return gf_strdup("100");
4172		else if (intVal==SVG_FONTWEIGHT_200) return gf_strdup("200");
4173		else if (intVal==SVG_FONTWEIGHT_300) return gf_strdup("300");
4174		else if (intVal==SVG_FONTWEIGHT_400) return gf_strdup("400");
4175		else if (intVal==SVG_FONTWEIGHT_500) return gf_strdup("500");
4176		else if (intVal==SVG_FONTWEIGHT_600) return gf_strdup("600");
4177		else if (intVal==SVG_FONTWEIGHT_700) return gf_strdup("700");
4178		else if (intVal==SVG_FONTWEIGHT_800) return gf_strdup("800");
4179		else if (intVal==SVG_FONTWEIGHT_900) return gf_strdup("900");
4180		break;
4181	case SVG_FontVariant_datatype:
4182		if (intVal==SVG_FONTVARIANT_INHERIT) return gf_strdup("inherit");
4183		else if (intVal==SVG_FONTVARIANT_NORMAL) return gf_strdup("normal");
4184		else if (intVal==SVG_FONTVARIANT_SMALLCAPS) return gf_strdup("small-caps");
4185		break;
4186	case SVG_TextAnchor_datatype:
4187		if (intVal==SVG_TEXTANCHOR_INHERIT) return gf_strdup("inherit");
4188		else if (intVal==SVG_TEXTANCHOR_START) return gf_strdup("start");
4189		else if (intVal==SVG_TEXTANCHOR_MIDDLE) return gf_strdup("middle");
4190		else if (intVal==SVG_TEXTANCHOR_END) return gf_strdup("end");
4191		break;
4192	case SVG_Display_datatype:
4193		if (intVal==SVG_DISPLAY_INHERIT) return gf_strdup("inherit");
4194		else if (intVal==SVG_DISPLAY_NONE) return gf_strdup("none");
4195		else if (intVal==SVG_DISPLAY_INLINE) return gf_strdup("inline");
4196		else if (intVal==SVG_DISPLAY_BLOCK) return gf_strdup("block");
4197		else if (intVal==SVG_DISPLAY_LIST_ITEM) return gf_strdup("list-item");
4198		else if (intVal==SVG_DISPLAY_RUN_IN) return gf_strdup("run-in");
4199		else if (intVal==SVG_DISPLAY_COMPACT) return gf_strdup("compact");
4200		else if (intVal==SVG_DISPLAY_MARKER) return gf_strdup("marker");
4201		else if (intVal==SVG_DISPLAY_TABLE) return gf_strdup("table");
4202		else if (intVal==SVG_DISPLAY_INLINE_TABLE) return gf_strdup("inline-table");
4203		else if (intVal==SVG_DISPLAY_TABLE_ROW_GROUP) return gf_strdup("table-row-group");
4204		else if (intVal==SVG_DISPLAY_TABLE_HEADER_GROUP) return gf_strdup("table-header-group");
4205		else if (intVal==SVG_DISPLAY_TABLE_FOOTER_GROUP) return gf_strdup("table-footer-group");
4206		else if (intVal==SVG_DISPLAY_TABLE_ROW) return gf_strdup("table-row");
4207		else if (intVal==SVG_DISPLAY_TABLE_COLUMN_GROUP) return gf_strdup("table-column-group");
4208		else if (intVal==SVG_DISPLAY_TABLE_COLUMN) return gf_strdup("table-column");
4209		else if (intVal==SVG_DISPLAY_TABLE_CELL) return gf_strdup("table-cell");
4210		else if (intVal==SVG_DISPLAY_TABLE_CAPTION) return gf_strdup("table-caption");
4211		break;
4212	case SVG_Visibility_datatype:
4213		if (intVal==SVG_VISIBILITY_INHERIT) return gf_strdup("inherit");
4214		else if (intVal==SVG_VISIBILITY_VISIBLE) return gf_strdup("visible");
4215		else if (intVal==SVG_VISIBILITY_HIDDEN) return gf_strdup("hidden");
4216		else if (intVal==SVG_VISIBILITY_COLLAPSE) return gf_strdup("collapse");
4217		break;
4218	case SVG_Overflow_datatype:
4219		if (intVal==SVG_OVERFLOW_INHERIT) return gf_strdup("inherit");
4220		else if (intVal==SVG_OVERFLOW_VISIBLE) return gf_strdup("visible");
4221		else if (intVal==SVG_OVERFLOW_HIDDEN) return gf_strdup("hidden");
4222		else if (intVal==SVG_OVERFLOW_SCROLL) return gf_strdup("scroll");
4223		else if (intVal==SVG_OVERFLOW_AUTO) return gf_strdup("auto");
4224		break;
4225	case SVG_ZoomAndPan_datatype:
4226		if (intVal==SVG_ZOOMANDPAN_DISABLE) return gf_strdup("disable");
4227		else return gf_strdup("magnify");
4228		break;
4229	case SVG_DisplayAlign_datatype:
4230		if (intVal==SVG_DISPLAYALIGN_INHERIT) return gf_strdup("inherit");
4231		else if (intVal==SVG_DISPLAYALIGN_AUTO) return gf_strdup("auto");
4232		else if (intVal==SVG_DISPLAYALIGN_BEFORE) return gf_strdup("before");
4233		else if (intVal==SVG_DISPLAYALIGN_CENTER) return gf_strdup("center");
4234		else if (intVal==SVG_DISPLAYALIGN_AFTER) return gf_strdup("after");
4235		break;
4236	case SVG_TextAlign_datatype:
4237		if (intVal==SVG_TEXTALIGN_INHERIT) return gf_strdup("inherit");
4238		else if (intVal==SVG_TEXTALIGN_START) return gf_strdup("start");
4239		else if (intVal==SVG_TEXTALIGN_CENTER) return gf_strdup("center");
4240		else if (intVal==SVG_TEXTALIGN_END) return gf_strdup("end");
4241		break;
4242	case SVG_PointerEvents_datatype:
4243		if (intVal==SVG_POINTEREVENTS_INHERIT) return gf_strdup("inherit");
4244		else if (intVal==SVG_POINTEREVENTS_VISIBLEPAINTED) return gf_strdup("visiblePainted");
4245		else if (intVal==SVG_POINTEREVENTS_VISIBLEFILL) return gf_strdup("visibleFill");
4246		else if (intVal==SVG_POINTEREVENTS_VISIBLESTROKE) return gf_strdup("visibleStroke");
4247		else if (intVal==SVG_POINTEREVENTS_VISIBLE) return gf_strdup("visible");
4248		else if (intVal==SVG_POINTEREVENTS_PAINTED) return gf_strdup("painted");
4249		else if (intVal==SVG_POINTEREVENTS_FILL) return gf_strdup("fill");
4250		else if (intVal==SVG_POINTEREVENTS_STROKE) return gf_strdup("stroke");
4251		else if (intVal==SVG_POINTEREVENTS_ALL) return gf_strdup("all");
4252		else if (intVal==SVG_POINTEREVENTS_NONE) return gf_strdup("none");
4253		else if (intVal==SVG_POINTEREVENTS_BOUNDINGBOX) return gf_strdup("boundingBox");
4254		break;
4255	case SVG_RenderingHint_datatype:
4256		if (intVal==SVG_RENDERINGHINT_INHERIT) return gf_strdup("inherit");
4257		else if (intVal==SVG_RENDERINGHINT_AUTO) return gf_strdup("auto");
4258		else if (intVal==SVG_RENDERINGHINT_OPTIMIZEQUALITY) return gf_strdup("optimizeQuality");
4259		else if (intVal==SVG_RENDERINGHINT_OPTIMIZESPEED) return gf_strdup("optimizeSpeed");
4260		else if (intVal==SVG_RENDERINGHINT_OPTIMIZELEGIBILITY) return gf_strdup("optimizeLegibility");
4261		else if (intVal==SVG_RENDERINGHINT_CRISPEDGES) return gf_strdup("crispEdges");
4262		else if (intVal==SVG_RENDERINGHINT_GEOMETRICPRECISION) return gf_strdup("geometricPrecision");
4263		break;
4264	case SVG_VectorEffect_datatype:
4265		if (intVal==SVG_VECTOREFFECT_INHERIT) return gf_strdup("inherit");
4266		else if (intVal==SVG_VECTOREFFECT_NONE) return gf_strdup("none");
4267		else if (intVal==SVG_VECTOREFFECT_NONSCALINGSTROKE) return gf_strdup("non-scaling-stroke");
4268		break;
4269	case SVG_PlaybackOrder_datatype:
4270		if (intVal== SVG_PLAYBACKORDER_FORWARDONLY) return gf_strdup("forwardOnly");
4271		else if (intVal== SVG_PLAYBACKORDER_ALL) return gf_strdup("all");
4272		break;
4273	case SVG_TimelineBegin_datatype:
4274		if (intVal== SVG_TIMELINEBEGIN_ONSTART) return gf_strdup("onStart");
4275		else if (intVal== SVG_TIMELINEBEGIN_ONLOAD) return gf_strdup("onLoad");
4276		break;
4277	case XML_Space_datatype:
4278		if (intVal==XML_SPACE_DEFAULT) return gf_strdup("default");
4279		else if (intVal==XML_SPACE_PRESERVE) return gf_strdup("preserve");
4280		break;
4281	case XMLEV_Propagate_datatype:
4282		if (intVal==XMLEVENT_PROPAGATE_CONTINUE) return gf_strdup("continue");
4283		else if (intVal==XMLEVENT_PROPAGATE_STOP) return gf_strdup("stop");
4284		break;
4285	case XMLEV_DefaultAction_datatype:
4286		if (intVal==XMLEVENT_DEFAULTACTION_CANCEL) return gf_strdup("cancel");
4287		else if (intVal==XMLEVENT_DEFAULTACTION_PERFORM) return gf_strdup("perform");
4288		break;
4289	case XMLEV_Phase_datatype:
4290		if (intVal==XMLEVENT_PHASE_DEFAULT) return gf_strdup("default");
4291		else if (intVal==XMLEVENT_PHASE_CAPTURE) return gf_strdup("capture");
4292		break;
4293	case SMIL_SyncBehavior_datatype:
4294		if (intVal==SMIL_SYNCBEHAVIOR_INHERIT) return gf_strdup("inherit");
4295		else if (intVal==SMIL_SYNCBEHAVIOR_DEFAULT) return gf_strdup("default");
4296		else if (intVal==SMIL_SYNCBEHAVIOR_LOCKED) return gf_strdup("locked");
4297		else if (intVal==SMIL_SYNCBEHAVIOR_CANSLIP) return gf_strdup("canSlip");
4298		else if (intVal==SMIL_SYNCBEHAVIOR_INDEPENDENT) return gf_strdup("independent");
4299		break;
4300	case SMIL_SyncTolerance_datatype:
4301		if (((SMIL_SyncTolerance*)info->far_ptr)->type==SMIL_SYNCTOLERANCE_INHERIT) return gf_strdup("inherit");
4302		else if (((SMIL_SyncTolerance*)info->far_ptr)->type==SMIL_SYNCTOLERANCE_DEFAULT) return gf_strdup("default");
4303		else if (((SMIL_SyncTolerance*)info->far_ptr)->type==SMIL_SYNCBEHAVIOR_LOCKED) {
4304			sprintf(tmp, "%g", ((SMIL_SyncTolerance*)info->far_ptr)->value);
4305			return gf_strdup(tmp);
4306		}
4307		break;
4308	case SMIL_AttributeType_datatype:
4309		if (intVal==SMIL_ATTRIBUTETYPE_AUTO) return gf_strdup("auto");
4310		else if (intVal==SMIL_ATTRIBUTETYPE_XML) return gf_strdup("XML");
4311		else if (intVal==SMIL_ATTRIBUTETYPE_CSS) return gf_strdup("CSS");
4312		break;
4313	case SMIL_CalcMode_datatype:
4314		if (intVal==SMIL_CALCMODE_DISCRETE) return gf_strdup("discrete");
4315		else if (intVal==SMIL_CALCMODE_LINEAR) return gf_strdup("linear");
4316		else if (intVal==SMIL_CALCMODE_PACED) return gf_strdup("paced");
4317		else if (intVal==SMIL_CALCMODE_SPLINE) return gf_strdup("spline");
4318		break;
4319	case SMIL_Additive_datatype:
4320		if (intVal==SMIL_ADDITIVE_REPLACE) return gf_strdup("replace");
4321		else if (intVal==SMIL_ADDITIVE_SUM) return gf_strdup("sum");
4322		break;
4323	case SMIL_Accumulate_datatype:
4324		if (intVal==SMIL_ACCUMULATE_NONE) return gf_strdup("none");
4325		else if (intVal==SMIL_ACCUMULATE_SUM) return gf_strdup("sum");
4326		break;
4327	case SMIL_Restart_datatype:
4328		if (intVal==SMIL_RESTART_ALWAYS) return gf_strdup("always");
4329		else if (intVal==SMIL_RESTART_WHENNOTACTIVE) return gf_strdup("whenNotActive");
4330		else if (intVal==SMIL_RESTART_NEVER) return gf_strdup("never");
4331		break;
4332	case SMIL_Fill_datatype:
4333		if (intVal==SMIL_FILL_FREEZE) return gf_strdup("freeze");
4334		else if (intVal==SMIL_FILL_REMOVE) return gf_strdup("remove");
4335		break;
4336
4337	case SVG_GradientUnit_datatype:
4338		if (intVal==SVG_GRADIENTUNITS_USER) return gf_strdup("userSpaceOnUse");
4339		else if (intVal==SVG_GRADIENTUNITS_OBJECT) return gf_strdup("objectBoundingBox");
4340		break;
4341	case SVG_InitialVisibility_datatype:
4342		if (intVal==SVG_INITIALVISIBILTY_WHENSTARTED) return gf_strdup("whenStarted");
4343		else if (intVal==SVG_INITIALVISIBILTY_ALWAYS) return gf_strdup("always");
4344		break;
4345	case SVG_FocusHighlight_datatype:
4346		if (intVal==SVG_FOCUSHIGHLIGHT_AUTO) return gf_strdup("auto");
4347		else if (intVal==SVG_FOCUSHIGHLIGHT_NONE) return gf_strdup("none");
4348		break;
4349	case SVG_Overlay_datatype:
4350		if (intVal==SVG_OVERLAY_NONE) return gf_strdup("none");
4351		else if (intVal==SVG_OVERLAY_TOP) return gf_strdup("top");
4352		break;
4353	case SVG_TransformBehavior_datatype:
4354		if (intVal==SVG_TRANSFORMBEHAVIOR_GEOMETRIC) return gf_strdup("geometric");
4355		else if (intVal==SVG_TRANSFORMBEHAVIOR_PINNED) return gf_strdup("pinned");
4356		else if (intVal==SVG_TRANSFORMBEHAVIOR_PINNED90) return gf_strdup("pinned90");
4357		else if (intVal==SVG_TRANSFORMBEHAVIOR_PINNED180) return gf_strdup("pinned180");
4358		else if (intVal==SVG_TRANSFORMBEHAVIOR_PINNED270) return gf_strdup("pinned270");
4359		break;
4360	case SVG_SpreadMethod_datatype:
4361		if (intVal