PageRenderTime 417ms CodeModel.GetById 202ms app.highlight 159ms RepoModel.GetById 12ms app.codeStats 3ms

/src/scenegraph/svg_attributes.c

https://github.com/svettom/gpac-1
C | 6443 lines | 5960 code | 325 blank | 158 comment | 1469 complexity | a2132d966357a269fa240b28914370a7 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 *					GPAC Multimedia Framework
   3 *
   4 *			Authors: Cyril Concolato - Jean le Feuvre - Jean-Claude Moissinac
   5 *				Copyright (c) 2005-200X ENST
   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 <gpac/base_coding.h>
  27#include <gpac/events.h>
  28#include <gpac/nodes_svg.h>
  29
  30#ifndef GPAC_DISABLE_SVG
  31
  32#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	/*GPAC internals*/
 165	{ GF_EVENT_SCENE_ATTACHED, "gpac_scene_attached", GF_DOM_EVENT_DOM },
 166	{ GF_EVENT_VP_RESIZE, "gpac_vp_changed", GF_DOM_EVENT_DOM },
 167};
 168
 169GF_EXPORT
 170u32 gf_dom_event_type_by_name(const char *name)
 171{
 172	u32 i, count;
 173	count = sizeof(defined_dom_events) / sizeof(struct dom_event_def);
 174	if (!name) return GF_EVENT_UNKNOWN;
 175	if ((name[0]=='o') && (name[1]=='n')) name += 2;
 176	for (i=0;i<count;i++) {
 177		if (!strcmp(name, defined_dom_events[i].name))
 178			return defined_dom_events[i].event;
 179	}
 180	return GF_EVENT_UNKNOWN;
 181}
 182
 183const char *gf_dom_event_get_name(u32 type)
 184{
 185	u32 i, count;
 186	count = sizeof(defined_dom_events) / sizeof(struct dom_event_def);
 187	for (i=0;i<count;i++) {
 188		if (defined_dom_events[i].event == type)
 189			return defined_dom_events[i].name;
 190	}
 191	return "unknown";
 192}
 193
 194u32 gf_dom_event_get_category(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].category;
 201	}
 202	return 0;
 203}
 204
 205
 206static const struct predef_keyid {u32 key_code;  const char *name; } predefined_key_identifiers[] =
 207{
 208	{ GF_KEY_ACCEPT, "Accept" },
 209	{ GF_KEY_AGAIN, "Again" },
 210	{ GF_KEY_ALLCANDIDATES, "AllCandidates" },
 211	{ GF_KEY_ALPHANUM, "Alphanumeric" },
 212	{ GF_KEY_ALT, "Alt" },
 213	{ GF_KEY_ALTGRAPH, "AltGraph" },
 214	{ GF_KEY_APPS, "Apps" },
 215	{ GF_KEY_ATTN, "Attn" },
 216	{ GF_KEY_BROWSERBACK, "BrowserBack" },
 217	{ GF_KEY_BROWSERFAVORITES, "BrowserFavorites" },
 218	{ GF_KEY_BROWSERFORWARD, "BrowserForward" },
 219	{ GF_KEY_BROWSERHOME, "BrowserHome" },
 220	{ GF_KEY_BROWSERREFRESH, "BrowserRefresh" },
 221	{ GF_KEY_BROWSERSEARCH, "BrowserSearch" },
 222	{ GF_KEY_BROWSERSTOP, "BrowserStop" },
 223	{ GF_KEY_CAPSLOCK, "CapsLock" },
 224	{ GF_KEY_CLEAR, "Clear" },
 225	{ GF_KEY_CODEINPUT, "CodeInput" },
 226	{ GF_KEY_COMPOSE, "Compose" },
 227	{ GF_KEY_CONTROL, "Control" },
 228	{ GF_KEY_CRSEL, "Crsel" },
 229	{ GF_KEY_CONVERT, "Convert" },
 230	{ GF_KEY_COPY, "Copy"  },
 231	{ GF_KEY_CUT, "Cut" },
 232	{ GF_KEY_DOWN, "Down" },
 233	{ GF_KEY_END, "End" },
 234	{ GF_KEY_ENTER, "Enter" },
 235	{ GF_KEY_ERASEEOF, "EraseEof" },
 236	{ GF_KEY_EXECUTE, "Execute" },
 237	{ GF_KEY_EXSEL, "Exsel" },
 238	{ GF_KEY_F1, "F1" },
 239	{ GF_KEY_F2, "F2" },
 240	{ GF_KEY_F3, "F3" },
 241	{ GF_KEY_F4, "F4" },
 242	{ GF_KEY_F5, "F5" },
 243	{ GF_KEY_F6, "F6" },
 244	{ GF_KEY_F7, "F7" },
 245	{ GF_KEY_F8, "F8" },
 246	{ GF_KEY_F9, "F9" },
 247	{ GF_KEY_F10, "F10" },
 248	{ GF_KEY_F11, "F11" },
 249	{ GF_KEY_F12, "F12" },
 250	{ GF_KEY_F13, "F13" },
 251	{ GF_KEY_F14, "F14" },
 252	{ GF_KEY_F15, "F15" },
 253	{ GF_KEY_F16, "F16" },
 254	{ GF_KEY_F17, "F17" },
 255	{ GF_KEY_F18, "F18" },
 256	{ GF_KEY_F19, "F19" },
 257	{ GF_KEY_F20, "F20" },
 258	{ GF_KEY_F21, "F21" },
 259	{ GF_KEY_F22, "F22" },
 260	{ GF_KEY_F23, "F23" },
 261	{ GF_KEY_F24, "F24" },
 262	{ GF_KEY_FINALMODE, "FinalMode" },
 263	{ GF_KEY_FIND, "Find" },
 264	{ GF_KEY_FULLWIDTH, "FullWidth" },
 265	{ GF_KEY_HALFWIDTH, "HalfWidth" },
 266	{ GF_KEY_HANGULMODE, "HangulMode" },
 267	{ GF_KEY_HANJAMODE, "HanjaMode"   },
 268	{ GF_KEY_HELP, "Help" },
 269	{ GF_KEY_HIRAGANA, "Hiragana" },
 270	{ GF_KEY_HOME, "Home" },
 271	{ GF_KEY_INSERT, "Insert" },
 272	{ GF_KEY_JAPANESEHIRAGANA, "JapaneseHiragana" },
 273	{ GF_KEY_JAPANESEKATAKANA, "JapaneseKatakana" },
 274	{ GF_KEY_JAPANESEROMAJI, "JapaneseRomaji" },
 275	{ GF_KEY_JUNJAMODE, "JunjaMode" },
 276	{ GF_KEY_KANAMODE, "KanaMode"   },
 277	{ GF_KEY_KANJIMODE, "KanjiMode" },
 278	{ GF_KEY_KATAKANA, "Katakana"   },
 279	{ GF_KEY_LAUNCHAPPLICATION1, "LaunchApplication1" },
 280	{ GF_KEY_LAUNCHAPPLICATION2, "LaunchApplication2" },
 281	{ GF_KEY_LAUNCHMAIL, "LaunchMail" },
 282	{ GF_KEY_LEFT, "Left" },
 283	{ GF_KEY_META, "Meta" },
 284	{ GF_KEY_MEDIANEXTTRACK, "MediaNextTrack" },
 285	{ GF_KEY_MEDIAPLAYPAUSE, "MediaPlayPause" },
 286	{ GF_KEY_MEDIAPREVIOUSTRACK, "MediaPreviousTrack" },
 287	{ GF_KEY_MEDIASTOP, "MediaStop" },
 288	{ GF_KEY_MODECHANGE, "ModeChange" },
 289	{ GF_KEY_NONCONVERT, "Nonconvert" },
 290	{ GF_KEY_NUMLOCK, "NumLock" },
 291	{ GF_KEY_PAGEDOWN, "PageDown" },
 292	{ GF_KEY_PAGEUP, "PageUp" },
 293	{ GF_KEY_PASTE, "Paste" },
 294	{ GF_KEY_PAUSE, "Pause" },
 295	{ GF_KEY_PLAY, "Play" },
 296	{ GF_KEY_PREVIOUSCANDIDATE, "PreviousCandidate" },
 297	{ GF_KEY_PRINTSCREEN, "PrintScreen" },
 298	{ GF_KEY_PROCESS, "Process" },
 299	{ GF_KEY_PROPS, "Props" },
 300	{ GF_KEY_RIGHT, "Right" },
 301	{ GF_KEY_ROMANCHARACTERS, "RomanCharacters" },
 302	{ GF_KEY_SCROLL, "Scroll" },
 303	{ GF_KEY_SELECT, "Select" },
 304	{ GF_KEY_SELECTMEDIA, "SelectMedia" },
 305	{ GF_KEY_SHIFT, "Shift" },
 306	{ GF_KEY_STOP, "Stop" },
 307	{ GF_KEY_UP, "Up" },
 308	{ GF_KEY_UNDO, "Undo" },
 309	{ GF_KEY_VOLUMEDOWN, "VolumeDown" },
 310	{ GF_KEY_VOLUMEMUTE, "VolumeMute" },
 311	{ GF_KEY_VOLUMEUP, "VolumeUp" },
 312	{ GF_KEY_WIN, "Win" },
 313	{ GF_KEY_ZOOM, "Zoom" },
 314	{ GF_KEY_BACKSPACE, "U+0008" },
 315	{ GF_KEY_TAB, "U+0009" },
 316	{ GF_KEY_CANCEL, "U+0018" },
 317	{ GF_KEY_ESCAPE, "U+001B" },
 318	{ GF_KEY_SPACE, "U+0020" },
 319	{ GF_KEY_EXCLAMATION, "U+0021" },
 320	{ GF_KEY_QUOTATION, "U+0022" },
 321	{ GF_KEY_NUMBER, "U+0023" },
 322	{ GF_KEY_DOLLAR, "U+0024" },
 323	{ GF_KEY_AMPERSAND, "U+0026" },
 324	{ GF_KEY_APOSTROPHE, "U+0027" },
 325	{ GF_KEY_LEFTPARENTHESIS, "U+0028" },
 326	{ GF_KEY_RIGHTPARENTHESIS, "U+0029" },
 327	{ GF_KEY_STAR, "U+002A" },
 328	{ GF_KEY_PLUS, "U+002B" },
 329	{ GF_KEY_COMMA, "U+002C" },
 330	{ GF_KEY_HYPHEN, "U+002D" },
 331	{ GF_KEY_FULLSTOP, "U+002E" },
 332	{ GF_KEY_SLASH, "U+002F" },
 333	{ GF_KEY_0, "U+0030" },
 334	{ GF_KEY_1, "U+0031" },
 335	{ GF_KEY_2, "U+0032" },
 336	{ GF_KEY_3, "U+0033" },
 337	{ GF_KEY_4, "U+0034" },
 338	{ GF_KEY_5, "U+0035" },
 339	{ GF_KEY_6, "U+0036" },
 340	{ GF_KEY_7, "U+0037" },
 341	{ GF_KEY_8, "U+0038" },
 342	{ GF_KEY_9, "U+0039" },
 343	{ GF_KEY_COLON, "U+003A" },
 344	{ GF_KEY_SEMICOLON, "U+003B" },
 345	{ GF_KEY_LESSTHAN, "U+003C" },
 346	{ GF_KEY_EQUALS, "U+003D" },
 347	{ GF_KEY_GREATERTHAN, "U+003E" },
 348	{ GF_KEY_QUESTION, "U+003F" },
 349	{ GF_KEY_AT, "U+0040" },
 350	{ GF_KEY_A, "U+0041" },
 351	{ GF_KEY_B, "U+0042" },
 352	{ GF_KEY_C, "U+0043" },
 353	{ GF_KEY_D, "U+0044" },
 354	{ GF_KEY_E, "U+0045" },
 355	{ GF_KEY_F, "U+0046" },
 356	{ GF_KEY_G, "U+0047" },
 357	{ GF_KEY_H, "U+0048" },
 358	{ GF_KEY_I, "U+0049" },
 359	{ GF_KEY_J, "U+004A" },
 360	{ GF_KEY_K, "U+004B" },
 361	{ GF_KEY_L, "U+004C" },
 362	{ GF_KEY_M, "U+004D" },
 363	{ GF_KEY_N, "U+004E" },
 364	{ GF_KEY_O, "U+004F" },
 365	{ GF_KEY_P, "U+0050" },
 366	{ GF_KEY_Q, "U+0051" },
 367	{ GF_KEY_R, "U+0052" },
 368	{ GF_KEY_S, "U+0053" },
 369	{ GF_KEY_T, "U+0054" },
 370	{ GF_KEY_U, "U+0055" },
 371	{ GF_KEY_V, "U+0056" },
 372	{ GF_KEY_W, "U+0057" },
 373	{ GF_KEY_X, "U+0058" },
 374	{ GF_KEY_Y, "U+0059" },
 375	{ GF_KEY_Z, "U+005A" },
 376	{ GF_KEY_LEFTSQUAREBRACKET, "U+005B" },
 377	{ GF_KEY_BACKSLASH, "U+005C" },
 378	{ GF_KEY_RIGHTSQUAREBRACKET, "U+005D" },
 379	{ GF_KEY_CIRCUM, "U+005E" },
 380	{ GF_KEY_UNDERSCORE, "U+005F" },
 381	{ GF_KEY_GRAVEACCENT, "U+0060" },
 382	{ GF_KEY_LEFTCURLYBRACKET, "U+007B" },
 383	{ GF_KEY_PIPE, "U+007C" },
 384	{ GF_KEY_RIGHTCURLYBRACKET, "U+007D" },
 385	{ GF_KEY_DEL, "U+007F" },
 386	{ GF_KEY_INVERTEXCLAMATION, "U+00A1" },
 387	{ GF_KEY_DEADGRAVE, "U+0300" },
 388	{ GF_KEY_DEADEACUTE, "U+0301" },
 389	{ GF_KEY_DEADCIRCUM, "U+0302" },
 390	{ GF_KEY_DEADTILDE, "U+0303" },
 391	{ GF_KEY_DEADMACRON, "U+0304" },
 392	{ GF_KEY_DEADBREVE, "U+0306" },
 393	{ GF_KEY_DEADABOVEDOT, "U+0307" },
 394	{ GF_KEY_DEADDIARESIS, "U+0308" },
 395	{ GF_KEY_DEADRINGABOVE, "U+030A" },
 396	{ GF_KEY_DEADDOUBLEACUTE, "U+030B" },
 397	{ GF_KEY_DEADCARON, "U+030C" },
 398	{ GF_KEY_DEADCEDILLA, "U+0327" },
 399	{ GF_KEY_DEADOGONEK, "U+0328" },
 400	{ GF_KEY_DEADIOTA, "U+0345" },
 401	{ GF_KEY_EURO, "U+20AC" },
 402	{ GF_KEY_DEADVOICESOUND, "U+3099" },
 403	{ GF_KEY_DEADSEMIVOICESOUND, "U+309A" },
 404	{ GF_KEY_CHANNELUP, "ChannelUp" },
 405	{ GF_KEY_CHANNELDOWN, "ChannelDown" },
 406	{ GF_KEY_TEXT, "Text" },
 407	{ GF_KEY_INFO, "Info" },
 408	{ GF_KEY_EPG, "EPG" },
 409	{ GF_KEY_RECORD, "Record" },
 410	{ GF_KEY_BEGINPAGE, "BeginPage" }
 411};
 412
 413
 414GF_EXPORT
 415const char *gf_dom_get_key_name(u32 key_identifier)
 416{
 417	u32 count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid);
 418	if (!key_identifier || count<=key_identifier) return "Unknown";
 419	return predefined_key_identifiers[key_identifier-1].name;
 420}
 421
 422
 423u32 gf_dom_get_key_type(char *key_name)
 424{
 425	if (strlen(key_name) == 1) {
 426		char c[2];
 427		c[0] = key_name[0];
 428		c[1] = 0;
 429		strupr(c);
 430		if (c[0] >= 'A' && c[0] <= 'Z')
 431			return (GF_KEY_A + (c[0] - 'A') );
 432
 433		if (c[0] >= '0' && c[0] <= '9')
 434			return ( GF_KEY_0 + (c[0] - '0') );
 435
 436		switch (c[0]) {
 437		case '@': return GF_KEY_AT;
 438		case '*': return GF_KEY_STAR;
 439		case '#': return GF_KEY_NUMBER;
 440		case ' ': return GF_KEY_SPACE;
 441		case '!': return GF_KEY_EXCLAMATION;
 442		case '"': return GF_KEY_QUOTATION;
 443		case '$': return GF_KEY_DOLLAR;
 444		case '&': return GF_KEY_AMPERSAND;
 445		case '\'': return GF_KEY_APOSTROPHE;
 446		case '(': return GF_KEY_LEFTPARENTHESIS;
 447		case ')': return GF_KEY_RIGHTPARENTHESIS;
 448		case '+': return GF_KEY_PLUS;
 449		case ',': return GF_KEY_COMMA;
 450		case '-': return GF_KEY_HYPHEN;
 451		case '.': return GF_KEY_FULLSTOP;
 452		case '/': return GF_KEY_SLASH;
 453		case ':': return GF_KEY_COLON;
 454		case ';': return GF_KEY_SEMICOLON;
 455		case '<': return GF_KEY_LESSTHAN;
 456		case '=': return GF_KEY_EQUALS;
 457		case '>': return GF_KEY_GREATERTHAN;
 458		case '?': return GF_KEY_QUESTION;
 459		case '[': return GF_KEY_LEFTSQUAREBRACKET;
 460		case '\\': return GF_KEY_BACKSLASH;
 461		case ']': return GF_KEY_RIGHTSQUAREBRACKET;
 462		case '^': return GF_KEY_CIRCUM;
 463		case '_': return GF_KEY_UNDERSCORE;
 464		case '`': return GF_KEY_GRAVEACCENT;
 465		case '{': return GF_KEY_LEFTCURLYBRACKET;
 466		case '|': return GF_KEY_PIPE;
 467		case '}': return GF_KEY_RIGHTCURLYBRACKET;
 468		case 'Ą': return GF_KEY_INVERTEXCLAMATION;
 469		default: return GF_KEY_UNIDENTIFIED;
 470		}
 471	} else {
 472		u32 i, count;
 473		count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid);
 474		for (i=0; i<count; i++) {
 475			if (!stricmp(key_name, predefined_key_identifiers[i].name)) {
 476				return predefined_key_identifiers[i].key_code;
 477			}
 478		}
 479		return GF_KEY_UNIDENTIFIED;
 480	}
 481}
 482
 483/* Basic SVG datatype parsing functions */
 484static const struct predef_col { const char *name; u8 r; u8 g; u8 b; } predefined_colors[] =
 485{
 486	{"aliceblue",240, 248, 255},
 487	{"antiquewhite",250, 235, 215},
 488	{"aqua", 0, 255, 255},
 489	{"aquamarine",127, 255, 212},
 490	{"azure",240, 255, 255},
 491	{"beige",245, 245, 220},
 492	{"bisque",255, 228, 196},
 493	{"black", 0, 0, 0},
 494	{"blanchedalmond",255, 235, 205},
 495	{"blue", 0, 0, 255},
 496	{"blueviolet",138, 43, 226},
 497	{"brown",165, 42, 42},
 498	{"burlywood",222, 184, 135},
 499	{"cadetblue", 95, 158, 160},
 500	{"chartreuse",127, 255, 0},
 501	{"chocolate",210, 105, 30},
 502	{"coral",255, 127, 80},
 503	{"lightpink",255, 182, 193},
 504	{"lightsalmon",255, 160, 122},
 505	{"lightseagreen", 32, 178, 170},
 506	{"lightskyblue",135, 206, 250},
 507	{"lightslategray",119, 136, 153},
 508	{"lightslategrey",119, 136, 153},
 509	{"lightsteelblue",176, 196, 222},
 510	{"lightyellow",255, 255, 224},
 511	{"lime", 0, 255, 0},
 512	{"limegreen", 50, 205, 50},
 513	{"linen",250, 240, 230},
 514	{"magenta",255, 0, 255},
 515	{"maroon",128, 0, 0},
 516	{"mediumaquamarine",102, 205, 170},
 517	{"mediumblue", 0, 0, 205},
 518	{"mediumorchid",186, 85, 211},
 519	{"cornflowerblue",100, 149, 237},
 520	{"cornsilk",255, 248, 220},
 521	{"crimson",220, 20, 60},
 522	{"cyan", 0, 255, 255},
 523	{"darkblue", 0, 0, 139},
 524	{"darkcyan", 0, 139, 139},
 525	{"darkgoldenrod",184, 134, 11},
 526	{"darkgray",169, 169, 169},
 527	{"darkgreen", 0, 100, 0},
 528	{"darkgrey",169, 169, 169},
 529	{"darkkhaki",189, 183, 107},
 530	{"darkmagenta",139, 0, 139},
 531	{"darkolivegreen", 85, 107, 47},
 532	{"darkorange",255, 140, 0},
 533	{"darkorchid",153, 50, 204},
 534	{"darkred",139, 0, 0},
 535	{"darksalmon",233, 150, 122},
 536	{"darkseagreen",143, 188, 143},
 537	{"darkslateblue", 72, 61, 139},
 538	{"darkslategray", 47, 79, 79},
 539	{"darkslategrey", 47, 79, 79},
 540	{"darkturquoise", 0, 206, 209},
 541	{"darkviolet",148, 0, 211},
 542	{"deeppink",255, 20, 147},
 543	{"deepskyblue", 0, 191, 255},
 544	{"dimgray",105, 105, 105},
 545	{"dimgrey",105, 105, 105},
 546	{"dodgerblue", 30, 144, 255},
 547	{"firebrick",178, 34, 34},
 548	{"floralwhite",255, 250, 240},
 549	{"forestgreen", 34, 139, 34},
 550	{"fuchsia",255, 0, 255},
 551	{"gainsboro",220, 220, 220},
 552	{"ghostwhite",248, 248, 255},
 553	{"gold",255, 215, 0},
 554	{"goldenrod",218, 165, 32},
 555	{"gray",128, 128, 128},
 556	{"grey",128, 128, 128},
 557	{"green", 0, 128, 0},
 558	{"greenyellow",173, 255, 47},
 559	{"honeydew",240, 255, 240},
 560	{"hotpink",255, 105, 180},
 561	{"indianred",205, 92, 92},
 562	{"indigo", 75, 0, 130},
 563	{"ivory",255, 255, 240},
 564	{"khaki",240, 230, 140},
 565	{"lavender",230, 230, 25},
 566	{"lavenderblush",255, 240, 245},
 567	{"mediumpurple",147, 112, 219},
 568	{"mediumseagreen", 60, 179, 113},
 569	{"mediumslateblue",123, 104, 238},
 570	{"mediumspringgreen", 0, 250, 154},
 571	{"mediumturquoise", 72, 209, 204},
 572	{"mediumvioletred",199, 21, 133},
 573	{"midnightblue", 25, 25, 112},
 574	{"mintcream",245, 255, 250},
 575	{"mistyrose",255, 228, 225},
 576	{"moccasin",255, 228, 181},
 577	{"navajowhite",255, 222, 173},
 578	{"navy", 0, 0, 128},
 579	{"oldlace",253, 245, 230},
 580	{"olive",128, 128, 0},
 581	{"olivedrab",107, 142, 35},
 582	{"orange",255, 165, 0},
 583	{"orangered",255, 69, 0},
 584	{"orchid",218, 112, 214},
 585	{"palegoldenrod",238, 232, 170},
 586	{"palegreen",152, 251, 152},
 587	{"paleturquoise",175, 238, 238},
 588	{"palevioletred",219, 112, 147},
 589	{"papayawhip",255, 239, 213},
 590	{"peachpuff",255, 218, 185},
 591	{"peru",205, 133, 63},
 592	{"pink",255, 192, 203},
 593	{"plum",221, 160, 221},
 594	{"powderblue",176, 224, 230},
 595	{"purple",128, 0, 128},
 596	{"red",255, 0, 0},
 597	{"rosybrown",188, 143, 143},
 598	{"royalblue", 65, 105, 225},
 599	{"saddlebrown",139, 69, 19},
 600	{"salmon",250, 128, 114},
 601	{"sandybrown",244, 164, 96},
 602	{"seagreen", 46, 139, 87},
 603	{"seashell",255, 245, 238},
 604	{"sienna",160, 82, 45},
 605	{"silver",192, 192, 192},
 606	{"skyblue",135, 206, 235},
 607	{"slateblue",106, 90, 205},
 608	{"slategray",112, 128, 144},
 609	{"slategrey",112, 128, 144},
 610	{"snow",255, 250, 250},
 611	{"springgreen", 0, 255, 127},
 612	{"steelblue", 70, 130, 180},
 613	{"tan",210, 180, 140},
 614	{"teal", 0, 128, 128},
 615	{"lawngreen",124, 252, 0},
 616	{"lemonchiffon",255, 250, 205},
 617	{"lightblue",173, 216, 230},
 618	{"lightcoral",240, 128, 128},
 619	{"lightcyan",224, 255, 255},
 620	{"lightgoldenrodyellow",250, 250, 210},
 621	{"lightgray",211, 211, 211},
 622	{"lightgreen",144, 238, 144},
 623	{"lightgrey",211, 211, 211},
 624	{"thistle",216, 191, 216},
 625	{"tomato",255, 99, 71},
 626	{"turquoise", 64, 224, 208},
 627	{"violet",238, 130, 238},
 628	{"wheat",245, 222, 179},
 629	{"white",255, 255, 255},
 630	{"whitesmoke",245, 245, 245},
 631	{"yellow",255, 255, 0},
 632	{"yellowgreen",154, 205, 50}
 633
 634};
 635
 636
 637/* Basic SVG datatype parsing functions */
 638static const struct sys_col { const char *name; u8 type; } system_colors[] =
 639{
 640	{"ActiveBorder", SVG_COLOR_ACTIVE_BORDER},
 641	{"ActiveCaption", SVG_COLOR_ACTIVE_CAPTION},
 642	{"AppWorkspace", SVG_COLOR_APP_WORKSPACE},
 643	{"Background", SVG_COLOR_BACKGROUND},
 644	{"ButtonFace", SVG_COLOR_BUTTON_FACE},
 645	{"ButtonHighlight", SVG_COLOR_BUTTON_HIGHLIGHT},
 646	{"ButtonShadow", SVG_COLOR_BUTTON_SHADOW},
 647	{"ButtonText", SVG_COLOR_BUTTON_TEXT},
 648	{"CaptionText", SVG_COLOR_CAPTION_TEXT},
 649	{"GrayText", SVG_COLOR_GRAY_TEXT},
 650	{"Highlight", SVG_COLOR_HIGHLIGHT},
 651	{"HighlightText", SVG_COLOR_HIGHLIGHT_TEXT},
 652	{"InactiveBorder", SVG_COLOR_INACTIVE_BORDER},
 653	{"InactiveCaption", SVG_COLOR_INACTIVE_CAPTION},
 654	{"InactiveCaptionText", SVG_COLOR_INACTIVE_CAPTION_TEXT},
 655	{"InfoBackground", SVG_COLOR_INFO_BACKGROUND},
 656	{"InfoText", SVG_COLOR_INFO_TEXT},
 657	{"Menu", SVG_COLOR_MENU},
 658	{"MenuText", SVG_COLOR_MENU_TEXT},
 659	{"Scrollbar", SVG_COLOR_SCROLLBAR},
 660	{"ThreeDDarkShadow", SVG_COLOR_3D_DARK_SHADOW},
 661	{"ThreeDFace", SVG_COLOR_3D_FACE},
 662	{"ThreeDHighlight", SVG_COLOR_3D_HIGHLIGHT},
 663	{"ThreeDLightShadow", SVG_COLOR_3D_LIGHT_SHADOW},
 664	{"ThreeDShadow", SVG_COLOR_3D_SHADOW},
 665	{"Window", SVG_COLOR_WINDOW},
 666	{"WindowFrame", SVG_COLOR_WINDOW_FRAME},
 667	{"WindowText", SVG_COLOR_WINDOW_TEXT},
 668};
 669
 670/* parses an color from a named color HTML or CSS 2 */
 671static void svg_parse_named_color(SVG_Color *col, char *attribute_content)
 672{
 673	u32 i, count;
 674	count = sizeof(predefined_colors) / sizeof(struct predef_col);
 675	for (i=0; i<count; i++) {
 676		if (!strcmp(attribute_content, predefined_colors[i].name)) {
 677			col->red = INT2FIX(predefined_colors[i].r) / 255;
 678			col->green = INT2FIX(predefined_colors[i].g) / 255;
 679			col->blue = INT2FIX(predefined_colors[i].b) / 255;
 680			col->type = SVG_COLOR_RGBCOLOR;
 681			return;
 682		}
 683	}
 684	count = sizeof(system_colors) / sizeof(struct sys_col);
 685	for (i=0; i<count; i++) {
 686		if (!strcmp(attribute_content, system_colors[i].name)) {
 687			col->type = system_colors[i].type;
 688			return;
 689		}
 690	}
 691}
 692
 693const char *gf_svg_get_system_paint_server_name(u32 paint_type)
 694{
 695	u32 i, count;
 696	count = sizeof(system_colors) / sizeof(struct sys_col);
 697	for (i=0; i<count; i++) {
 698		if (paint_type == system_colors[i].type) return system_colors[i].name;
 699	}
 700	return "undefined";
 701}
 702
 703u32 gf_svg_get_system_paint_server_type(const char *name)
 704{
 705	u32 i, count;
 706	count = sizeof(system_colors) / sizeof(struct sys_col);
 707	for (i=0; i<count; i++) {
 708		if (!strcmp(name, system_colors[i].name)) return system_colors[i].type;
 709	}
 710	return 0;
 711}
 712
 713/* Reads an SVG Color
 714   either #RRGGBB, #RGB, rgb(r,g,b) in [0,255] , colorname, or 'r g b' in [0,1]
 715   ignores any space, comma, semi-column before and any space after
 716   TODO:
 717	transform the char into char and duplicate the input, instead of modifying it
 718		be more robust to errors in color description ex rgb(0 0 0)
 719*/
 720static void svg_parse_color(SVG_Color *col, char *attribute_content)
 721{
 722	char *str = attribute_content;
 723	while (str[strlen(attribute_content)-1] == ' ') str[strlen(attribute_content)-1] = 0;
 724	while (*str != 0 && (*str == ' ' || *str == ',' || *str == ';')) str++;
 725
 726	if (!strcmp(str, "currentColor")) {
 727		col->type = SVG_COLOR_CURRENTCOLOR;
 728		return;
 729	} else if (!strcmp(str, "inherit")) {
 730		col->type = SVG_COLOR_INHERIT;
 731		return;
 732	} else if (str[0]=='#') {
 733		u32 val;
 734		sscanf(str+1, "%x", &val);
 735		if (strlen(str) == 7) {
 736			col->red = INT2FIX((val>>16) & 0xFF) / 255;
 737			col->green = INT2FIX((val>>8) & 0xFF) / 255;
 738			col->blue = INT2FIX(val & 0xFF) / 255;
 739		} else {
 740			col->red = INT2FIX((val>>8) & 0xF) / 15;
 741			col->green = INT2FIX((val>>4) & 0xF) / 15;
 742			col->blue = INT2FIX(val & 0xF) / 15;
 743		}
 744		col->type = SVG_COLOR_RGBCOLOR;
 745	} else if (strstr(str, "rgb(") || strstr(str, "RGB(")) {
 746		Float _val;
 747		u8 is_percentage= 0;
 748		if (strstr(str, "%")) is_percentage = 1;
 749		str = strstr(str, "(");
 750		str++;
 751		sscanf(str, "%f", &_val); col->red = FLT2FIX(_val);
 752		str = strstr(str, ",");
 753		if (!str) {
 754			/* space separated colors/percentages are not allowed neither in SVG 1.1 nor in SVG T1.2 */
 755			col->red = col->green = col->blue = 0;
 756			return;
 757		}
 758		str++;
 759		sscanf(str, "%f", &_val); col->green = FLT2FIX(_val);
 760		str = strstr(str, ",");
 761		if (!str) {
 762			/* space separated colors/percentages are not allowed neither in SVG 1.1 nor in SVG T1.2 */
 763			col->red = col->green = col->blue = 0;
 764			return;
 765		}
 766		str++;
 767		sscanf(str, "%f", &_val); col->blue = FLT2FIX(_val);
 768		if (is_percentage) {
 769			col->red /= 100;
 770			col->green /= 100;
 771			col->blue /= 100;
 772		} else {
 773			col->red /= 255;
 774			col->green /= 255;
 775			col->blue /= 255;
 776		}
 777		col->type = SVG_COLOR_RGBCOLOR;
 778	} else if ((str[0] >= 'a' && str[0] <= 'z')
 779		|| (str[0] >= 'A' && str[0] <= 'Z')) {
 780		svg_parse_named_color(col, str);
 781	} else {
 782		Float _r, _g, _b;
 783		sscanf(str, "%f %f %f", &_r, &_g, &_b);
 784		col->red = FLT2FIX(_r);
 785		col->green = FLT2FIX(_g);
 786		col->blue = FLT2FIX(_b);
 787		col->type = SVG_COLOR_RGBCOLOR;
 788	}
 789}
 790
 791/*
 792	Reads a number (i.e. without unit) according to the CSS syntax (same as SVG paths and transforms)
 793		trims any space, comma, semi-column before or after (TODO: fix this)
 794		reads an optional + or -
 795		then reads a digit between 0 and 9
 796		optionally followed by an '.' and digits between 0 and 9
 797		optionally followed by e or E and digits between 0 and 9
 798	Returns the number of chars read in d
 799*/
 800static u32 svg_parse_number(char *d, Fixed *f, Bool is_angle)
 801{
 802    u32 nb_digit_before = 0;
 803	u32 nb_digit_after = 0;
 804    Bool has_fractional = 0;
 805	Bool is_negative = 0;
 806	Float _val = 0;
 807	u32 i = 0;
 808
 809    /* warning the comma and semicolumn should not be there when parsing a number in a path */
 810	while ((d[i] != 0) && strchr(" ,;\r\n\t", d[i])) i++;
 811
 812    if (!d[i]) {
 813        GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Parsing] Parsing number with empty string or only spaces: %s\n", d));
 814        return 0;
 815    }
 816    if (d[i] == '+') {
 817        i++;
 818    } else if (d[i] == '-') {
 819		is_negative = 1;
 820		i++;
 821	}
 822    /* Warning: this is not normal, should be detected somehow by checking the BNF */
 823	/* if ((d[i]=='N') && (d[i+1]=='a') && (d[i+2]=='N')) {
 824		i+= 3;
 825		_val = 0;
 826		goto end;
 827	}*/
 828    /* read the digit-sequence token of the BNF */
 829	while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) {
 830		_val = _val*10 + (d[i]-'0');
 831        nb_digit_before++;
 832		i++;
 833	}
 834	if (d[i] == '.') {
 835        has_fractional = 1;
 836		i++;
 837		while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) {
 838			_val = _val*10 + (d[i]-'0');
 839			nb_digit_after++;
 840			i++;
 841		}
 842        if (nb_digit_after) {
 843            _val /= (Float)pow(10,nb_digit_after);
 844        } else if (nb_digit_before == 0) {
 845            GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing number (expecting digits before or after a '.': %s\n", d));
 846            return 0;
 847        } else {
 848            /* dangling '.' without digits after. This is allowed by the BNF */
 849        }
 850	}
 851    if ((nb_digit_before == 0) && (has_fractional == 0)) {
 852        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing number (expecting digits):%s\n", d));
 853        return 0;
 854    }
 855    /* reading the exponent */
 856	if (d[i] == 'e' || d[i] == 'E') {
 857		Bool neg_exp = 0;
 858		u32 nb_exp_digits = 0;
 859        s32 exp = 0;
 860		i++;
 861		if (d[i] == '+') i++;
 862		else if (d[i] == '-') {
 863			i++;
 864			neg_exp=1;
 865		}
 866		while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) {
 867			exp = exp*10 + (d[i]-'0');
 868            nb_exp_digits++;
 869			i++;
 870		}
 871        if (nb_exp_digits) {
 872            _val *= (Float)pow(10, neg_exp ? -exp : exp);
 873        } else {
 874            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));
 875            return 0;
 876        }
 877	}
 878    /* We can now produce the final number */
 879	if (is_negative) _val *= -1;
 880	if (is_angle) {
 881		_val/=180;
 882		(*f) = gf_mulfix(FLT2FIX(_val), GF_PI);
 883	} else {
 884		(*f) = FLT2FIX(_val);
 885	}
 886
 887    /* warning the comma and semicolumn should not be there when parsing a path number */
 888	while (d[i] != 0 && (d[i] == ' ' || d[i] == ',' || d[i] == ';')) i++;
 889	return i;
 890}
 891
 892/*
 893   Parse an Offset Value, i.e +/- Clock Value
 894*/
 895static GF_Err svg_parse_clock_value(char *d, Double *clock_value)
 896{
 897	char *tmp;
 898	s32 sign = 1;
 899
 900	if (!d) return GF_BAD_PARAM;
 901
 902	if (!d[0]) return GF_BAD_PARAM;
 903
 904	if (d[0] == '+') d++;
 905	else if (d[0] == '-') { sign = -1; d++; }
 906
 907	if (!d[0]) return GF_BAD_PARAM;
 908
 909	/* According to SVG, the following are invalid syntaxes (see animate-elem-225-t.svg)
 910		'+-2s'
 911		'1++s' even though sscanf returns the right values
 912	*/
 913	if (strchr(d, '+') || strchr(d, '-')) return GF_BAD_PARAM;
 914
 915	/* No embedded white space is allowed in clock values,
 916	   although leading and trailing white space characters will be ignored.*/
 917	while (*d == ' ') d++;
 918
 919	if ((tmp = strchr(d, ':'))) {
 920		/* Full or Partial Clock value */
 921		tmp++;
 922		if ((tmp = strchr(tmp, ':'))) {
 923			/* Full Clock value : hh:mm:ss(.frac) */
 924			u32 hours;
 925			u32 minutes;
 926			Float seconds;
 927			if (sscanf(d, "%u:%u:%f", &hours, &minutes, &seconds) < 3) return GF_BAD_PARAM;
 928			*clock_value = hours*3600 + minutes*60 + seconds;
 929		} else {
 930			/* Partial Clock value : mm:ss(.frac) */
 931			s32 minutes;
 932			Float seconds;
 933			if (sscanf(d, "%d:%f", &minutes, &seconds) < 2) return GF_BAD_PARAM;
 934			*clock_value = minutes*60 + seconds;
 935		}
 936	} else if ((tmp = strstr(d, "h"))) {
 937		Float f;
 938		if (sscanf(d, "%fh", &f) == 0) return GF_BAD_PARAM;
 939		*clock_value = 3600*f;
 940	} else if (strstr(d, "min")) {
 941		Float f;
 942		if (sscanf(d, "%fmin", &f) == 0) return GF_BAD_PARAM;
 943		*clock_value = 60*f;
 944	} else if ((tmp = strstr(d, "ms"))) {
 945		Float f;
 946		if (sscanf(d, "%fms", &f) == 0) return GF_BAD_PARAM;
 947		*clock_value = f/1000;
 948	} else if (strchr(d, 's')) {
 949		Float f;
 950		if (sscanf(d, "%fs", &f) == 0) return GF_BAD_PARAM;
 951		*clock_value = f;
 952	} else {
 953		Float f;
 954		if (sscanf(d, "%f", &f) == 0) return GF_BAD_PARAM;
 955		*clock_value = f;
 956	}
 957	*clock_value *= sign;
 958	return GF_OK;
 959}
 960/* Parses one SVG time value:
 961	  indefinite,
 962	  element_id.event_name
 963	  wallclock,
 964	  accessKey,
 965	  events,
 966	  clock value.
 967 */
 968static GF_Err smil_parse_time(GF_Node *elt, SMIL_Time *v, char *d)
 969{
 970	GF_Err e = GF_OK;
 971	char *tmp;
 972
 973	/* Offset Values */
 974	if ((d[0] >= '0' && d[0] <= '9') || d[0] == '+' || d[0] == '-'){
 975		v->type = GF_SMIL_TIME_CLOCK;
 976		return svg_parse_clock_value(d, &(v->clock));
 977	}
 978
 979	/* Indefinite Values */
 980	else if (!strcmp(d, "indefinite")) {
 981		v->type = GF_SMIL_TIME_INDEFINITE;
 982		return GF_OK;
 983	}
 984
 985	/* Wallclock Values */
 986	else if ((tmp = strstr(d, "wallclock("))) {
 987		u32 year, month, day;
 988		u32 hours, minutes;
 989		u32 nhours, nminutes;
 990		Float seconds;
 991		char *tmp1, *tmp2;
 992
 993		v->type = GF_SMIL_TIME_WALLCLOCK;
 994		tmp += 10;
 995		if ((tmp1 = strchr(tmp, 'T')) ) {
 996			/* From tmp to wallStartTime, we parse a date */
 997			sscanf(tmp, "%u-%u-%dT", &year, &month, &day);
 998			tmp1++;
 999			tmp = tmp1;
1000		}
1001		if ((tmp1 = strchr(tmp, ':')) ) {
1002			if ((tmp2 = strchr(tmp1, ':')) ) {
1003				/* HHMMSS */
1004				sscanf(tmp, "%u:%u:%f", &hours, &minutes, &seconds);
1005			} else {
1006				/* HHMM */
1007				sscanf(tmp, "%u:%u", &hours, &minutes);
1008			}
1009		}
1010		if (strchr(tmp, 'Z')) {
1011			return GF_OK;
1012		} else {
1013			if ( (tmp1 = strchr(tmp, '+')) ) {
1014				sscanf(tmp1, "%u:%u", &nhours, &nminutes);
1015			} else if ( (tmp1 = strchr(tmp, '-')) ) {
1016				sscanf(tmp1, "%u:%u", &nhours, &nminutes);
1017			}
1018		}
1019		return GF_OK;
1020	}
1021
1022	/* AccessKey Values */
1023	else if ((tmp = strstr(d, "accessKey("))) {
1024		char *sep;
1025		v->type = GF_SMIL_TIME_EVENT;
1026		v->event.type = GF_EVENT_KEYDOWN;
1027		v->element = elt->sgprivate->scenegraph->RootNode;
1028		tmp+=10;
1029		sep = strchr(d, ')');
1030		sep[0] = 0;
1031		v->event.parameter = gf_dom_get_key_type(tmp);
1032		sep++;
1033		if ((tmp = strchr(sep, '+')) || (tmp = strchr(sep, '-'))) {
1034			char c = *tmp;
1035			tmp++;
1036			e = svg_parse_clock_value(tmp, &(v->clock));
1037			if (c == '-') v->clock *= -1;
1038		}
1039		return e;
1040	}
1041
1042	else {
1043		Bool had_param = 0;
1044		char *tmp2;
1045		v->type = GF_SMIL_TIME_EVENT;
1046		if ((tmp = strchr(d, '.'))) {
1047			tmp[0] = 0;
1048			if (strlen(d) == 0) {
1049				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] expecting an id before '.' in SMIL Time .%s\n", tmp+1));
1050				return GF_BAD_PARAM;
1051			}
1052			v->element_id = gf_strdup(d);
1053			tmp[0] = '.';
1054			tmp++;
1055		} else {
1056			tmp = d;
1057		}
1058		if ((tmp2 = strchr(tmp, '('))) {
1059			tmp2[0] = 0;
1060			v->event.type = gf_dom_event_type_by_name(tmp);
1061			tmp2[0] = '(';
1062			tmp2++;
1063			had_param = 1;
1064			v->event.parameter = atoi(tmp2);
1065			tmp = strchr(tmp2, ')');
1066			if (!tmp) {
1067				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] expecting ')' in SMIL Time %s\n", d));
1068				return GF_BAD_PARAM;
1069			}
1070			tmp++;
1071		}
1072		if ((tmp2 = strchr(tmp, '+')) || (tmp2 = strchr(tmp, '-'))) {
1073			char c = *tmp2;
1074			char *tmp3 = tmp2;
1075			tmp2[0] = 0;
1076			tmp3--;
1077			while (*tmp3==' ') { *tmp3=0; tmp3--; }
1078			if (v->event.type == 0) v->event.type = gf_dom_event_type_by_name(tmp);
1079			if (!had_param && (v->event.type == GF_EVENT_REPEAT || v->event.type == GF_EVENT_REPEAT_EVENT))
1080				v->event.parameter = 1;
1081			tmp2[0] = c;
1082			tmp2++;
1083			e = svg_parse_clock_value(tmp2, &(v->clock));
1084			if (c == '-') v->clock *= -1;
1085			return e;
1086		} else {
1087			if (v->event.type == 0) v->event.type = gf_dom_event_type_by_name(tmp);
1088			if (!had_param && (v->event.type == GF_EVENT_REPEAT || v->event.type == GF_EVENT_REPEAT_EVENT))
1089				v->event.parameter = 1;
1090		}
1091	}
1092	return GF_OK;
1093}
1094
1095/* Parses a list of SVG transformations and collapses them in the given matrix */
1096Bool gf_svg_parse_transformlist(GF_Matrix2D *mat, char *attribute_content)
1097{
1098	GF_Matrix2D tmp;
1099
1100	char *str;
1101    u32 read_chars;
1102	u32 i;
1103
1104	gf_mx2d_init(*mat);
1105
1106	str = attribute_content;
1107	i = 0;
1108	while (str[i] != 0) {
1109		while (str[i] == ' ') i++;
1110		if (str[i] == ',') i++;
1111		while (str[i] == ' ') i++;
1112		if (strstr(str+i, "scale")==str+i) {
1113			i += 5;
1114			while(str[i] == ' ') i++;
1115			if (str[i] == '(') {
1116				Fixed sx, sy;
1117				i++;
1118				read_chars = svg_parse_number(&(str[i]), &sx, 0);
1119                if (!read_chars) {
1120                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading sx component in scale: %s\n", attribute_content));
1121                    return 0;
1122                }
1123                i += read_chars;
1124
1125				if (str[i] == ')') {
1126					sy = sx;
1127				} else {
1128					read_chars = svg_parse_number(&(str[i]), &sy, 0);
1129                    if (!read_chars) {
1130                        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading sy component in scale: %s\n", attribute_content));
1131                        return 0;
1132                    }
1133                    i += read_chars;
1134				}
1135				gf_mx2d_init(tmp);
1136				gf_mx2d_add_scale(&tmp, sx, sy);
1137				gf_mx2d_add_matrix(&tmp, mat);
1138				gf_mx2d_copy(*mat, tmp);
1139
1140				while(str[i] == ' ') i++;
1141				if (str[i] == ')') i++;
1142				else {
1143                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1144                    return 0;
1145				}
1146			} else {
1147				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
1148                return 0;
1149			}
1150		} else if (strstr(str+i, "translate")==str+i) {
1151			i += 9;
1152			while(str[i] == ' ') i++;
1153			if (str[i] == '(') {
1154				Fixed tx, ty;
1155				i++;
1156				read_chars = svg_parse_number(&(str[i]), &tx, 0);
1157                if (!read_chars) {
1158                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading tx component in translate: %s\n", attribute_content));
1159                    return 0;
1160                }
1161                i += read_chars;
1162				if (str[i] == ')') {
1163					ty = 0;
1164				} else {
1165					read_chars = svg_parse_number(&(str[i]), &ty, 0);
1166                    if (!read_chars) {
1167                        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading ty component in translate: %s\n", attribute_content));
1168                        return 0;
1169                    }
1170                    i += read_chars;
1171				}
1172				gf_mx2d_init(tmp);
1173				gf_mx2d_add_translation(&tmp, tx, ty);
1174				gf_mx2d_add_matrix(&tmp, mat);
1175				gf_mx2d_copy(*mat, tmp);
1176				while(str[i] == ' ') i++;
1177				if (str[i] == ')') i++;
1178				else {
1179                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1180                    return 0;
1181				}
1182			} else {
1183				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
1184                return 0;
1185			}
1186		} else if (strstr(str+i, "rotate")==str+i) {
1187			i += 6;
1188			while(str[i] == ' ') i++;
1189			if (str[i] == '(') {
1190				Fixed angle, cx, cy;
1191				i++;
1192				read_chars = svg_parse_number(&(str[i]), &angle, 1);
1193                if (!read_chars) {
1194                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading angle component in rotate: %s\n", attribute_content));
1195                    return 0;
1196                }
1197                i += read_chars;
1198				if (str[i] == ')') {
1199					cx = cy = 0;
1200				} else {
1201					read_chars = svg_parse_number(&(str[i]), &cx, 0);
1202                    if (!read_chars) {
1203                        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading cx component in rotate: %s\n", attribute_content));
1204                        return 0;
1205                    }
1206                    i += read_chars;
1207					read_chars = svg_parse_number(&(str[i]), &cy, 0);
1208                    if (!read_chars) {
1209                        GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading cy component in rotate: %s\n", attribute_content));
1210                        return 0;
1211                    }
1212                    i += read_chars;
1213				}
1214				gf_mx2d_init(tmp);
1215				gf_mx2d_add_rotation(&tmp, cx, cy, angle);
1216				gf_mx2d_add_matrix(&tmp, mat);
1217				gf_mx2d_copy(*mat, tmp);
1218				while(str[i] == ' ') i++;
1219				if (str[i] == ')') i++;
1220				else {
1221                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1222                    return 0;
1223				}
1224			} else {
1225				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
1226                return 0;
1227			}
1228		} else if (strstr(str+i, "skewX")==str+i) {
1229			i += 5;
1230			while(str[i] == ' ') i++;
1231			if (str[i] == '(') {
1232				Fixed angle;
1233				i++;
1234				read_chars = svg_parse_number(&(str[i]), &angle, 1);
1235                if (!read_chars) {
1236                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading angle in skewX: %s\n", attribute_content));
1237                    return 0;
1238                }
1239                i += read_chars;
1240				gf_mx2d_init(tmp);
1241				gf_mx2d_add_skew_x(&tmp, angle);
1242				gf_mx2d_add_matrix(&tmp, mat);
1243				gf_mx2d_copy(*mat, tmp);
1244				while(str[i] == ' ') i++;
1245				if (str[i] == ')') i++;
1246				else {
1247                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1248                    return 0;
1249				}
1250			} else {
1251				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
1252                return 0;
1253			}
1254		} else if (strstr(str+i, "skewY")==str+i) {
1255			i += 5;
1256			while(str[i] == ' ') i++;
1257			if (str[i] == '(') {
1258				Fixed angle;
1259				i++;
1260				read_chars = svg_parse_number(&(str[i]), &angle, 1);
1261                if (!read_chars) {
1262                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading angle component in skewY: %s\n", attribute_content));
1263                    return 0;
1264                }
1265                i += read_chars;
1266				gf_mx2d_init(tmp);
1267				gf_mx2d_add_skew_y(&tmp, angle);
1268				gf_mx2d_add_matrix(&tmp, mat);
1269				gf_mx2d_copy(*mat, tmp);
1270				while(str[i] == ' ') i++;
1271				if (str[i] == ')') i++;
1272				else {
1273                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1274                    return 0;
1275				}
1276			} else {
1277				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
1278                return 0;
1279			}
1280		} else if (strstr(str+i, "matrix")==str+i) {
1281			i+=6;
1282			while(str[i] == ' ') i++;
1283			if (str[i] == '(') {
1284				i++;
1285				read_chars = svg_parse_number(&(str[i]), &(tmp.m[0]), 0);
1286                if (!read_chars) {
1287                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient a in matrix: %s\n", attribute_content));
1288                    return 0;
1289                }
1290                i += read_chars;
1291				read_chars = svg_parse_number(&(str[i]), &(tmp.m[3]), 0);
1292                if (!read_chars) {
1293                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient b in matrix: %s\n", attribute_content));
1294                    return 0;
1295                }
1296                i += read_chars;
1297				read_chars = svg_parse_number(&(str[i]), &(tmp.m[1]), 0);
1298                if (!read_chars) {
1299                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient c in matrix: %s\n", attribute_content));
1300                    return 0;
1301                }
1302                i += read_chars;
1303				read_chars = svg_parse_number(&(str[i]), &(tmp.m[4]), 0);
1304                if (!read_chars) {
1305                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient d in matrix: %s\n", attribute_content));
1306                    return 0;
1307                }
1308                i += read_chars;
1309				read_chars = svg_parse_number(&(str[i]), &(tmp.m[2]), 0);
1310                if (!read_chars) {
1311                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient e in matrix: %s\n", attribute_content));
1312                    return 0;
1313                }
1314                i += read_chars;
1315				read_chars = svg_parse_number(&(str[i]), &(tmp.m[5]), 0);
1316                if (!read_chars) {
1317                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient f in matrix: %s\n", attribute_content));
1318                    return 0;
1319                }
1320                i += read_chars;
1321				gf_mx2d_add_matrix(&tmp, mat);
1322				gf_mx2d_copy(*mat, tmp);
1323				while(str[i] == ' ') i++;
1324				if (str[i] == ')') i++;
1325				else {
1326                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1327                    return 0;
1328				}
1329			} else {
1330				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
1331                return 0;
1332			}
1333		} else {
1334			GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Unrecognized transofrm type in attribute %s\n", attribute_content));
1335            return 0;
1336		}
1337		/*for svgView parsing*/
1338		if (str[i] == ')') i++;
1339	}
1340    return 1;
1341}
1342
1343/* Parses an SVG transform attribute and collapses all in the given matrix */
1344static Bool svg_parse_transform(SVG_Transform *t, char *attribute_content)
1345{
1346	char *str;
1347	u32 i;
1348    u32 read_chars;
1349	str = attribute_content;
1350	i = 0;
1351
1352	if ((str = strstr(attribute_content, "ref"))) {
1353		t->is_ref = 1;
1354		gf_mx2d_init(t->mat);
1355		str+=2;
1356		while (str[i] == ' ') i++;
1357		if (str[i] == '(') {
1358			i++;
1359			while (str[i] == ' ') i++;
1360			if (str[i] == 's' && str[i+1] == 'v' && str[i+2] == 'g') {
1361				i+=3;
1362				while (str[i] == ' ') i++;
1363                if (str[i] == ',') {
1364                    i++;
1365                } else if (str[i] == ')') {
1366					i++;
1367					return GF_OK;
1368				}
1369				read_chars = svg_parse_number(&(str[i]), &(t->mat.m[2]), 0);
1370                if (!read_chars) {
1371                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient tx in ref transform: %s\n", attribute_content));
1372                    return GF_BAD_PARAM;
1373                }
1374                i += read_chars;
1375				read_chars = svg_parse_number(&(str[i]), &(t->mat.m[5]), 0);
1376                if (!read_chars) {
1377                    GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient ty in ref transform: %s\n", attribute_content));
1378                    return GF_BAD_PARAM;
1379                }
1380                i += read_chars;
1381            } else {
1382				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Unsupported syntax for ref transform attribute"));
1383            }
1384			while (str[i] == ' ') i++;
1385			if (str[i] == ')') i++;
1386			else {
1387                GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
1388			}
1389			return GF_OK;
1390		} else {
1391            GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in ref transform attribute: %s\n", attribute_content));
1392			return GF_BAD_PARAM;
1393		}
1394	} else {
1395		read_chars = gf_svg_parse_transformlist(&t->mat, attribute_content);
1396        if (!read_chars) {
1397            GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error parsing transform list: %s\n", attribute_content));
1398            return GF_BAD_PARAM;
1399        }
1400	}
1401	return GF_OK;
1402}
1403
1404#undef REMOVE_ALLOC
1405
1406#if USE_GF_PATH
1407
1408//#define PARSE_PATH_ONLY
1409
1410static void svg_parse_path(SVG_PathData *path, char *attribute_content)
1411{
1412	char *d = attribute_content;
1413
1414    /* used to detect end of BNF production:
1415    "The processing of the BNF must consume as much of a given BNF production as possible,
1416    stopping at the point when a character is encountered which no longer satisfies the production." */
1417    u32 read_chars = 0;
1418
1419	/* Point used to start a new subpath when the previous subpath is closed */
1420	SVG_Point prev_m_pt;
1421	/* Point used to convert relative 'lower-case commands' into absolute */
1422	SVG_Point rel_ref_pt;
1423	/* Points used to convert S, T commands into C, Q */
1424	SVG_Point orig, ct_orig, ct_end, end;
1425	/* Used by elliptical arcs */
1426	Fixed x_axis_rotation, large_arc_flag, sweep_flag;
1427
1428	char c, prev_c;
1429	u32 i;
1430
1431	if (*d == 0) return;
1432
1433	i = 0;
1434	prev_c = 'M';
1435	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;
1436	while(1) {
1437		while ( (d[i]==' ') || (d[i] =='\t') || (d[i] =='\r') || (d[i] =='\n') ) i++;
1438		c = d[i];
1439		if (! c) break;
1440next_command:
1441		switch (c) {
1442		case 'm':
1443		case 'M':
1444			i++;
1445			read_chars = svg_parse_number(&(d[i]), &(orig.x), 0);
1446            if (!read_chars) return;
1447            i += read_chars;
1448			read_chars = svg_parse_number(&(d[i]), &(orig.y), 0);
1449            if (!read_chars) return;
1450            i += read_chars;
1451			if (c == 'm') {
1452				orig.x += rel_ref_pt.x;
1453				orig.y += rel_ref_pt.y;
1454			}
1455#ifndef PARSE_PATH_ONLY
1456			gf_path_add_move_to(path, orig.x, orig.y);
1457#endif
1458			rel_ref_pt = orig;
1459			prev_m_pt = orig;
1460			/*provision for nextCurveTo when no curve is specified:
1461				"If there is no previous command or if the previous command was not an C, c, S or s,
1462				assume the first control point is coincident with the current point.
1463			*/
1464			ct_orig = orig;
1465			prev_c = c;
1466			break;
1467		case 'L':
1468		case 'l':
1469			i++;
1470			read_chars = svg_parse_number(&(d[i]), &(orig.x), 0);
1471            if (!read_chars) return;
1472            i += read_chars;
1473			read_chars = svg_parse_number(&(d[i]), &(orig.y), 0);
1474            if (!read_chars) return;
1475            i += read_chars;
1476			if (c == 'l') {
1477				orig.x += rel_ref_pt.x;
1478				orig.y += rel_ref_pt.y;
1479			}
1480#ifndef PARSE_PATH_ONLY
1481			gf_path_add_line_to(path, orig.x, orig.y);
1482#endif
1483			rel_ref_pt = orig;
1484			orig = end;
1485			/*cf above*/
1486			ct_orig = orig;
1487			prev_c = c;
1488			break;
1489		case 'H':
1490		case 'h':
1491			i++;
1492			read_chars = svg_parse_number(&(d[i]), &(orig.x), 0);
1493            if (!read_chars) return;
1494            i += read_chars;
1495			if (c == 'h') {
1496				orig.x += rel_ref_pt.x;
1497			}
1498			orig.y = rel_ref_pt.y;
1499#ifndef PARSE_PATH_ONLY
1500			gf_path_add_line_to(path, orig.x, orig.y);
1501#endif
1502			rel_ref_pt.x = orig.x;
1503			orig = end;
1504			/*cf above*/
1505			ct_orig = orig;
1506			prev_c = c;
1507			break;
1508		case 'V':
1509		case 'v':
1510			i++;
1511			read_chars = svg_parse_number(&(d[i]), &(orig.y), 0);
1512            if (!read_chars) return;
1513            i += read_chars;
1514			if (c == 'v') {
1515				orig.y += rel_ref_pt.y;
1516			}
1517			orig.x = rel_ref_pt.x;
1518#ifndef PARSE_PATH_ONLY
1519			gf_path_add_line_to(path, orig.x, orig.y);
1520#endif
1521			rel_ref_pt.y = orig.y;
1522			orig = end;
1523			/*cf above*/
1524			ct_orig 

Large files files are truncated, but you can click here to view the full file