PageRenderTime 10ms CodeModel.GetById 121ms app.highlight 237ms RepoModel.GetById 24ms app.codeStats 3ms

/ext/gpac/src/scenegraph/svg_attributes.c

https://github.com/paulcbetts/yikes
C | 5816 lines | 5425 code | 280 blank | 111 comment | 1405 complexity | 3aeb496d80ffcd900b05cc19ea685d13 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/scenegraph_svg.h>
  29#include <gpac/internal/scenegraph_dev.h>
  30
  31#define DUMP_COORDINATES 1
  32
  33/*
  34	    list of supported events in Tiny 1.2 as of 2005/09/10:
  35		repeat is somehow a special case ...
  36*/
  37u32 gf_dom_event_type_by_name(const char *name)
  38{
  39	if ((name[0]=='o') && (name[1]=='n')) name += 2;
  40
  41	if (!strcmp(name, "abort"))	return GF_EVENT_ABORT;
  42	if (!strcmp(name, "activate"))	return GF_EVENT_ACTIVATE;
  43	if (!strcmp(name, "begin"))		return GF_EVENT_BEGIN;
  44	if (!strcmp(name, "beginEvent"))	return GF_EVENT_BEGIN_EVENT;
  45	if (!strcmp(name, "click"))		return GF_EVENT_CLICK;
  46	if (!strcmp(name, "end"))		return GF_EVENT_END;
  47	if (!strcmp(name, "endEvent"))	return GF_EVENT_END_EVENT;
  48	if (!strcmp(name, "error"))		return GF_EVENT_ERROR;
  49	if (!strcmp(name, "focusin") || !strcmp(name, "DOMFocusIn"))	return GF_EVENT_FOCUSIN;
  50	if (!strcmp(name, "focusout") || !strcmp(name, "DOMFocusOut"))	return GF_EVENT_FOCUSOUT;
  51	if (!strcmp(name, "keydown"))	return GF_EVENT_KEYDOWN;
  52	if (!strcmp(name, "keypress") || !stricmp(name, "accesskey"))	return GF_EVENT_KEYDOWN;
  53	if (!strcmp(name, "keyup"))		return GF_EVENT_KEYUP;
  54	if (!strcmp(name, "load"))		return GF_EVENT_LOAD;
  55	if (!strcmp(name, "SVGLoad"))	return GF_EVENT_LOAD;
  56	if (!strcmp(name, "longkeypress") || !stricmp(name, "longaccesskey"))	return GF_EVENT_LONGKEYPRESS;
  57	if (!strcmp(name, "mousedown")) return GF_EVENT_MOUSEDOWN;
  58	if (!strcmp(name, "mousemove")) return GF_EVENT_MOUSEMOVE;
  59	if (!strcmp(name, "mouseout"))	return GF_EVENT_MOUSEOUT;
  60	if (!strcmp(name, "mouseover")) return GF_EVENT_MOUSEOVER;
  61	if (!strcmp(name, "mouseup"))	return GF_EVENT_MOUSEUP;
  62	if (!strcmp(name, "repeat"))	return GF_EVENT_REPEAT;
  63	if (!strcmp(name, "repeatEvent"))	return GF_EVENT_REPEAT_EVENT;
  64	if (!strcmp(name, "resize"))	return GF_EVENT_RESIZE;
  65	if (!strcmp(name, "scroll"))	return GF_EVENT_SCROLL;
  66	if (!strcmp(name, "textInput"))	return GF_EVENT_TEXTINPUT;
  67	if (!strcmp(name, "unload"))	return GF_EVENT_UNLOAD;
  68	if (!strcmp(name, "zoom"))		return GF_EVENT_ZOOM;
  69
  70	/*LASeR events*/
  71	if (!strcmp(name, "activatedEvent"))	return GF_EVENT_ACTIVATED;
  72	if (!strcmp(name, "deactivatedEvent"))	return GF_EVENT_DEACTIVATED;
  73	if (!strcmp(name, "executionTime"))	return GF_EVENT_EXECUTION_TIME;
  74	if (!strcmp(name, "pause"))	return GF_EVENT_PAUSE;
  75	if (!strcmp(name, "pausedEvent"))	return GF_EVENT_PAUSED_EVENT;
  76	if (!strcmp(name, "play"))	return GF_EVENT_PLAY;
  77	if (!strcmp(name, "repeatKey"))	return GF_EVENT_REPEAT_KEY;
  78	if (!strcmp(name, "resumedEvent"))	return GF_EVENT_RESUME_EVENT;
  79	if (!strcmp(name, "shortAccessKey"))	return GF_EVENT_SHORT_ACCESSKEY;
  80	/*LASeR unofficial events*/
  81	if (!strcmp(name, "battery"))		return GF_EVENT_BATTERY;
  82	if (!strcmp(name, "cpu"))		return GF_EVENT_CPU;
  83	GF_LOG(GF_LOG_WARNING, GF_LOG_COMPOSE, ("[DOM Events] Unknown event found \"%s\"\n", name));
  84	return GF_EVENT_UNKNOWN;
  85}
  86
  87const char *gf_dom_event_get_name(u32 type)
  88{
  89
  90	switch (type) {
  91	case GF_EVENT_ABORT: return "abort";
  92	case GF_EVENT_ACTIVATE: return "activate";
  93	case GF_EVENT_BEGIN: return "begin";
  94	case GF_EVENT_BEGIN_EVENT: return "beginEvent";
  95	case GF_EVENT_CLICK: return "click";
  96	case GF_EVENT_END: return "end";
  97	case GF_EVENT_END_EVENT: return "endEvent";
  98	case GF_EVENT_ERROR: return "error";
  99	case GF_EVENT_FOCUSIN: return "focusin";
 100	case GF_EVENT_FOCUSOUT: return "focusout";
 101	case GF_EVENT_KEYDOWN: return "keydown";
 102	case GF_EVENT_KEYUP: return "keyup";
 103	case GF_EVENT_LOAD: return "load";
 104	case GF_EVENT_LONGKEYPRESS: return "longaccesskey";
 105	case GF_EVENT_MOUSEDOWN: return "mousedown";
 106	case GF_EVENT_MOUSEMOVE: return "mousemove";
 107	case GF_EVENT_MOUSEOUT: return "mouseout";
 108	case GF_EVENT_MOUSEOVER: return "mouseover";
 109	case GF_EVENT_MOUSEUP: return "mouseup";
 110	case GF_EVENT_REPEAT: return "repeat";
 111	case GF_EVENT_REPEAT_EVENT: return "repeatEvent";
 112	case GF_EVENT_RESIZE: return "resize";
 113	case GF_EVENT_SCROLL: return "scroll";
 114	case GF_EVENT_TEXTINPUT: return "textInput";
 115	case GF_EVENT_UNLOAD: return "unload";
 116	case GF_EVENT_ZOOM: return "zoom";
 117
 118	/*LASeR events*/
 119	case GF_EVENT_ACTIVATED: return "activatedEvent";
 120	case GF_EVENT_DEACTIVATED: return "deactivatedEvent";
 121	case GF_EVENT_EXECUTION_TIME: return "executionTime";
 122	case GF_EVENT_PAUSE: return "pause";
 123	case GF_EVENT_PAUSED_EVENT: return "pausedEvent";
 124	case GF_EVENT_PLAY: return "play";
 125	case GF_EVENT_REPEAT_KEY: return "repeatKey";
 126	case GF_EVENT_RESUME_EVENT: return "resumedEvent";
 127	case GF_EVENT_SHORT_ACCESSKEY: return "shortAccessKey";
 128	/*LASeR unofficial events*/
 129	case GF_EVENT_BATTERY: return "battery";
 130	case GF_EVENT_CPU: return "cpu";
 131
 132	default: return "unknown";
 133	}
 134}
 135
 136static const struct predef_keyid {u32 key_code;  const char *name; } predefined_key_identifiers[] = 
 137{
 138	{ GF_KEY_ACCEPT, "Accept" },
 139	{ GF_KEY_AGAIN, "Again" },
 140	{ GF_KEY_ALLCANDIDATES, "AllCandidates" },
 141	{ GF_KEY_ALPHANUM, "Alphanumeric" },
 142	{ GF_KEY_ALT, "Alt" },
 143	{ GF_KEY_ALTGRAPH, "AltGraph" },
 144	{ GF_KEY_APPS, "Apps" },
 145	{ GF_KEY_ATTN, "Attn" },
 146	{ GF_KEY_BROWSERBACK, "BrowserBack" },
 147	{ GF_KEY_BROWSERFAVORITES, "BrowserFavorites" },
 148	{ GF_KEY_BROWSERFORWARD, "BrowserForward" },
 149	{ GF_KEY_BROWSERHOME, "BrowserHome" },
 150	{ GF_KEY_BROWSERREFRESH, "BrowserRefresh" },
 151	{ GF_KEY_BROWSERSEARCH, "BrowserSearch" },
 152	{ GF_KEY_BROWSERSTOP, "BrowserStop" },
 153	{ GF_KEY_CAPSLOCK, "CapsLock" },
 154	{ GF_KEY_CLEAR, "Clear" },
 155	{ GF_KEY_CODEINPUT, "CodeInput" },
 156	{ GF_KEY_COMPOSE, "Compose" },
 157	{ GF_KEY_CONTROL, "Control" },
 158	{ GF_KEY_CRSEL, "Crsel" },
 159	{ GF_KEY_CONVERT, "Convert" },
 160	{ GF_KEY_COPY, "Copy"  },
 161	{ GF_KEY_CUT, "Cut" },
 162	{ GF_KEY_DOWN, "Down" },
 163	{ GF_KEY_END, "End" },
 164	{ GF_KEY_ENTER, "Enter" },
 165	{ GF_KEY_ERASEEOF, "EraseEof" },
 166	{ GF_KEY_EXECUTE, "Execute" },
 167	{ GF_KEY_EXSEL, "Exsel" },
 168	{ GF_KEY_F1, "F1" },
 169	{ GF_KEY_F2, "F2" },
 170	{ GF_KEY_F3, "F3" },
 171	{ GF_KEY_F4, "F4" },
 172	{ GF_KEY_F5, "F5" },
 173	{ GF_KEY_F6, "F6" },
 174	{ GF_KEY_F7, "F7" },
 175	{ GF_KEY_F8, "F8" },
 176	{ GF_KEY_F9, "F9" },
 177	{ GF_KEY_F10, "F10" },
 178	{ GF_KEY_F11, "F11" },
 179	{ GF_KEY_F12, "F12" },
 180	{ GF_KEY_F13, "F13" },
 181	{ GF_KEY_F14, "F14" },
 182	{ GF_KEY_F15, "F15" },
 183	{ GF_KEY_F16, "F16" },
 184	{ GF_KEY_F17, "F17" },
 185	{ GF_KEY_F18, "F18" },
 186	{ GF_KEY_F19, "F19" },
 187	{ GF_KEY_F20, "F20" },
 188	{ GF_KEY_F21, "F21" },
 189	{ GF_KEY_F22, "F22" },
 190	{ GF_KEY_F23, "F23" },
 191	{ GF_KEY_F24, "F24" },
 192	{ GF_KEY_FINALMODE, "FinalMode" },
 193	{ GF_KEY_FIND, "Find" },
 194	{ GF_KEY_FULLWIDTH, "FullWidth" },
 195	{ GF_KEY_HALFWIDTH, "HalfWidth" },
 196	{ GF_KEY_HANGULMODE, "HangulMode" },
 197	{ GF_KEY_HANJAMODE, "HanjaMode"   },
 198	{ GF_KEY_HELP, "Help" },
 199	{ GF_KEY_HIRAGANA, "Hiragana" },
 200	{ GF_KEY_HOME, "Home" },
 201	{ GF_KEY_INSERT, "Insert" },
 202	{ GF_KEY_JAPANESEHIRAGANA, "JapaneseHiragana" },
 203	{ GF_KEY_JAPANESEKATAKANA, "JapaneseKatakana" },
 204	{ GF_KEY_JAPANESEROMAJI, "JapaneseRomaji" },
 205	{ GF_KEY_JUNJAMODE, "JunjaMode" },
 206	{ GF_KEY_KANAMODE, "KanaMode"   },
 207	{ GF_KEY_KANJIMODE, "KanjiMode" },
 208	{ GF_KEY_KATAKANA, "Katakana"   },
 209	{ GF_KEY_LAUNCHAPPLICATION1, "LaunchApplication1" },
 210	{ GF_KEY_LAUNCHAPPLICATION2, "LaunchApplication2" },
 211	{ GF_KEY_LAUNCHMAIL, "LaunchMail" },
 212	{ GF_KEY_LEFT, "Left" },
 213	{ GF_KEY_META, "Meta" },
 214	{ GF_KEY_MEDIANEXTTRACK, "MediaNextTrack" },
 215	{ GF_KEY_MEDIAPLAYPAUSE, "MediaPlayPause" },
 216	{ GF_KEY_MEDIAPREVIOUSTRACK, "MediaPreviousTrack" },
 217	{ GF_KEY_MEDIASTOP, "MediaStop" },
 218	{ GF_KEY_MODECHANGE, "ModeChange" },
 219	{ GF_KEY_NONCONVERT, "Nonconvert" },
 220	{ GF_KEY_NUMLOCK, "NumLock" },
 221	{ GF_KEY_PAGEDOWN, "PageDown" },
 222	{ GF_KEY_PAGEUP, "PageUp" },
 223	{ GF_KEY_PASTE, "Paste" },
 224	{ GF_KEY_PAUSE, "Pause" },
 225	{ GF_KEY_PLAY, "Play" },
 226	{ GF_KEY_PREVIOUSCANDIDATE, "PreviousCandidate" },
 227	{ GF_KEY_PRINTSCREEN, "PrintScreen" },
 228	{ GF_KEY_PROCESS, "Process" },
 229	{ GF_KEY_PROPS, "Props" },
 230	{ GF_KEY_RIGHT, "Right" },
 231	{ GF_KEY_ROMANCHARACTERS, "RomanCharacters" },
 232	{ GF_KEY_SCROLL, "Scroll" },
 233	{ GF_KEY_SELECT, "Select" },
 234	{ GF_KEY_SELECTMEDIA, "SelectMedia" },
 235	{ GF_KEY_SHIFT, "Shift" },
 236	{ GF_KEY_STOP, "Stop" },
 237	{ GF_KEY_UP, "Up" },
 238	{ GF_KEY_UNDO, "Undo" },
 239	{ GF_KEY_VOLUMEDOWN, "VolumeDown" },
 240	{ GF_KEY_VOLUMEMUTE, "VolumeMute" },
 241	{ GF_KEY_VOLUMEUP, "VolumeUp" },
 242	{ GF_KEY_WIN, "Win" },
 243	{ GF_KEY_ZOOM, "Zoom" },
 244	{ GF_KEY_BACKSPACE, "U+0008" },
 245	{ GF_KEY_TAB, "U+0009" },
 246	{ GF_KEY_CANCEL, "U+0018" },
 247	{ GF_KEY_ESCAPE, "U+001B" },
 248	{ GF_KEY_SPACE, "U+0020" },
 249	{ GF_KEY_EXCLAMATION, "U+0021" },
 250	{ GF_KEY_QUOTATION, "U+0022" },
 251	{ GF_KEY_NUMBER, "U+0023" },
 252	{ GF_KEY_DOLLAR, "U+0024" },
 253	{ GF_KEY_AMPERSAND, "U+0026" },
 254	{ GF_KEY_APOSTROPHE, "U+0027" },
 255	{ GF_KEY_LEFTPARENTHESIS, "U+0028" },
 256	{ GF_KEY_RIGHTPARENTHESIS, "U+0029" },
 257	{ GF_KEY_STAR, "U+002A" },
 258	{ GF_KEY_PLUS, "U+002B" },
 259	{ GF_KEY_COMMA, "U+002C" },
 260	{ GF_KEY_HYPHEN, "U+002D" },
 261	{ GF_KEY_FULLSTOP, "U+002E" },
 262	{ GF_KEY_SLASH, "U+002F" },
 263	{ GF_KEY_0, "U+0030" },
 264	{ GF_KEY_1, "U+0031" },
 265	{ GF_KEY_2, "U+0032" },
 266	{ GF_KEY_3, "U+0033" },
 267	{ GF_KEY_4, "U+0034" },
 268	{ GF_KEY_5, "U+0035" },
 269	{ GF_KEY_6, "U+0036" },
 270	{ GF_KEY_7, "U+0037" },
 271	{ GF_KEY_8, "U+0038" },
 272	{ GF_KEY_9, "U+0039" },
 273	{ GF_KEY_COLON, "U+003A" },
 274	{ GF_KEY_SEMICOLON, "U+003B" },
 275	{ GF_KEY_LESSTHAN, "U+003C" },
 276	{ GF_KEY_EQUALS, "U+003D" },
 277	{ GF_KEY_GREATERTHAN, "U+003E" },
 278	{ GF_KEY_QUESTION, "U+003F" },
 279	{ GF_KEY_AT, "U+0040" },
 280	{ GF_KEY_A, "U+0041" },
 281	{ GF_KEY_B, "U+0042" },
 282	{ GF_KEY_C, "U+0043" },
 283	{ GF_KEY_D, "U+0044" },
 284	{ GF_KEY_E, "U+0045" },
 285	{ GF_KEY_F, "U+0046" },
 286	{ GF_KEY_G, "U+0047" },
 287	{ GF_KEY_H, "U+0048" },
 288	{ GF_KEY_I, "U+0049" },
 289	{ GF_KEY_J, "U+004A" },
 290	{ GF_KEY_K, "U+004B" },
 291	{ GF_KEY_L, "U+004C" },
 292	{ GF_KEY_M, "U+004D" },
 293	{ GF_KEY_N, "U+004E" },
 294	{ GF_KEY_O, "U+004F" },
 295	{ GF_KEY_P, "U+0050" },
 296	{ GF_KEY_Q, "U+0051" },
 297	{ GF_KEY_R, "U+0052" },
 298	{ GF_KEY_S, "U+0053" },
 299	{ GF_KEY_T, "U+0054" },
 300	{ GF_KEY_U, "U+0055" },
 301	{ GF_KEY_V, "U+0056" },
 302	{ GF_KEY_W, "U+0057" },
 303	{ GF_KEY_X, "U+0058" },
 304	{ GF_KEY_Y, "U+0059" },
 305	{ GF_KEY_Z, "U+005A" },
 306	{ GF_KEY_LEFTSQUAREBRACKET, "U+005B" },
 307	{ GF_KEY_BACKSLASH, "U+005C" },
 308	{ GF_KEY_RIGHTSQUAREBRACKET, "U+005D" },
 309	{ GF_KEY_CIRCUM, "U+005E" },
 310	{ GF_KEY_UNDERSCORE, "U+005F" },
 311	{ GF_KEY_GRAVEACCENT, "U+0060" },
 312	{ GF_KEY_LEFTCURLYBRACKET, "U+007B" },
 313	{ GF_KEY_PIPE, "U+007C" },
 314	{ GF_KEY_RIGHTCURLYBRACKET, "U+007D" },
 315	{ GF_KEY_DEL, "U+007F" },
 316	{ GF_KEY_INVERTEXCLAMATION, "U+00A1" },
 317	{ GF_KEY_DEADGRAVE, "U+0300" },
 318	{ GF_KEY_DEADEACUTE, "U+0301" },
 319	{ GF_KEY_DEADCIRCUM, "U+0302" },
 320	{ GF_KEY_DEADTILDE, "U+0303" },
 321	{ GF_KEY_DEADMACRON, "U+0304" },
 322	{ GF_KEY_DEADBREVE, "U+0306" },
 323	{ GF_KEY_DEADABOVEDOT, "U+0307" },
 324	{ GF_KEY_DEADDIARESIS, "U+0308" },
 325	{ GF_KEY_DEADRINGABOVE, "U+030A" },
 326	{ GF_KEY_DEADDOUBLEACUTE, "U+030B" },
 327	{ GF_KEY_DEADCARON, "U+030C" },
 328	{ GF_KEY_DEADCEDILLA, "U+0327" },
 329	{ GF_KEY_DEADOGONEK, "U+0328" },
 330	{ GF_KEY_DEADIOTA, "U+0345" },
 331	{ GF_KEY_EURO, "U+20AC" },
 332	{ GF_KEY_DEADVOICESOUND, "U+3099" },
 333	{ GF_KEY_DEADSEMIVOICESOUND, "U+309A" }
 334};
 335const char *gf_dom_get_key_name(u32 key_identifier)
 336{
 337	u32 count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid);
 338	if (!key_identifier || count<=key_identifier) return "Unknown";
 339	return predefined_key_identifiers[key_identifier-1].name;
 340}
 341
 342
 343u32 gf_dom_get_key_type(char *key_name)
 344{
 345	if (strlen(key_name) == 1) {
 346		char c[2];
 347		c[0] = key_name[0];
 348		c[1] = 0;
 349		strupr(c);
 350		if (c[0] >= 'A' && c[0] <= 'Z') 
 351			return (GF_KEY_A + (c[0] - 'A') );
 352		
 353		if (c[0] >= '0' && c[0] <= '9')
 354			return ( GF_KEY_0 + (c[0] - '0') );
 355		
 356		switch (c[0]) {
 357		case '@': return GF_KEY_AT;
 358		case '*': return GF_KEY_STAR;
 359		case '#': return GF_KEY_NUMBER;
 360		case ' ': return GF_KEY_SPACE;
 361		case '!': return GF_KEY_EXCLAMATION;
 362		case '"': return GF_KEY_QUOTATION;
 363		case '$': return GF_KEY_DOLLAR;
 364		case '&': return GF_KEY_AMPERSAND;
 365		case '\'': return GF_KEY_APOSTROPHE;
 366		case '(': return GF_KEY_LEFTPARENTHESIS;
 367		case ')': return GF_KEY_RIGHTPARENTHESIS;
 368		case '+': return GF_KEY_PLUS;
 369		case ',': return GF_KEY_COMMA;
 370		case '-': return GF_KEY_HYPHEN;
 371		case '.': return GF_KEY_FULLSTOP;
 372		case '/': return GF_KEY_SLASH;
 373		case ':': return GF_KEY_COLON;
 374		case ';': return GF_KEY_SEMICOLON;
 375		case '<': return GF_KEY_LESSTHAN;
 376		case '=': return GF_KEY_EQUALS;
 377		case '>': return GF_KEY_GREATERTHAN;
 378		case '?': return GF_KEY_QUESTION;
 379		case '[': return GF_KEY_LEFTSQUAREBRACKET;
 380		case '\\': return GF_KEY_BACKSLASH;
 381		case ']': return GF_KEY_RIGHTSQUAREBRACKET;
 382		case '^': return GF_KEY_CIRCUM;
 383		case '_': return GF_KEY_UNDERSCORE;
 384		case '`': return GF_KEY_GRAVEACCENT;
 385		case '{': return GF_KEY_LEFTCURLYBRACKET;
 386		case '|': return GF_KEY_PIPE;
 387		case '}': return GF_KEY_RIGHTCURLYBRACKET;
 388		case '¡': return GF_KEY_INVERTEXCLAMATION;
 389		default: return GF_KEY_UNIDENTIFIED;
 390		}
 391	} else {
 392		u32 i, count;
 393		count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid);
 394		for (i=0; i<count; i++) {
 395			if (!stricmp(key_name, predefined_key_identifiers[i].name)) {
 396				return predefined_key_identifiers[i].key_code;
 397			}
 398		}
 399		return GF_KEY_UNIDENTIFIED;
 400	}
 401}
 402
 403/* Basic SVG datatype parsing functions */
 404static const struct predef_col { const char *name; u8 r; u8 g; u8 b; } predefined_colors[] = 
 405{
 406	{"aliceblue",240, 248, 255},
 407	{"antiquewhite",250, 235, 215},
 408	{"aqua", 0, 255, 255},
 409	{"aquamarine",127, 255, 212},
 410	{"azure",240, 255, 255},
 411	{"beige",245, 245, 220},
 412	{"bisque",255, 228, 196},
 413	{"black", 0, 0, 0},
 414	{"blanchedalmond",255, 235, 205},
 415	{"blue", 0, 0, 255},
 416	{"blueviolet",138, 43, 226},
 417	{"brown",165, 42, 42},
 418	{"burlywood",222, 184, 135},
 419	{"cadetblue", 95, 158, 160},
 420	{"chartreuse",127, 255, 0},
 421	{"chocolate",210, 105, 30},
 422	{"coral",255, 127, 80},
 423	{"lightpink",255, 182, 193},
 424	{"lightsalmon",255, 160, 122},
 425	{"lightseagreen", 32, 178, 170},
 426	{"lightskyblue",135, 206, 250},
 427	{"lightslategray",119, 136, 153},
 428	{"lightslategrey",119, 136, 153},
 429	{"lightsteelblue",176, 196, 222},
 430	{"lightyellow",255, 255, 224},
 431	{"lime", 0, 255, 0},
 432	{"limegreen", 50, 205, 50},
 433	{"linen",250, 240, 230},
 434	{"magenta",255, 0, 255},
 435	{"maroon",128, 0, 0},
 436	{"mediumaquamarine",102, 205, 170},
 437	{"mediumblue", 0, 0, 205},
 438	{"mediumorchid",186, 85, 211},
 439	{"cornflowerblue",100, 149, 237},
 440	{"cornsilk",255, 248, 220},
 441	{"crimson",220, 20, 60},
 442	{"cyan", 0, 255, 255},
 443	{"darkblue", 0, 0, 139},
 444	{"darkcyan", 0, 139, 139},
 445	{"darkgoldenrod",184, 134, 11},
 446	{"darkgray",169, 169, 169},
 447	{"darkgreen", 0, 100, 0},
 448	{"darkgrey",169, 169, 169},
 449	{"darkkhaki",189, 183, 107},
 450	{"darkmagenta",139, 0, 139},
 451	{"darkolivegreen", 85, 107, 47},
 452	{"darkorange",255, 140, 0},
 453	{"darkorchid",153, 50, 204},
 454	{"darkred",139, 0, 0},
 455	{"darksalmon",233, 150, 122},
 456	{"darkseagreen",143, 188, 143},
 457	{"darkslateblue", 72, 61, 139},
 458	{"darkslategray", 47, 79, 79},
 459	{"darkslategrey", 47, 79, 79},
 460	{"darkturquoise", 0, 206, 209},
 461	{"darkviolet",148, 0, 211},
 462	{"deeppink",255, 20, 147},
 463	{"deepskyblue", 0, 191, 255},
 464	{"dimgray",105, 105, 105},
 465	{"dimgrey",105, 105, 105},
 466	{"dodgerblue", 30, 144, 255},
 467	{"firebrick",178, 34, 34},
 468	{"floralwhite",255, 250, 240},
 469	{"forestgreen", 34, 139, 34},
 470	{"fuchsia",255, 0, 255},
 471	{"gainsboro",220, 220, 220},
 472	{"ghostwhite",248, 248, 255},
 473	{"gold",255, 215, 0},
 474	{"goldenrod",218, 165, 32},
 475	{"gray",128, 128, 128},
 476	{"grey",128, 128, 128},
 477	{"green", 0, 128, 0},
 478	{"greenyellow",173, 255, 47},
 479	{"honeydew",240, 255, 240},
 480	{"hotpink",255, 105, 180},
 481	{"indianred",205, 92, 92},
 482	{"indigo", 75, 0, 130},
 483	{"ivory",255, 255, 240},
 484	{"khaki",240, 230, 140},
 485	{"lavender",230, 230, 25},
 486	{"lavenderblush",255, 240, 245},
 487	{"mediumpurple",147, 112, 219},
 488	{"mediumseagreen", 60, 179, 113},
 489	{"mediumslateblue",123, 104, 238},
 490	{"mediumspringgreen", 0, 250, 154},
 491	{"mediumturquoise", 72, 209, 204},
 492	{"mediumvioletred",199, 21, 133},
 493	{"midnightblue", 25, 25, 112},
 494	{"mintcream",245, 255, 250},
 495	{"mistyrose",255, 228, 225},
 496	{"moccasin",255, 228, 181},
 497	{"navajowhite",255, 222, 173},
 498	{"navy", 0, 0, 128},
 499	{"oldlace",253, 245, 230},
 500	{"olive",128, 128, 0},
 501	{"olivedrab",107, 142, 35},
 502	{"orange",255, 165, 0},
 503	{"orangered",255, 69, 0},
 504	{"orchid",218, 112, 214},
 505	{"palegoldenrod",238, 232, 170},
 506	{"palegreen",152, 251, 152},
 507	{"paleturquoise",175, 238, 238},
 508	{"palevioletred",219, 112, 147},
 509	{"papayawhip",255, 239, 213},
 510	{"peachpuff",255, 218, 185},
 511	{"peru",205, 133, 63},
 512	{"pink",255, 192, 203},
 513	{"plum",221, 160, 221},
 514	{"powderblue",176, 224, 230},
 515	{"purple",128, 0, 128},
 516	{"red",255, 0, 0},
 517	{"rosybrown",188, 143, 143},
 518	{"royalblue", 65, 105, 225},
 519	{"saddlebrown",139, 69, 19},
 520	{"salmon",250, 128, 114},
 521	{"sandybrown",244, 164, 96},
 522	{"seagreen", 46, 139, 87},
 523	{"seashell",255, 245, 238},
 524	{"sienna",160, 82, 45},
 525	{"silver",192, 192, 192},
 526	{"skyblue",135, 206, 235},
 527	{"slateblue",106, 90, 205},
 528	{"slategray",112, 128, 144},
 529	{"slategrey",112, 128, 144},
 530	{"snow",255, 250, 250},
 531	{"springgreen", 0, 255, 127},
 532	{"steelblue", 70, 130, 180},
 533	{"tan",210, 180, 140},
 534	{"teal", 0, 128, 128},
 535	{"lawngreen",124, 252, 0},
 536	{"lemonchiffon",255, 250, 205},
 537	{"lightblue",173, 216, 230},
 538	{"lightcoral",240, 128, 128},
 539	{"lightcyan",224, 255, 255},
 540	{"lightgoldenrodyellow",250, 250, 210},
 541	{"lightgray",211, 211, 211},
 542	{"lightgreen",144, 238, 144},
 543	{"lightgrey",211, 211, 211},
 544	{"thistle",216, 191, 216},
 545	{"tomato",255, 99, 71},
 546	{"turquoise", 64, 224, 208},
 547	{"violet",238, 130, 238},
 548	{"wheat",245, 222, 179},
 549	{"white",255, 255, 255},
 550	{"whitesmoke",245, 245, 245},
 551	{"yellow",255, 255, 0},
 552	{"yellowgreen",154, 205, 50}
 553
 554};
 555
 556
 557/* Basic SVG datatype parsing functions */
 558static const struct sys_col { const char *name; u8 type; } system_colors[] = 
 559{
 560	{"ActiveBorder", SVG_COLOR_ACTIVE_BORDER},
 561	{"ActiveCaption", SVG_COLOR_ACTIVE_CAPTION},
 562	{"AppWorkspace", SVG_COLOR_APP_WORKSPACE},
 563	{"Background", SVG_COLOR_BACKGROUND},
 564	{"ButtonFace", SVG_COLOR_BUTTON_FACE},
 565	{"ButtonHighlight", SVG_COLOR_BUTTON_HIGHLIGHT},
 566	{"ButtonShadow", SVG_COLOR_BUTTON_SHADOW},
 567	{"ButtonText", SVG_COLOR_BUTTON_TEXT},
 568	{"CaptionText", SVG_COLOR_CAPTION_TEXT},
 569	{"GrayText", SVG_COLOR_GRAY_TEXT},
 570	{"Highlight", SVG_COLOR_HIGHLIGHT},
 571	{"HighlightText", SVG_COLOR_HIGHLIGHT_TEXT},
 572	{"InactiveBorder", SVG_COLOR_INACTIVE_BORDER},
 573	{"InactiveCaption", SVG_COLOR_INACTIVE_CAPTION},
 574	{"InactiveCaptionText", SVG_COLOR_INACTIVE_CAPTION_TEXT},
 575	{"InfoBackground", SVG_COLOR_INFO_BACKGROUND},
 576	{"InfoText", SVG_COLOR_INFO_TEXT},
 577	{"Menu", SVG_COLOR_MENU},
 578	{"MenuText", SVG_COLOR_MENU_TEXT},
 579	{"Scrollbar", SVG_COLOR_SCROLLBAR},
 580	{"ThreeDDarkShadow", SVG_COLOR_3D_DARK_SHADOW},
 581	{"ThreeDFace", SVG_COLOR_3D_FACE},
 582	{"ThreeDHighlight", SVG_COLOR_3D_HIGHLIGHT},
 583	{"ThreeDLightShadow", SVG_COLOR_3D_LIGHT_SHADOW},
 584	{"ThreeDShadow", SVG_COLOR_3D_SHADOW},
 585	{"Window", SVG_COLOR_WINDOW},
 586	{"WindowFrame", SVG_COLOR_WINDOW_FRAME},
 587	{"WindowText", SVG_COLOR_WINDOW_TEXT},
 588};
 589
 590/* parses an color from a named color HTML or CSS 2 */
 591static void svg_parse_named_color(SVG_Color *col, char *attribute_content)
 592{
 593	u32 i, count;
 594	count = sizeof(predefined_colors) / sizeof(struct predef_col);
 595	for (i=0; i<count; i++) {
 596		if (!strcmp(attribute_content, predefined_colors[i].name)) {
 597			col->red = INT2FIX(predefined_colors[i].r) / 255;
 598			col->green = INT2FIX(predefined_colors[i].g) / 255;
 599			col->blue = INT2FIX(predefined_colors[i].b) / 255;
 600			col->type = SVG_COLOR_RGBCOLOR;
 601			return;
 602		}
 603	}
 604	count = sizeof(system_colors) / sizeof(struct sys_col);
 605	for (i=0; i<count; i++) {
 606		if (!strcmp(attribute_content, system_colors[i].name)) {
 607			col->type = system_colors[i].type;
 608			return;
 609		}
 610	}
 611}
 612
 613const char *gf_svg_get_system_paint_server_name(u32 paint_type)
 614{
 615	u32 i, count;
 616	count = sizeof(system_colors) / sizeof(struct sys_col);
 617	for (i=0; i<count; i++) {
 618		if (paint_type == system_colors[i].type) return system_colors[i].name;
 619	}
 620	return "undefined";
 621}
 622
 623u32 gf_svg_get_system_paint_server_type(const char *name)
 624{
 625	u32 i, count;
 626	count = sizeof(system_colors) / sizeof(struct sys_col);
 627	for (i=0; i<count; i++) {
 628		if (!strcmp(name, system_colors[i].name)) return system_colors[i].type;
 629	}
 630	return 0;
 631}
 632
 633/* Reads an SVG Color 
 634   either #RRGGBB, #RGB, rgb(r,g,b) in [0,255] , colorname, or 'r g b' in [0,1]
 635   ignores any space, comma, semi-column before and any space after
 636   TODO: 
 637	transform the char into char and duplicate the input, instead of modifying it
 638		be more robust to errors in color description ex rgb(0 0 0)
 639*/
 640static void svg_parse_color(SVG_Color *col, char *attribute_content)
 641{
 642	char *str = attribute_content;
 643	while (str[strlen(attribute_content)-1] == ' ') str[strlen(attribute_content)-1] = 0;
 644	while (*str != 0 && (*str == ' ' || *str == ',' || *str == ';')) str++;
 645
 646	if (!strcmp(str, "currentColor")) {
 647		col->type = SVG_COLOR_CURRENTCOLOR;
 648		return;
 649	} else if (!strcmp(str, "inherit")) {
 650		col->type = SVG_COLOR_INHERIT;
 651		return;
 652	} else if (str[0]=='#') {
 653		u32 val;
 654		sscanf(str+1, "%x", &val);
 655		if (strlen(str) == 7) {
 656			col->red = INT2FIX((val>>16) & 0xFF) / 255;
 657			col->green = INT2FIX((val>>8) & 0xFF) / 255;
 658			col->blue = INT2FIX(val & 0xFF) / 255;
 659		} else {
 660			col->red = INT2FIX((val>>8) & 0xF) / 15;
 661			col->green = INT2FIX((val>>4) & 0xF) / 15;
 662			col->blue = INT2FIX(val & 0xF) / 15;
 663		}
 664		col->type = SVG_COLOR_RGBCOLOR;
 665	} else if (strstr(str, "rgb(") || strstr(str, "RGB(")) {
 666		Float _val;
 667		u8 is_percentage= 0;
 668		if (strstr(str, "%")) is_percentage = 1;
 669		str = strstr(str, "(");
 670		str++;
 671		sscanf(str, "%f", &_val); col->red = FLT2FIX(_val);
 672		str = strstr(str, ",");
 673		str++;
 674		sscanf(str, "%f", &_val); col->green = FLT2FIX(_val);
 675		str = strstr(str, ",");
 676		str++;
 677		sscanf(str, "%f", &_val); col->blue = FLT2FIX(_val);
 678		if (is_percentage) {
 679			col->red /= 100;
 680			col->green /= 100;
 681			col->blue /= 100;
 682		} else {
 683			col->red /= 255;
 684			col->green /= 255;
 685			col->blue /= 255;
 686		}
 687		col->type = SVG_COLOR_RGBCOLOR;
 688	} else if ((str[0] >= 'a' && str[0] <= 'z')
 689		|| (str[0] >= 'A' && str[0] <= 'Z')) {
 690		svg_parse_named_color(col, str);
 691	} else {
 692		Float _r, _g, _b;
 693		sscanf(str, "%f %f %f", &_r, &_g, &_b);
 694		col->red = FLT2FIX(_r);
 695		col->green = FLT2FIX(_g);
 696		col->blue = FLT2FIX(_b);
 697		col->type = SVG_COLOR_RGBCOLOR;
 698	}
 699}
 700
 701/* 
 702	Reads a float in scientific notation 
 703		trims any space, comma, semi-column before or after
 704		reads an optional + or -
 705		then reads a digit between 0 and 9
 706		optionally followed by an '.' and digits between 0 and 9
 707		optionally followed by e or E and digits between 0 and 9
 708	Returns the number of char read in d 
 709*/
 710static u32 svg_parse_float(char *d, Fixed *f, Bool is_angle) 
 711{
 712	Bool is_negative = 0;
 713	Float _val = 0;
 714	u32 i = 0;
 715	while ((d[i] != 0) && strchr(" ,;\r\n\t", d[i])) i++;
 716	if (!d[i]) goto end;
 717	if (d[i] == '+') i++;
 718	if (d[i] == '-') {
 719		is_negative = 1;
 720		i++;
 721	}
 722	while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) {
 723		_val = _val*10 + (d[i]-'0');
 724		i++;
 725	}
 726	if (!d[i]) goto end;
 727	if (d[i] == '.') {
 728		u32 nb_digit_after = 0;
 729		i++;
 730		while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) {
 731			_val = _val*10 + (d[i]-'0');
 732			nb_digit_after++;
 733			i++;
 734		}
 735		_val /= (Float)pow(10,nb_digit_after);
 736		if (!d[i]) goto end;
 737	}
 738	if (d[i] == 'e' || d[i] == 'E') {
 739		u32 exp = 0;
 740		i++;
 741		if (d[i] == '+' || d[i] == '-') i++;
 742		while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) {
 743			exp = exp*10 + (d[i]-'0');
 744			i++;
 745		}
 746		_val *= (Float)pow(10, exp);
 747	}
 748end:
 749	if (is_negative) _val *= -1;
 750	//_val = atof(d);
 751	if (is_angle) {
 752		_val/=180;
 753		(*f) = gf_mulfix(FLT2FIX(_val), GF_PI);
 754	} else {
 755		(*f) = FLT2FIX(_val);
 756	}
 757	while (d[i] != 0 && (d[i] == ' ' || d[i] == ',' || d[i] == ';')) i++;
 758	return i;
 759}
 760
 761/*
 762   Parse an Offset Value, i.e +/- Clock Value
 763*/
 764static void svg_parse_clock_value(char *d, Double *clock_value) 
 765{
 766	char *tmp;
 767	s32 sign = 1;
 768	if (d[0] == '+') d++;
 769	if (d[0] == '-') { sign = -1; d++; }
 770	while (*d == ' ') d++;
 771
 772	if ((tmp = strchr(d, ':'))) {
 773		/* Full or Partial Clock value */
 774		tmp++;
 775		if ((tmp = strchr(tmp, ':'))) {
 776			/* Full Clock value : hh:mm:ss(.frac) */
 777			u32 hours;
 778			u32 minutes;
 779			Float seconds;
 780			sscanf(d, "%d:%d:%f", &hours, &minutes, &seconds);
 781			*clock_value = hours*3600 + minutes*60 + seconds;
 782		} else {
 783			/* Partial Clock value : mm:ss(.frac) */
 784			s32 minutes;
 785			Float seconds;
 786			sscanf(d, "%d:%f", &minutes, &seconds);
 787			*clock_value = minutes*60 + seconds;
 788		}
 789	} else if ((tmp = strstr(d, "h"))) {
 790		Float f;
 791		sscanf(d, "%fh", &f);
 792		*clock_value = 3600*f;
 793	} else if (strstr(d, "min")) {
 794		Float f;
 795		sscanf(d, "%fmin", &f);
 796		*clock_value = 60*f;
 797	} else if ((tmp = strstr(d, "ms"))) {
 798		Float f;
 799		sscanf(d, "%fms", &f);
 800		*clock_value = f/1000;
 801	} else if (strchr(d, 's')) {
 802		Float f;
 803		sscanf(d, "%fs", &f);
 804		*clock_value = f;
 805	} else {
 806		*clock_value = atof(d);
 807	}
 808	*clock_value *= sign;
 809}
 810/* Parses one SVG time value:
 811	  'indefinite', 
 812	  'name.begin', 'name.end', 
 813	  wallclock,
 814	  accessKey,
 815	  events, 
 816	  clock value.
 817 */
 818static void smil_parse_time(GF_Node *e, SMIL_Time *v, char *d) 
 819{
 820	char *tmp;
 821
 822	/* Offset Values */
 823	if ((d[0] >= '0' && d[0] <= '9') || d[0] == '+' || d[0] == '-'){
 824		v->type = GF_SMIL_TIME_CLOCK;
 825		svg_parse_clock_value(d, &(v->clock));
 826		return;
 827	} 
 828	
 829	/* Indefinite Values */
 830	else if (!strcmp(d, "indefinite")) {
 831		v->type = GF_SMIL_TIME_INDEFINITE;
 832		return;
 833	} 
 834
 835	/* Wallclock Values */
 836	else if ((tmp = strstr(d, "wallclock("))) {
 837		u32 year, month, day;
 838		u32 hours, minutes;
 839		u32 nhours, nminutes;
 840		Float seconds;
 841		char *tmp1, *tmp2;
 842
 843		v->type = GF_SMIL_TIME_WALLCLOCK;
 844		tmp += 10;
 845		if ((tmp1 = strchr(tmp, 'T')) ) {
 846			/* From tmp to wallStartTime, we parse a date */
 847			sscanf(tmp, "%d-%d-%dT", &year, &month, &day);
 848			tmp1++;
 849			tmp = tmp1;
 850		} 	
 851		if ((tmp1 = strchr(tmp, ':')) ) {
 852			if ((tmp2 = strchr(tmp1, ':')) ) {
 853				/* HHMMSS */
 854				sscanf(tmp, "%d:%d:%f", &hours, &minutes, &seconds);		
 855			} else {
 856				/* HHMM */
 857				sscanf(tmp, "%d:%d", &hours, &minutes);		
 858			}
 859		}
 860		if (strchr(tmp, 'Z')) {
 861			return;
 862		} else {
 863			if ( (tmp1 = strchr(tmp, '+')) ) {
 864				sscanf(tmp1, "%d:%d", &nhours, &nminutes);		
 865			} else if ( (tmp1 = strchr(tmp, '-')) ) {
 866				sscanf(tmp1, "%d:%d", &nhours, &nminutes);		
 867			}
 868		}
 869		return;
 870	} 
 871
 872	/* AccessKey Values */
 873	else if ((tmp = strstr(d, "accessKey("))) {
 874		char *sep;
 875		v->type = GF_SMIL_TIME_EVENT;
 876		v->event.type = GF_EVENT_KEYDOWN;
 877		v->element = e->sgprivate->scenegraph->RootNode;
 878		tmp+=10;
 879		sep = strchr(d, ')');
 880		sep[0] = 0;
 881		v->event.parameter = gf_dom_get_key_type(tmp);
 882		sep++;
 883		if ((tmp = strchr(sep, '+')) || (tmp = strchr(sep, '-'))) {
 884			char c = *tmp;
 885			tmp++;
 886			svg_parse_clock_value(tmp, &(v->clock));
 887			if (c == '-') v->clock *= -1;
 888		} 
 889		return;
 890	} 
 891
 892	else {
 893		Bool had_param = 0;
 894		char *tmp2;
 895		v->type = GF_SMIL_TIME_EVENT;
 896		if ((tmp = strchr(d, '.'))) {
 897			tmp[0] = 0;
 898			v->element_id = strdup(d);
 899			tmp[0] = '.';
 900			tmp++;
 901		} else {
 902			tmp = d;
 903		}
 904		if ((tmp2 = strchr(tmp, '('))) {
 905			tmp2[0] = 0;
 906			v->event.type = gf_dom_event_type_by_name(tmp);
 907			tmp2[0] = '(';
 908			tmp2++;
 909			had_param = 1;
 910			v->event.parameter = atoi(tmp2);
 911			tmp = strchr(tmp2, ')');
 912			if (!tmp) {
 913				GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] expecting ')' in SMIL Time %s\n", d));
 914				return;
 915			}			
 916			tmp++;
 917		} 
 918		if ((tmp2 = strchr(tmp, '+')) || (tmp2 = strchr(tmp, '-'))) {
 919			char c = *tmp2;
 920			char *tmp3 = tmp2;
 921			tmp2[0] = 0;
 922			tmp3--;
 923			while (*tmp3==' ') { *tmp3=0; tmp3--; }
 924			if (v->event.type == 0) v->event.type = gf_dom_event_type_by_name(tmp);
 925			if (!had_param && (v->event.type == GF_EVENT_REPEAT || v->event.type == GF_EVENT_REPEAT_EVENT))
 926				v->event.parameter = 1;
 927			tmp2[0] = c;
 928			tmp2++;
 929			svg_parse_clock_value(tmp2, &(v->clock));
 930			if (c == '-') v->clock *= -1;
 931		} else {
 932			if (v->event.type == 0) v->event.type = gf_dom_event_type_by_name(tmp);
 933			if (!had_param && (v->event.type == GF_EVENT_REPEAT || v->event.type == GF_EVENT_REPEAT_EVENT))
 934				v->event.parameter = 1;
 935		}
 936	}
 937}
 938
 939/* Parses a list of SVG transformations and collapses them in the given matrix */
 940static void svg_parse_transformlist(GF_Matrix2D *mat, char *attribute_content) 
 941{
 942	GF_Matrix2D tmp;
 943
 944	char *str;
 945	u32 i;
 946	
 947	gf_mx2d_init(*mat);
 948	
 949	str = attribute_content;
 950	i = 0;
 951	while (str[i] != 0) {
 952		while (str[i] == ' ') i++;
 953		if (str[i] == ',') i++;
 954		while (str[i] == ' ') i++;
 955		if (strstr(str+i, "scale")==str+i) {
 956			Fixed sx, sy;
 957			i += 5;
 958			while(str[i] != 0 && str[i] == ' ') i++;
 959			if (str[i] == '(') {
 960				i++;
 961				i+=svg_parse_float(&(str[i]), &sx, 0);
 962				if (str[i] == ')') {
 963					sy = sx;
 964				} else {
 965					i+=svg_parse_float(&(str[i]), &sy, 0);
 966				}
 967				i++;
 968			}
 969			gf_mx2d_init(tmp);
 970			gf_mx2d_add_scale(&tmp, sx, sy);
 971			gf_mx2d_add_matrix(&tmp, mat);
 972			gf_mx2d_copy(*mat, tmp);
 973			while(str[i] != 0 && str[i] == ' ') i++;
 974		} else if (strstr(str+i, "translate")==str+i) {
 975			Fixed tx, ty;
 976			i += 9;
 977			while(str[i] != 0 && str[i] == ' ') i++;
 978			if (str[i] == '(') {
 979				i++;
 980				i+=svg_parse_float(&(str[i]), &tx, 0);
 981				if (str[i] == ')') {
 982					ty = 0;
 983				} else {
 984					i+=svg_parse_float(&(str[i]), &ty, 0);
 985				}
 986				i++;
 987			}
 988			gf_mx2d_init(tmp);
 989			gf_mx2d_add_translation(&tmp, tx, ty);
 990			gf_mx2d_add_matrix(&tmp, mat);
 991			gf_mx2d_copy(*mat, tmp);
 992			while(str[i] != 0 && str[i] == ' ') i++;
 993		} else if (strstr(str+i, "rotate")==str+i) {
 994			Fixed angle, cx, cy;
 995			i += 6;
 996			while(str[i] != 0 && str[i] == ' ') i++;
 997			if (str[i] == '(') {
 998				i++;
 999				i+=svg_parse_float(&(str[i]), &angle, 1);
1000				if (str[i] == ')') {
1001					cx = cy = 0;
1002				} else {
1003					i+=svg_parse_float(&(str[i]), &cx, 0);
1004					i+=svg_parse_float(&(str[i]), &cy, 0);
1005				}
1006				i++;
1007			}
1008			gf_mx2d_init(tmp);
1009			gf_mx2d_add_rotation(&tmp, cx, cy, angle);
1010			gf_mx2d_add_matrix(&tmp, mat);
1011			gf_mx2d_copy(*mat, tmp);
1012			while(str[i] != 0 && str[i] == ' ') i++;
1013		} else if (strstr(str+i, "skewX")==str+i) {
1014			Fixed angle;
1015			i += 5;
1016			while(str[i] != 0 && str[i] == ' ') i++;
1017			if (str[i] == '(') {
1018				i++;
1019				i+=svg_parse_float(&(str[i]), &angle, 1);
1020				i++;
1021			}
1022			gf_mx2d_init(tmp);
1023			gf_mx2d_add_skew_x(&tmp, angle);
1024			gf_mx2d_add_matrix(&tmp, mat);
1025			gf_mx2d_copy(*mat, tmp);
1026			while(str[i] != 0 && str[i] == ' ') i++;
1027		} else if (strstr(str+i, "skewY")==str+i) {
1028			Fixed angle;
1029			i += 5;
1030			while(str[i] != 0 && str[i] == ' ') i++;
1031			if (str[i] == '(') {
1032				i++;
1033				i+=svg_parse_float(&(str[i]), &angle, 1);
1034				i++;
1035			}
1036			gf_mx2d_init(tmp);
1037			gf_mx2d_add_skew_y(&tmp, angle);
1038			gf_mx2d_add_matrix(&tmp, mat);
1039			gf_mx2d_copy(*mat, tmp);
1040			while(str[i] != 0 && str[i] == ' ') i++;
1041		} else if (strstr(str+i, "matrix")==str+i) {
1042			i+=6;
1043			while(str[i] != 0 && str[i] == ' ') i++;
1044			if (str[i] == '(') {
1045				i++;
1046				i+=svg_parse_float(&(str[i]), &(tmp.m[0]), 0);
1047				i+=svg_parse_float(&(str[i]), &(tmp.m[3]), 0);
1048				i+=svg_parse_float(&(str[i]), &(tmp.m[1]), 0);
1049				i+=svg_parse_float(&(str[i]), &(tmp.m[4]), 0);
1050				i+=svg_parse_float(&(str[i]), &(tmp.m[2]), 0);
1051				i+=svg_parse_float(&(str[i]), &(tmp.m[5]), 0);
1052				i++;
1053			}
1054			gf_mx2d_add_matrix(&tmp, mat);
1055			gf_mx2d_copy(*mat, tmp);
1056			while(str[i] != 0 && str[i] == ' ') i++;
1057			if (str[i] == ')') i++;
1058		} 
1059	}
1060}
1061
1062/* Parses an SVG transform attribute and collapses all in the given matrix */
1063static Bool svg_parse_transform(SVG_Transform *t, char *attribute_content) 
1064{
1065	char *str;
1066	u32 i;
1067	str = attribute_content;
1068	i = 0;
1069
1070	if ((str = strstr(attribute_content, "ref("))) {
1071		t->is_ref = 1;
1072		gf_mx2d_init(t->mat);
1073		str+=3;
1074		while(str[i] != 0 && str[i] == ' ') i++;
1075		if (str[i] == 's' && str[i+1] == 'v' && str[i+2] == 'g') {
1076			i+=3;
1077			while(str[i] != 0 && str[i] == ' ') i++;					
1078			if (str[i] == ',') i++;
1079			else if (str[i] == ')') {
1080				i++;
1081				return GF_OK;
1082			}
1083			i+=svg_parse_float(&(str[i]), &(t->mat.m[2]), 0);
1084			i+=svg_parse_float(&(str[i]), &(t->mat.m[5]), 0);
1085			while(str[i] != 0 && str[i] == ' ') i++;
1086			if (str[i] == ')')  i++;
1087			i++;
1088			return GF_OK;
1089		} else {
1090			while(str[i] != 0 && str[i] != ')') i++;
1091			i++;
1092			return GF_NOT_SUPPORTED;
1093		}
1094		
1095	} else {
1096		svg_parse_transformlist(&t->mat, attribute_content);
1097	}
1098	return GF_OK;
1099}
1100
1101#undef REMOVE_ALLOC
1102
1103#if USE_GF_PATH    
1104
1105//#define PARSE_PATH_ONLY
1106
1107static void svg_parse_path(SVG_PathData *path, char *attribute_content) 
1108{
1109	char *d = attribute_content;
1110	
1111	/* Point used to start a new subpath when the previous subpath is closed */
1112	SVG_Point prev_m_pt;
1113	/* Point used to convert relative 'lower-case commands' into absolute */
1114	SVG_Point rel_ref_pt;
1115	/* Points used to convert S, T commands into C, Q */
1116	SVG_Point orig, ct_orig, ct_end, end;
1117	/* Used by elliptical arcs */
1118	Fixed x_axis_rotation, large_arc_flag, sweep_flag;
1119
1120	char c, prev_c;
1121	u32 i;
1122
1123	if (*d == 0) return;
1124
1125	i = 0;
1126	prev_c = 'M';
1127	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 = 0;
1128	while(1) {
1129		while ( (d[i]==' ') || (d[i] =='\t') || (d[i] =='\r') || (d[i] =='\n') ) i++;			
1130		c = d[i];
1131		if (! c) break;
1132next_command:
1133		switch (c) {
1134		case 'm':
1135		case 'M':
1136			i++;
1137			i += svg_parse_float(&(d[i]), &(orig.x), 0);
1138			i += svg_parse_float(&(d[i]), &(orig.y), 0);				
1139			if (c == 'm') {
1140				orig.x += rel_ref_pt.x;
1141				orig.y += rel_ref_pt.y;
1142			}
1143#ifndef PARSE_PATH_ONLY
1144			gf_path_add_move_to(path, orig.x, orig.y);
1145#endif
1146			rel_ref_pt = orig;
1147			prev_m_pt = orig;
1148			/*provision for nextCurveTo when no curve is specified:
1149				"If there is no previous command or if the previous command was not an C, c, S or s, 
1150				assume the first control point is coincident with the current point.
1151			*/
1152			ct_orig = orig;
1153			prev_c = c;
1154			break;
1155		case 'L':
1156		case 'l':
1157			i++;
1158			i += svg_parse_float(&(d[i]), &(orig.x), 0);
1159			i += svg_parse_float(&(d[i]), &(orig.y), 0);				
1160			if (c == 'l') {
1161				orig.x += rel_ref_pt.x;
1162				orig.y += rel_ref_pt.y;
1163			}
1164#ifndef PARSE_PATH_ONLY
1165			gf_path_add_line_to(path, orig.x, orig.y);
1166#endif
1167			rel_ref_pt = orig;
1168			orig = end;
1169			/*cf above*/
1170			ct_orig = orig;
1171			prev_c = c;
1172			break;
1173		case 'H':
1174		case 'h':
1175			i++;				
1176			i += svg_parse_float(&(d[i]), &(orig.x), 0);
1177			if (c == 'h') {
1178				orig.x += rel_ref_pt.x;
1179			}
1180			orig.y = rel_ref_pt.y;
1181#ifndef PARSE_PATH_ONLY
1182			gf_path_add_line_to(path, orig.x, orig.y);			
1183#endif
1184			rel_ref_pt.x = orig.x;
1185			orig = end;
1186			/*cf above*/
1187			ct_orig = orig;
1188			prev_c = c;
1189			break;
1190		case 'V':
1191		case 'v':
1192			i++;				
1193			i += svg_parse_float(&(d[i]), &(orig.y), 0);
1194			if (c == 'v') {
1195				orig.y += rel_ref_pt.y;
1196			}
1197			orig.x = rel_ref_pt.x;
1198#ifndef PARSE_PATH_ONLY
1199			gf_path_add_line_to(path, orig.x, orig.y);			
1200#endif
1201			rel_ref_pt.y = orig.y;
1202			orig = end;
1203			/*cf above*/
1204			ct_orig = orig;
1205			prev_c = c;
1206			break;
1207		case 'C':
1208		case 'c':
1209			i++;				
1210			i += svg_parse_float(&(d[i]), &(ct_orig.x), 0);
1211			i += svg_parse_float(&(d[i]), &(ct_orig.y), 0);
1212			if (c == 'c') {
1213				ct_orig.x += rel_ref_pt.x;
1214				ct_orig.y += rel_ref_pt.y;
1215			}
1216			i += svg_parse_float(&(d[i]), &(ct_end.x), 0);
1217			i += svg_parse_float(&(d[i]), &(ct_end.y), 0);
1218			if (c == 'c') {
1219				ct_end.x += rel_ref_pt.x;
1220				ct_end.y += rel_ref_pt.y;
1221			}
1222			i += svg_parse_float(&(d[i]), &(end.x), 0);
1223			i += svg_parse_float(&(d[i]), &(end.y), 0);
1224			if (c == 'c') {
1225				end.x += rel_ref_pt.x;
1226				end.y += rel_ref_pt.y;
1227			}
1228#ifndef PARSE_PATH_ONLY
1229			gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
1230#endif
1231			rel_ref_pt = end;
1232			ct_orig = ct_end;
1233			orig = end;
1234			prev_c = c;
1235			break;
1236		case 'S':
1237		case 's':
1238			i++;				
1239			ct_orig.x = 2*orig.x - ct_orig.x;
1240			ct_orig.y = 2*orig.y - ct_orig.y;
1241			i += svg_parse_float(&(d[i]), &(ct_end.x), 0);
1242			i += svg_parse_float(&(d[i]), &(ct_end.y), 0);
1243			if (c == 's') {
1244				ct_end.x += rel_ref_pt.x;
1245				ct_end.y += rel_ref_pt.y;
1246			}
1247			i += svg_parse_float(&(d[i]), &(end.x), 0);
1248			i += svg_parse_float(&(d[i]), &(end.y), 0);
1249			if (c == 's') {
1250				end.x += rel_ref_pt.x;
1251				end.y += rel_ref_pt.y;
1252			}
1253#ifndef PARSE_PATH_ONLY
1254			gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
1255#endif
1256			rel_ref_pt = end;
1257			ct_orig = ct_end;
1258			orig = end;
1259			prev_c = c;
1260			break;
1261		case 'Q':
1262		case 'q':
1263			i++;				
1264			i += svg_parse_float(&(d[i]), &(ct_orig.x), 0);
1265			i += svg_parse_float(&(d[i]), &(ct_orig.y), 0);				
1266			if (c == 'q') {
1267				ct_orig.x += rel_ref_pt.x;
1268				ct_orig.y += rel_ref_pt.y;
1269			}
1270			i += svg_parse_float(&(d[i]), &(end.x), 0);
1271			i += svg_parse_float(&(d[i]), &(end.y), 0);				
1272			if (c == 'q') {
1273				end.x += rel_ref_pt.x;
1274				end.y += rel_ref_pt.y;
1275			}
1276#ifndef PARSE_PATH_ONLY
1277			gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y);			
1278#endif
1279			rel_ref_pt = end;
1280			orig = end;
1281			prev_c = c;
1282			break;
1283		case 'T':
1284		case 't':
1285			i++;				
1286			ct_orig.x = 2*orig.x - ct_orig.x;
1287			ct_orig.y = 2*orig.y - ct_orig.y;
1288			i += svg_parse_float(&(d[i]), &(end.x), 0);
1289			i += svg_parse_float(&(d[i]), &(end.y), 0);				
1290			if (c == 't') {
1291				end.x += rel_ref_pt.x;
1292				end.y += rel_ref_pt.y;
1293			}
1294#ifndef PARSE_PATH_ONLY
1295			gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y);
1296#endif
1297			rel_ref_pt = end;
1298			orig = end;
1299			prev_c = c;
1300			break;
1301		case 'A':
1302		case 'a':
1303			i++;				
1304
1305			i += svg_parse_float(&(d[i]), &(orig.x), 0);	
1306			i += svg_parse_float(&(d[i]), &(orig.y), 0);				
1307			if (c == 'a') {
1308				orig.x += rel_ref_pt.x;
1309				orig.y += rel_ref_pt.y;
1310			}
1311
1312			i += svg_parse_float(&(d[i]), &(x_axis_rotation), 0);	
1313			i += svg_parse_float(&(d[i]), &(large_arc_flag), 0);				
1314			i += svg_parse_float(&(d[i]), &(sweep_flag), 0);	
1315			
1316			i += svg_parse_float(&(d[i]), &(end.x), 0);	
1317			i += svg_parse_float(&(d[i]), &(end.y), 0);				
1318			if (c == 'a') {
1319				end.x += rel_ref_pt.x;
1320				end.y += rel_ref_pt.y;
1321			}
1322			//gf_path_add_svg_arc_to(path, orig.x, orig.y, x_axis_rotation, large_arc_flag, sweep_flag, end.x, end.y);
1323			rel_ref_pt = end;
1324			ct_orig = end;
1325			prev_c = c;
1326			break;
1327		case 'Z':
1328		case 'z':
1329			i++;				
1330#ifndef PARSE_PATH_ONLY
1331			gf_path_close(path);
1332#endif
1333			prev_c = c;
1334			rel_ref_pt = prev_m_pt;
1335			break;
1336		default:
1337			i--;
1338			switch (prev_c) {
1339			case 'M':
1340				c = 'L';
1341				break;
1342			case 'm':
1343				c = 'l';
1344				break;
1345			default:
1346				c = prev_c;
1347			}
1348			goto next_command;
1349		}
1350	}
1351}
1352#else
1353/* TODO: Change the function to handle elliptical arcs, requires changing data structure */
1354static void svg_parse_path(SVG_PathData *d_attribute, char *attribute_content) 
1355{
1356	GF_List *d_commands = d_attribute->commands;
1357	GF_List *d_points = d_attribute->points;
1358	char *d = attribute_content;
1359
1360	if (strlen(d)) {
1361		SVG_Point *pt, cur_pt, prev_m_pt;
1362		u8 *command;
1363		u32 i, k;
1364		char c, prev_c = 'M';
1365#ifdef REMOVE_ALLOC
1366		GF_SAFEALLOC(pt, SVG_Point)
1367#endif
1368		i = 0;
1369		cur_pt.x = cur_pt.y = 0;
1370		prev_m_pt.x = prev_m_pt.y = 0;
1371		while(1) {
1372			while ( (d[i]==' ') || (d[i] =='\t') ) i++;			
1373			c = d[i];
1374			if (! c) break;
1375next_command:
1376			switch (c) {
1377			case 'm':
1378			case 'M':
1379				i++;
1380#ifndef REMOVE_ALLOC
1381				GF_SAFEALLOC(command, u8)
1382				gf_list_add(d_commands, command);
1383				*command = SVG_PATHCOMMAND_M;
1384
1385				GF_SAFEALLOC(pt, SVG_Point)
1386				gf_list_add(d_points, pt);
1387#endif
1388				i += svg_parse_float(&(d[i]), &(pt->x), 0);
1389				i += svg_parse_float(&(d[i]), &(pt->y), 0);				
1390				if (c == 'm') {
1391					pt->x += cur_pt.x;
1392					pt->y += cur_pt.y;
1393				}
1394				cur_pt.x = pt->x;
1395				cur_pt.y = pt->y;
1396				prev_m_pt = cur_pt;
1397				prev_c = c;
1398				break;
1399			case 'L':
1400			case 'l':
1401				i++;
1402#ifndef REMOVE_ALLOC
1403				GF_SAFEALLOC(command, u8)
1404				gf_list_add(d_commands, command);
1405				*command = SVG_PATHCOMMAND_L;
1406				
1407				GF_SAFEALLOC(pt, SVG_Point)
1408				gf_list_add(d_points, pt);
1409#endif
1410				i += svg_parse_float(&(d[i]), &(pt->x), 0);
1411				i += svg_parse_float(&(d[i]), &(pt->y), 0);				
1412				if (c == 'l') {
1413					pt->x += cur_pt.x;
1414					pt->y += cur_pt.y;
1415				}
1416				cur_pt.x = pt->x;
1417				cur_pt.y = pt->y;
1418				prev_c = c;
1419				break;
1420			case 'H':
1421			case 'h':
1422				i++;				
1423#ifndef REMOVE_ALLOC
1424				GF_SAFEALLOC(command, u8)
1425				gf_list_add(d_commands, command);
1426				*command = SVG_PATHCOMMAND_L;
1427
1428				GF_SAFEALLOC(pt, SVG_Point)
1429				gf_list_add(d_points, pt);
1430#endif
1431				i += svg_parse_float(&(d[i]), &(pt->x), 0);
1432				if (c == 'h') {
1433					pt->x += cur_pt.x;
1434				}
1435				pt->y = cur_pt.y;
1436				cur_pt.x = pt->x;
1437				prev_c = c;
1438				break;
1439			case 'V':
1440			case 'v':
1441				i++;				
1442#ifndef REMOVE_ALLOC
1443				GF_SAFEALLOC(command, u8)
1444				gf_list_add(d_commands, command);
1445				*command = SVG_PATHCOMMAND_L;
1446
1447				GF_SAFEALLOC(pt, SVG_Point)
1448				gf_list_add(d_points, pt);
1449#endif
1450				i += svg_parse_float(&(d[i]), &(pt->y), 0);
1451				if (c == 'v') {
1452					pt->y += cur_pt.y;
1453				}
1454				pt->x = cur_pt.x;
1455				cur_pt.y = pt->y;
1456				prev_c = c;
1457				break;
1458			case 'C':
1459			case 'c':
1460				i++;				
1461#ifndef REMOVE_ALLOC
1462				GF_SAFEALLOC(command, u8)
1463				gf_list_add(d_commands, command);
1464				*command = SVG_PATHCOMMAND_C;
1465#endif
1466				
1467				for (k=0; k<3; k++) {
1468#ifndef REMOVE_ALLOC
1469					GF_SAFEALLOC(pt, SVG_Point)
1470					gf_list_add(d_points, pt);
1471#endif
1472					i += svg_parse_float(&(d[i]), &(pt->x), 0);
1473					i += svg_parse_float(&(d[i]), &(pt->y), 0);				
1474					if (c == 'c') {
1475						pt->x += cur_pt.x;
1476						pt->y += cur_pt.y;
1477					}
1478				}				
1479				cur_pt.x = pt->x;
1480				cur_pt.y = pt->y;
1481				prev_c = c;
1482				break;
1483			case 'S':
1484			case 's':
1485				i++;				
1486#ifndef REMOVE_ALLOC
1487				GF_SAFEALLOC(command, u8)
1488				gf_list_add(d_commands, command);
1489				*command = SVG_PATHCOMMAND_S;
1490#endif
1491				
1492				for (k=0; k<2; k++) {
1493#ifndef REMOVE_ALLOC
1494					GF_SAFEALLOC(pt, SVG_Point)
1495					gf_list_add(d_points, pt);
1496#endif
1497					i += svg_parse_float(&(d[i]), &(pt->x), 0);
1498					i += svg_parse_float(&(d[i]), &(pt->y), 0);				
1499					if (c == 's') {
1500						pt->x += cur_pt.x;
1501						pt->y += cur_pt.y;
1502					}
1503				}				
1504				cur_pt.x = pt->x;
1505				cur_pt.y = pt->y;
1506				prev_c = c;
1507				break;
1508			case 'Q':
1509			case 'q':
1510				i++;				
1511#ifndef REMOVE_ALLOC
1512				GF_SAFEALLOC(command, u8)
1513				gf_list_add(d_commands, command);
1514				*command = SVG_PATHCOMMAND_Q;
1515#endif
1516				
1517				for (k=0; k<2; k++) {
1518#ifndef REMOVE_ALLOC
1519					GF_SAFEALLOC(pt, SVG_Point)
1520					gf_list_add(d_points, pt);
1521#endif
1522					i += svg_parse_float(&(d[i]), &(pt->x), 0);
1523					i += svg_parse_float(&(d[i]), &(pt->y), 0);				
1524					if (c == 'q') {
1525						pt->x += cur_pt.x;
1526						pt->y += cur_pt.y;
1527					}
1528				}				
1529				cur_pt.x = pt->x;
1530				cur_pt.y = pt->y;
1531				prev_c = c;
1532				break;
1533			case 'T':
1534			case 't':
1535				i++;				
1536#ifndef REMOVE_ALLOC
1537				GF_SAFEALLOC(command, u8)
1538				gf_list_add(d_commands, command);
1539				*command = SVG_PATHCOMMAND_T;
1540				
1541				GF_SAFEALLOC(pt, SVG_Point)
1542				gf_list_add(d_points, pt);
1543#endif
1544				i += svg_parse_float(&(d[i]), &(pt->x), 0);
1545				i += svg_parse_float(&(d[i]), &(pt->y), 0);				
1546				if (c == 't') {
1547					pt->x += cur_pt.x;
1548					pt->y += cur_pt.y;
1549				}
1550				cur_pt.x = pt->x;
1551				cur_pt.y = pt->y;
1552				prev_c = c;
1553				break;
1554			case 'A':
1555			case 'a':
1556				{
1557					Fixed tmp;
1558					i++;				
1559#ifndef REMOVE_ALLOC
1560					GF_SAFEALLOC(command, u8)
1561					gf_list_add(d_commands, command);
1562					*command = SVG_PATHCOMMAND_A;
1563	
1564					GF_SAFEALLOC(pt, SVG_Point)
1565					gf_list_add(d_points, pt);
1566#endif
1567					i += svg_parse_float(&(d[i]), &(pt->x), 0);	
1568					i += svg_parse_float(&(d[i]), &(pt->y), 0);				
1569
1570					i += svg_parse_float(&(d[i]), &(tmp), 0);	
1571					i += svg_parse_float(&(d[i]), &(tmp), 0);				
1572					i += svg_parse_float(&(d[i]), &(tmp), 0);	
1573					
1574#ifndef REMOVE_ALLOC
1575					GF_SAFEALLOC(pt, SVG_Point)
1576					gf_list_add(d_points, pt);
1577#endif
1578					i += svg_parse_float(&(d[i]), &(pt->x), 0);	
1579					i += svg_parse_float(&(d[i]), &(pt->y), 0);				
1580					if (c == 'a') {
1581						pt->x += cur_pt.x;
1582						pt->y += cur_pt.y;
1583					}
1584					cur_pt.x = pt->x;
1585					cur_pt.y = pt->y;
1586				}
1587				prev_c = c;
1588				break;
1589			case 'Z':
1590			case 'z':
1591				i++;				
1592#ifndef REMOVE_ALLOC
1593				GF_SAFEALLOC(command, u8)
1594				gf_list_add(d_commands, command);
1595				*command = SVG_PATHCOMMAND_Z;
1596#endif
1597				prev_c = c;
1598				cur_pt = prev_m_pt;
1599				break;
1600			default:
1601				i--;
1602				switch (prev_c) {
1603				case 'M':
1604					c = 'L';
1605					break;
1606				case 'm':
1607					c = 'l';
1608					break;
1609				default:
1610					c = prev_c;
1611				}
1612				goto next_command;
1613			}
1614		}
1615	}
1616}
1617#endif
1618
1619static void svg_parse_iri(GF_Node *elt, XMLRI *iri, char *attribute_content)
1620{
1621	/* TODO: Handle xpointer(id()) syntax */
1622	if (attribute_content[0] == '#') {
1623		iri->string = strdup(attribute_content);
1624		iri->target = gf_sg_find_node_by_name(elt->sgprivate->scenegraph, attribute_content + 1);
1625		if (!iri->target) {
1626			iri->type = XMLRI_STRING;
1627		} else {
1628			iri->type = XMLRI_ELEMENTID;
1629			gf_svg_register_iri(elt->sgprivate->scenegraph, iri);
1630		}
1631	} else {
1632		iri->type = XMLRI_STRING;
1633		iri->string = strdup(attribute_content);
1634	}
1635}
1636
1637static void svg_parse_idref(GF_Node *elt, XML_IDREF *iri, char *attribute_content)
1638{
1639	iri->type = XMLRI_ELEMENTID;
1640	iri->target = gf_sg_find_node_by_name(elt->sgprivate->scenegraph, attribute_content);
1641	if (!iri->target) {
1642		iri->string = strdup(attribute_content);
1643	} else {
1644		gf_svg_register_iri(elt->sgprivate->scenegraph, iri);
1645	}
1646}
1647
1648/* Parses a paint attribute: none, inherit or color */
1649static void svg_parse_paint(GF_Node *n, SVG_Paint *paint, char *attribute_content)
1650{
1651	if (!strcmp(attribute_content, "none")) {
1652		paint->type = SVG_PAINT_NONE;
1653	} else if (!strcmp(attribute_content, "inherit")) {
1654		paint->type = SVG_PAINT_INHERIT;
1655	} else if (!strncmp(attribute_content, "url(", 4) ) {
1656		u32 len = strlen(attribute_content);
1657		paint->type = SVG_PAINT_URI;
1658		attribute_content[len-1] = 0;
1659		svg_parse_iri(n, &paint->iri, attribute_content+4);
1660		attribute_content[len-1] = ')';
1661	} else {
1662		paint->type = SVG_PAINT_COLOR;
1663		svg_parse_color(&paint->color, attribute_content);
1664	}
1665}
1666
1667
1668static u32 svg_parse_number(SVG_Number *number, char *value_string, Bool clamp0to1)
1669{
1670	char *unit = NULL;
1671	u32 len = 0;
1672	if (!strcmp(value_string, "inherit")) {
1673		number->type = SVG_NUMBER_INHERIT;
1674		return 7;
1675	} else if (!strcmp(value_string, "auto")) {
1676		number->type = SVG_NUMBER_AUTO;
1677		return 4;
1678	} else if (!strcmp(value_string, "auto-reverse")) {
1679		number->type = SVG_NUMBER_AUTO_REVERSE;
1680		return 12;
1681	} else if ((unit = strstr(value_string, "%")) ) {
1682		number->type = SVG_NUMBER_PERCENTAGE;
1683	} else if ((unit = strstr(value_string, "em"))) {
1684		number->type = SVG_NUMBER_EMS;
1685	} else if ((unit = strstr(value_string, "ex"))) {
1686		number->type = SVG_NUMBER_EXS;
1687	} else if ((unit = strstr(value_string, "px"))) {
1688		number->type = SVG_NUMBER_PX;
1689	} else if ((unit = strstr(value_string, "cm"))) {
1690		number->type = SVG_NUMBER_CM;
1691	} else if ((unit = strstr(value_string, "mm"))) {
1692		number->type = SVG_NUMBER_MM;
1693	} else if ((unit = strstr(value_string, "in"))) {
1694		number->type = SVG_NUMBER_IN;
1695	} else if ((unit = strstr(value_string, "pt"))) {
1696		number->type = SVG_NUMBER_PT;
1697	} else if ((unit = strstr(value_string, "pc"))) {
1698		number->type = SVG_NUMBER_PC;
1699	} else {
1700		number->type = SVG_NUMBER_VALUE;
1701	}
1702	if (unit) len = strlen(unit); 
1703	len+=svg_parse_float(value_string, &(number->value), 0);
1704
1705	if (clamp0to1) number->value = MAX(0, MIN(1, number->value));
1706	return len;
1707}
1708
1709static void svg_parse_visibility(SVG_Visibility *value, char *value_string)
1710{
1711	if (!strcmp(value_string, "inherit")) {
1712		*value = SVG_VISIBILITY_INHERIT;
1713	} else if (!strcmp(value_string, "visible")) {
1714		*value = SVG_VISIBILITY_VISIBLE;
1715	} else if (!strcmp(value_string, "hidden")) {
1716		*value = SVG_VISIBILITY_HIDDEN;
1717	} else if (!strcmp(value_string, "collapse")) {
1718		*value = SVG_VISIBILITY_COLLAPSE;
1719	} 
1720}
1721
1722static void svg_parse_display(SVG_Display *value, char *value_string)
1723{
1724	if (!strcmp(value_string, "inherit")) {
1725		*value = SVG_DISPLAY_INHERIT;
1726	} else if (!strcmp(value_string, "none")) {
1727		*value = SVG_DISPLAY_NONE;
1728	} else if (!strcmp(value_string, "inline")) {
1729		*value = SVG_DISPLAY_INLINE;
1730	} else if (!strcmp(value_string, "block")) {
1731		*value = SVG_DISPLAY_BLOCK;
1732	} else if (!strcmp(value_string, "list-item")) {
1733		*value = SVG_DISPLAY_LIST_ITEM;
1734	} else if (!strcmp(value_string, "run-in")) {
1735		*value = SVG_DISPLAY_RUN_IN;
1736	} else if (!strcmp(value_string, "compact")) {
1737		*value = SVG_DISPLAY_COMPACT;
1738	} else if (!strcmp(value_string, "marker")) {
1739		*value = SVG_DISPLAY_MARKER;
1740	} else if (!strcmp(value_string, "table")) {
1741		*value = SVG_DISPLAY_TABLE;
1742	} else if (!strcmp(value_string, "inline-table")) {
1743		*value = SVG_DISPLAY_INLINE_TABLE;
1744	} else if (!strcmp(value_string, "table-row-group")) {
1745		*value = SVG_DISPLAY_TABLE_ROW_GROUP;
1746	} else if (!strcmp(value_string, "table-header-group")) {
1747		*value = SVG_DISPLAY_TABLE_HEADER_GROUP;
1748	} else if (!strcmp(value_string, "table-footer-group")) {
1749		*value = SVG_DISPLAY_TABLE_FOOTER_GROUP;
1750	} else if (!strcmp(value_string, "table-row")) {
1751		*value = SVG_DISPLAY_TABLE_ROW;
1752	} else if (!strcmp(value_string, "table-column-group")) {
1753		*value = SVG_DISPLAY_TABLE_COLUMN_GROUP;
1754	} else if (!strcmp(value_string, "table-column")) {
1755		*value = SVG_DISPLAY_TABLE_COLUMN;
1756	} else if (!strcmp(value_string, "table-cell")) {
1757		*value = SVG_DISPLAY_TABLE_CELL;
1758	} else if (!strcmp(value_string, "table-caption")) {
1759		*value = SVG_DISPLAY_TABLE_CAPTION;
1760	} 
1761}
1762
1763static void svg_parse_displayalign(SVG_DisplayAlign *value, char *value_string)
1764{ 
1765	if (!strcmp(value_string, "inherit")) {
1766		*value = SVG_DISPLAYALIGN_INHERIT;
1767	} else if (!strcmp(value_string, "auto")) {
1768		*value = SVG_DISPLAYALIGN_AUTO;
1769	} els

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