PageRenderTime 66ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/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
Possible License(s): GPL-2.0, LGPL-2.0, BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception

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

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