PageRenderTime 83ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/scenegraph/svg_attributes.c

https://github.com/svettom/gpac
C | 6454 lines | 5969 code | 326 blank | 159 comment | 1469 complexity | 18d4b2816d8a3b02f0d6947c3f58ec2a MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0
  1. /*
  2. * GPAC Multimedia Framework
  3. *
  4. * Authors: Cyril Concolato, Jean Le Feuvre
  5. * Copyright (c) Telecom ParisTech 2004-2012
  6. * All rights reserved
  7. *
  8. * This file is part of GPAC / SVG Loader module
  9. *
  10. * GPAC is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU Lesser General Public License as published by
  12. * the Free Software Foundation; either version 2, or (at your option)
  13. * any later version.
  14. *
  15. * GPAC is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; see the file COPYING. If not, write to
  22. * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  23. *
  24. */
  25. #include "../../include/gpac/base_coding.h"
  26. #include "../../include/gpac/events.h"
  27. #include "../../include/gpac/nodes_svg.h"
  28. #ifndef GPAC_DISABLE_SVG
  29. #include "../../include/gpac/internal/scenegraph_dev.h"
  30. #define DUMP_COORDINATES 1
  31. static const struct dom_event_def {u32 event; const char *name; u32 category; } defined_dom_events [] =
  32. {
  33. { GF_EVENT_ABORT, "abort", GF_DOM_EVENT_DOM },
  34. { GF_EVENT_ERROR, "error", GF_DOM_EVENT_DOM },
  35. { GF_EVENT_LOAD, "load", GF_DOM_EVENT_DOM },
  36. { GF_EVENT_UNLOAD, "unload", GF_DOM_EVENT_DOM },
  37. /*focus - we differentiate from UI/key events to avoid browing focus if no listener is on place*/
  38. { GF_EVENT_FOCUSIN, "DOMFocusIn", GF_DOM_EVENT_FOCUS },
  39. { GF_EVENT_FOCUSIN, "focusin", GF_DOM_EVENT_FOCUS },
  40. { GF_EVENT_FOCUSOUT, "DOMFocusOut", GF_DOM_EVENT_FOCUS },
  41. { GF_EVENT_FOCUSOUT, "focusout", GF_DOM_EVENT_FOCUS },
  42. { GF_EVENT_CHANGE, "change", GF_DOM_EVENT_FOCUS },
  43. { GF_EVENT_FOCUS, "focus", GF_DOM_EVENT_FOCUS },
  44. { GF_EVENT_BLUR, "blur", GF_DOM_EVENT_FOCUS },
  45. /*key events*/
  46. { GF_EVENT_KEYDOWN, "keydown", GF_DOM_EVENT_KEY },
  47. { GF_EVENT_KEYDOWN, "accesskey", GF_DOM_EVENT_KEY },
  48. { GF_EVENT_KEYDOWN, "keypress", GF_DOM_EVENT_KEY },
  49. { GF_EVENT_KEYUP, "keyup", GF_DOM_EVENT_KEY },
  50. { GF_EVENT_LONGKEYPRESS, "longaccesskey", GF_DOM_EVENT_KEY },
  51. { GF_EVENT_CLICK, "click", GF_DOM_EVENT_MOUSE },
  52. { GF_EVENT_DBLCLICK, "dblclick", GF_DOM_EVENT_MOUSE },
  53. { GF_EVENT_MOUSEDOWN, "mousedown", GF_DOM_EVENT_MOUSE },
  54. { GF_EVENT_MOUSEMOVE, "mousemove", GF_DOM_EVENT_MOUSE },
  55. { GF_EVENT_MOUSEOUT, "mouseout", GF_DOM_EVENT_MOUSE },
  56. { GF_EVENT_MOUSEOVER, "mouseover", GF_DOM_EVENT_MOUSE },
  57. { GF_EVENT_MOUSEUP, "mouseup", GF_DOM_EVENT_MOUSE },
  58. { GF_EVENT_MOUSEWHEEL, "wheel", GF_DOM_EVENT_MOUSE },
  59. { GF_EVENT_MOUSEWHEEL, "SVGMousewheel", GF_DOM_EVENT_MOUSE },
  60. /*activate is not a basic DOM but a MOUSE and KEY event*/
  61. { GF_EVENT_ACTIVATE, "activate", GF_DOM_EVENT_MOUSE | GF_DOM_EVENT_KEY },
  62. { GF_EVENT_ACTIVATE, "DOMActivate", GF_DOM_EVENT_MOUSE | GF_DOM_EVENT_KEY },
  63. /*text events*/
  64. { GF_EVENT_TEXTINPUT, "textInput", GF_DOM_EVENT_TEXT },
  65. { GF_EVENT_TEXTSELECT, "select", GF_DOM_EVENT_TEXT },
  66. /*SMIL events*/
  67. { GF_EVENT_BEGIN, "begin", GF_DOM_EVENT_FAKE },
  68. { GF_EVENT_BEGIN_EVENT, "beginEvent", GF_DOM_EVENT_SMIL },
  69. { GF_EVENT_END, "end", GF_DOM_EVENT_FAKE },
  70. { GF_EVENT_END_EVENT, "endEvent", GF_DOM_EVENT_SMIL },
  71. { GF_EVENT_REPEAT, "repeat", GF_DOM_EVENT_FAKE },
  72. { GF_EVENT_REPEAT_EVENT, "repeatEvent", GF_DOM_EVENT_SMIL },
  73. /*all SVG/HTML/... UI events*/
  74. { GF_EVENT_RESIZE, "resize", GF_DOM_EVENT_UI },
  75. { GF_EVENT_SCROLL, "scroll", GF_DOM_EVENT_UI },
  76. { GF_EVENT_ZOOM, "zoom", GF_DOM_EVENT_UI },
  77. { GF_EVENT_LOAD, "SVGLoad", GF_DOM_EVENT_DOM },
  78. { GF_EVENT_RESIZE, "SVGResize", GF_DOM_EVENT_UI },
  79. { GF_EVENT_SCROLL, "SVGScroll", GF_DOM_EVENT_UI },
  80. { GF_EVENT_ZOOM, "SVGZoom", GF_DOM_EVENT_UI },
  81. /*mutation events and DCCI*/
  82. { GF_EVENT_TREE_MODIFIED, "DOMSubtreeModified", GF_DOM_EVENT_MUTATION },
  83. { GF_EVENT_NODE_INSERTED, "DOMNodeInserted", GF_DOM_EVENT_MUTATION },
  84. { GF_EVENT_NODE_REMOVED, "DOMNodeRemoved", GF_DOM_EVENT_MUTATION },
  85. { GF_EVENT_NODE_REMOVED_DOC, "DOMNodeRemovedFromDocument", GF_DOM_EVENT_MUTATION },
  86. { GF_EVENT_NODE_INSERTED_DOC, "DOMNodeInsertedIntoDocument", GF_DOM_EVENT_MUTATION },
  87. { GF_EVENT_ATTR_MODIFIED, "DOMAttrModified", GF_DOM_EVENT_MUTATION },
  88. { GF_EVENT_CHAR_DATA_MODIFIED, "DOMCharacterDataModified", GF_DOM_EVENT_MUTATION },
  89. { GF_EVENT_NODE_NAME_CHANGED, "DOMElementNameChanged", GF_DOM_EVENT_MUTATION },
  90. { GF_EVENT_ATTR_NAME_CHANGED, "DOMAttributeNameChanged", GF_DOM_EVENT_MUTATION },
  91. { GF_EVENT_DCCI_PROP_CHANGE, "DCCI-prop-change", GF_DOM_EVENT_MUTATION },
  92. /*LASeR events - some events are attached to other categorues*/
  93. { GF_EVENT_ACTIVATED, "activatedEvent", GF_DOM_EVENT_LASER },
  94. { GF_EVENT_DEACTIVATED, "deactivatedEvent", GF_DOM_EVENT_LASER },
  95. { GF_EVENT_EXECUTION_TIME, "executionTime", GF_DOM_EVENT_FAKE },
  96. { GF_EVENT_PAUSE, "pause", GF_DOM_EVENT_SMIL },
  97. { GF_EVENT_PAUSED_EVENT, "pausedEvent", GF_DOM_EVENT_SMIL },
  98. { GF_EVENT_PLAY, "play", GF_DOM_EVENT_SMIL },
  99. { GF_EVENT_RESUME_EVENT, "resumedEvent", GF_DOM_EVENT_SMIL },
  100. { GF_EVENT_REPEAT_KEY, "repeatKey", GF_DOM_EVENT_KEY },
  101. { GF_EVENT_SHORT_ACCESSKEY, "shortAccessKey", GF_DOM_EVENT_KEY },
  102. /*LASeR unofficial events*/
  103. { GF_EVENT_BATTERY, "battery", GF_DOM_EVENT_LASER },
  104. { GF_EVENT_CPU, "cpu", GF_DOM_EVENT_LASER },
  105. /*MediaAccess events*/
  106. #if 0
  107. { GF_EVENT_MEDIA_BEGIN_SESSION_SETUP, "BeginSessionSetup", GF_DOM_EVENT_MEDIA_ACCESS },
  108. { GF_EVENT_MEDIA_END_SESSION_SETUP, "EndSessionSetup", GF_DOM_EVENT_MEDIA_ACCESS },
  109. { GF_EVENT_MEDIA_DATA_REQUEST, "DataRequest", GF_DOM_EVENT_MEDIA_ACCESS },
  110. { GF_EVENT_MEDIA_PLAYABLE, "Playable", GF_DOM_EVENT_MEDIA_ACCESS },
  111. { GF_EVENT_MEDIA_NOT_PLAYABLE, "NotPlayable", GF_DOM_EVENT_MEDIA_ACCESS },
  112. { GF_EVENT_MEDIA_DATA_PROGRESS, "DataReceptionProgress", GF_DOM_EVENT_MEDIA_ACCESS },
  113. { GF_EVENT_MEDIA_END_OF_DATA, "EndOfDataReception", GF_DOM_EVENT_MEDIA_ACCESS },
  114. { GF_EVENT_MEDIA_STOP, "Stop", GF_DOM_EVENT_MEDIA_ACCESS },
  115. { GF_EVENT_MEDIA_ERROR, "Error", GF_DOM_EVENT_MEDIA_ACCESS },
  116. #endif
  117. { GF_EVENT_MEDIA_SETUP_BEGIN, "setupbegin", GF_DOM_EVENT_MEDIA},
  118. { GF_EVENT_MEDIA_SETUP_DONE, "setupdone", GF_DOM_EVENT_MEDIA},
  119. { GF_EVENT_MEDIA_LOAD_START, "loadstart", GF_DOM_EVENT_MEDIA },
  120. { GF_EVENT_MEDIA_LOAD_DONE, "loaddone", GF_DOM_EVENT_MEDIA },
  121. { GF_EVENT_MEDIA_PROGRESS, "progress", GF_DOM_EVENT_MEDIA },
  122. { GF_EVENT_MEDIA_SUSPEND, "suspend", GF_DOM_EVENT_MEDIA },
  123. { GF_EVENT_ABORT, "abort", GF_DOM_EVENT_MEDIA },
  124. { GF_EVENT_ERROR, "error", GF_DOM_EVENT_MEDIA },
  125. { GF_EVENT_MEDIA_EMPTIED, "emptied", GF_DOM_EVENT_MEDIA },
  126. { GF_EVENT_MEDIA_STALLED, "stalled", GF_DOM_EVENT_MEDIA },
  127. { GF_EVENT_MEDIA_LOADED_METADATA, "loadedmetadata", GF_DOM_EVENT_MEDIA },
  128. { GF_EVENT_MEDIA_LODADED_DATA, "loadeddata", GF_DOM_EVENT_MEDIA },
  129. { GF_EVENT_MEDIA_CANPLAY, "canplay", GF_DOM_EVENT_MEDIA },
  130. { GF_EVENT_MEDIA_CANPLAYTHROUGH, "canplaythrough", GF_DOM_EVENT_MEDIA },
  131. { GF_EVENT_MEDIA_PLAYING, "playing", GF_DOM_EVENT_MEDIA },
  132. { GF_EVENT_MEDIA_WAITING, "waiting", GF_DOM_EVENT_MEDIA },
  133. { GF_EVENT_MEDIA_SEEKING, "seeking", GF_DOM_EVENT_MEDIA },
  134. { GF_EVENT_MEDIA_SEEKED, "seeked", GF_DOM_EVENT_MEDIA },
  135. { GF_EVENT_MEDIA_ENDED, "ended", GF_DOM_EVENT_MEDIA },
  136. { GF_EVENT_MEDIA_DURATION_CHANGED, "durationchanged", GF_DOM_EVENT_MEDIA },
  137. { GF_EVENT_MEDIA_TIME_UPDATE, "timeupdate", GF_DOM_EVENT_MEDIA },
  138. { GF_EVENT_PLAY, "play", GF_DOM_EVENT_MEDIA },
  139. { GF_EVENT_PAUSE, "pause", GF_DOM_EVENT_MEDIA },
  140. { GF_EVENT_MEDIA_RATECHANGE, "ratechange", GF_DOM_EVENT_MEDIA },
  141. { GF_EVENT_MEDIA_VOLUME_CHANGED, "volumechange", GF_DOM_EVENT_MEDIA },
  142. /* Media Source Events */
  143. { GF_EVENT_HTML_MSE_SOURCE_OPEN, "sourceopen", GF_DOM_EVENT_MEDIASOURCE },
  144. { GF_EVENT_HTML_MSE_SOURCE_ENDED, "sourceended", GF_DOM_EVENT_MEDIASOURCE },
  145. { GF_EVENT_HTML_MSE_SOURCE_CLOSE, "sourceclose", GF_DOM_EVENT_MEDIASOURCE },
  146. { GF_EVENT_HTML_MSE_APPEND_START, "appendstart", GF_DOM_EVENT_MEDIASOURCE },
  147. { GF_EVENT_HTML_MSE_APPEND_END, "appendend", GF_DOM_EVENT_MEDIASOURCE },
  148. { GF_EVENT_HTML_MSE_APPEND_ERROR, "error", GF_DOM_EVENT_MEDIASOURCE },
  149. { GF_EVENT_HTML_MSE_APPEND_ABORT, "abort", GF_DOM_EVENT_MEDIASOURCE },
  150. { GF_EVENT_HTML_MSE_ADD_SOURCE_BUFFER, "addsourcebuffer", GF_DOM_EVENT_MEDIASOURCE },
  151. { GF_EVENT_HTML_MSE_REMOVE_SOURCE_BUFFER, "removesourcebuffer", GF_DOM_EVENT_MEDIASOURCE },
  152. /*GPAC internals*/
  153. { GF_EVENT_SCENE_ATTACHED, "gpac_scene_attached", GF_DOM_EVENT_DOM },
  154. { GF_EVENT_VP_RESIZE, "gpac_vp_changed", GF_DOM_EVENT_DOM },
  155. };
  156. GF_EXPORT
  157. u32 gf_dom_event_type_by_name(const char *name)
  158. {
  159. u32 i, count;
  160. count = sizeof(defined_dom_events) / sizeof(struct dom_event_def);
  161. if (!name) return GF_EVENT_UNKNOWN;
  162. if ((name[0]=='o') && (name[1]=='n')) name += 2;
  163. for (i=0;i<count;i++) {
  164. if (!strcmp(name, defined_dom_events[i].name))
  165. return defined_dom_events[i].event;
  166. }
  167. return GF_EVENT_UNKNOWN;
  168. }
  169. const char *gf_dom_event_get_name(u32 type)
  170. {
  171. u32 i, count;
  172. count = sizeof(defined_dom_events) / sizeof(struct dom_event_def);
  173. for (i=0;i<count;i++) {
  174. if (defined_dom_events[i].event == type)
  175. return defined_dom_events[i].name;
  176. }
  177. return "unknown";
  178. }
  179. u32 gf_dom_event_get_category(u32 type)
  180. {
  181. u32 i, count;
  182. count = sizeof(defined_dom_events) / sizeof(struct dom_event_def);
  183. for (i=0;i<count;i++) {
  184. if (defined_dom_events[i].event == type)
  185. return defined_dom_events[i].category;
  186. }
  187. return 0;
  188. }
  189. static const struct predef_keyid {u32 key_code; const char *name; } predefined_key_identifiers[] =
  190. {
  191. { GF_KEY_ACCEPT, "Accept" },
  192. { GF_KEY_AGAIN, "Again" },
  193. { GF_KEY_ALLCANDIDATES, "AllCandidates" },
  194. { GF_KEY_ALPHANUM, "Alphanumeric" },
  195. { GF_KEY_ALT, "Alt" },
  196. { GF_KEY_ALTGRAPH, "AltGraph" },
  197. { GF_KEY_APPS, "Apps" },
  198. { GF_KEY_ATTN, "Attn" },
  199. { GF_KEY_BROWSERBACK, "BrowserBack" },
  200. { GF_KEY_BROWSERFAVORITES, "BrowserFavorites" },
  201. { GF_KEY_BROWSERFORWARD, "BrowserForward" },
  202. { GF_KEY_BROWSERHOME, "BrowserHome" },
  203. { GF_KEY_BROWSERREFRESH, "BrowserRefresh" },
  204. { GF_KEY_BROWSERSEARCH, "BrowserSearch" },
  205. { GF_KEY_BROWSERSTOP, "BrowserStop" },
  206. { GF_KEY_CAPSLOCK, "CapsLock" },
  207. { GF_KEY_CLEAR, "Clear" },
  208. { GF_KEY_CODEINPUT, "CodeInput" },
  209. { GF_KEY_COMPOSE, "Compose" },
  210. { GF_KEY_CONTROL, "Control" },
  211. { GF_KEY_CRSEL, "Crsel" },
  212. { GF_KEY_CONVERT, "Convert" },
  213. { GF_KEY_COPY, "Copy" },
  214. { GF_KEY_CUT, "Cut" },
  215. { GF_KEY_DOWN, "Down" },
  216. { GF_KEY_END, "End" },
  217. { GF_KEY_ENTER, "Enter" },
  218. { GF_KEY_ERASEEOF, "EraseEof" },
  219. { GF_KEY_EXECUTE, "Execute" },
  220. { GF_KEY_EXSEL, "Exsel" },
  221. { GF_KEY_F1, "F1" },
  222. { GF_KEY_F2, "F2" },
  223. { GF_KEY_F3, "F3" },
  224. { GF_KEY_F4, "F4" },
  225. { GF_KEY_F5, "F5" },
  226. { GF_KEY_F6, "F6" },
  227. { GF_KEY_F7, "F7" },
  228. { GF_KEY_F8, "F8" },
  229. { GF_KEY_F9, "F9" },
  230. { GF_KEY_F10, "F10" },
  231. { GF_KEY_F11, "F11" },
  232. { GF_KEY_F12, "F12" },
  233. { GF_KEY_F13, "F13" },
  234. { GF_KEY_F14, "F14" },
  235. { GF_KEY_F15, "F15" },
  236. { GF_KEY_F16, "F16" },
  237. { GF_KEY_F17, "F17" },
  238. { GF_KEY_F18, "F18" },
  239. { GF_KEY_F19, "F19" },
  240. { GF_KEY_F20, "F20" },
  241. { GF_KEY_F21, "F21" },
  242. { GF_KEY_F22, "F22" },
  243. { GF_KEY_F23, "F23" },
  244. { GF_KEY_F24, "F24" },
  245. { GF_KEY_FINALMODE, "FinalMode" },
  246. { GF_KEY_FIND, "Find" },
  247. { GF_KEY_FULLWIDTH, "FullWidth" },
  248. { GF_KEY_HALFWIDTH, "HalfWidth" },
  249. { GF_KEY_HANGULMODE, "HangulMode" },
  250. { GF_KEY_HANJAMODE, "HanjaMode" },
  251. { GF_KEY_HELP, "Help" },
  252. { GF_KEY_HIRAGANA, "Hiragana" },
  253. { GF_KEY_HOME, "Home" },
  254. { GF_KEY_INSERT, "Insert" },
  255. { GF_KEY_JAPANESEHIRAGANA, "JapaneseHiragana" },
  256. { GF_KEY_JAPANESEKATAKANA, "JapaneseKatakana" },
  257. { GF_KEY_JAPANESEROMAJI, "JapaneseRomaji" },
  258. { GF_KEY_JUNJAMODE, "JunjaMode" },
  259. { GF_KEY_KANAMODE, "KanaMode" },
  260. { GF_KEY_KANJIMODE, "KanjiMode" },
  261. { GF_KEY_KATAKANA, "Katakana" },
  262. { GF_KEY_LAUNCHAPPLICATION1, "LaunchApplication1" },
  263. { GF_KEY_LAUNCHAPPLICATION2, "LaunchApplication2" },
  264. { GF_KEY_LAUNCHMAIL, "LaunchMail" },
  265. { GF_KEY_LEFT, "Left" },
  266. { GF_KEY_META, "Meta" },
  267. { GF_KEY_MEDIANEXTTRACK, "MediaNextTrack" },
  268. { GF_KEY_MEDIAPLAYPAUSE, "MediaPlayPause" },
  269. { GF_KEY_MEDIAPREVIOUSTRACK, "MediaPreviousTrack" },
  270. { GF_KEY_MEDIASTOP, "MediaStop" },
  271. { GF_KEY_MODECHANGE, "ModeChange" },
  272. { GF_KEY_NONCONVERT, "Nonconvert" },
  273. { GF_KEY_NUMLOCK, "NumLock" },
  274. { GF_KEY_PAGEDOWN, "PageDown" },
  275. { GF_KEY_PAGEUP, "PageUp" },
  276. { GF_KEY_PASTE, "Paste" },
  277. { GF_KEY_PAUSE, "Pause" },
  278. { GF_KEY_PLAY, "Play" },
  279. { GF_KEY_PREVIOUSCANDIDATE, "PreviousCandidate" },
  280. { GF_KEY_PRINTSCREEN, "PrintScreen" },
  281. { GF_KEY_PROCESS, "Process" },
  282. { GF_KEY_PROPS, "Props" },
  283. { GF_KEY_RIGHT, "Right" },
  284. { GF_KEY_ROMANCHARACTERS, "RomanCharacters" },
  285. { GF_KEY_SCROLL, "Scroll" },
  286. { GF_KEY_SELECT, "Select" },
  287. { GF_KEY_SELECTMEDIA, "SelectMedia" },
  288. { GF_KEY_SHIFT, "Shift" },
  289. { GF_KEY_STOP, "Stop" },
  290. { GF_KEY_UP, "Up" },
  291. { GF_KEY_UNDO, "Undo" },
  292. { GF_KEY_VOLUMEDOWN, "VolumeDown" },
  293. { GF_KEY_VOLUMEMUTE, "VolumeMute" },
  294. { GF_KEY_VOLUMEUP, "VolumeUp" },
  295. { GF_KEY_WIN, "Win" },
  296. { GF_KEY_ZOOM, "Zoom" },
  297. { GF_KEY_BACKSPACE, "U+0008" },
  298. { GF_KEY_TAB, "U+0009" },
  299. { GF_KEY_CANCEL, "U+0018" },
  300. { GF_KEY_ESCAPE, "U+001B" },
  301. { GF_KEY_SPACE, "U+0020" },
  302. { GF_KEY_EXCLAMATION, "U+0021" },
  303. { GF_KEY_QUOTATION, "U+0022" },
  304. { GF_KEY_NUMBER, "U+0023" },
  305. { GF_KEY_DOLLAR, "U+0024" },
  306. { GF_KEY_AMPERSAND, "U+0026" },
  307. { GF_KEY_APOSTROPHE, "U+0027" },
  308. { GF_KEY_LEFTPARENTHESIS, "U+0028" },
  309. { GF_KEY_RIGHTPARENTHESIS, "U+0029" },
  310. { GF_KEY_STAR, "U+002A" },
  311. { GF_KEY_PLUS, "U+002B" },
  312. { GF_KEY_COMMA, "U+002C" },
  313. { GF_KEY_HYPHEN, "U+002D" },
  314. { GF_KEY_FULLSTOP, "U+002E" },
  315. { GF_KEY_SLASH, "U+002F" },
  316. { GF_KEY_0, "U+0030" },
  317. { GF_KEY_1, "U+0031" },
  318. { GF_KEY_2, "U+0032" },
  319. { GF_KEY_3, "U+0033" },
  320. { GF_KEY_4, "U+0034" },
  321. { GF_KEY_5, "U+0035" },
  322. { GF_KEY_6, "U+0036" },
  323. { GF_KEY_7, "U+0037" },
  324. { GF_KEY_8, "U+0038" },
  325. { GF_KEY_9, "U+0039" },
  326. { GF_KEY_COLON, "U+003A" },
  327. { GF_KEY_SEMICOLON, "U+003B" },
  328. { GF_KEY_LESSTHAN, "U+003C" },
  329. { GF_KEY_EQUALS, "U+003D" },
  330. { GF_KEY_GREATERTHAN, "U+003E" },
  331. { GF_KEY_QUESTION, "U+003F" },
  332. { GF_KEY_AT, "U+0040" },
  333. { GF_KEY_A, "U+0041" },
  334. { GF_KEY_B, "U+0042" },
  335. { GF_KEY_C, "U+0043" },
  336. { GF_KEY_D, "U+0044" },
  337. { GF_KEY_E, "U+0045" },
  338. { GF_KEY_F, "U+0046" },
  339. { GF_KEY_G, "U+0047" },
  340. { GF_KEY_H, "U+0048" },
  341. { GF_KEY_I, "U+0049" },
  342. { GF_KEY_J, "U+004A" },
  343. { GF_KEY_K, "U+004B" },
  344. { GF_KEY_L, "U+004C" },
  345. { GF_KEY_M, "U+004D" },
  346. { GF_KEY_N, "U+004E" },
  347. { GF_KEY_O, "U+004F" },
  348. { GF_KEY_P, "U+0050" },
  349. { GF_KEY_Q, "U+0051" },
  350. { GF_KEY_R, "U+0052" },
  351. { GF_KEY_S, "U+0053" },
  352. { GF_KEY_T, "U+0054" },
  353. { GF_KEY_U, "U+0055" },
  354. { GF_KEY_V, "U+0056" },
  355. { GF_KEY_W, "U+0057" },
  356. { GF_KEY_X, "U+0058" },
  357. { GF_KEY_Y, "U+0059" },
  358. { GF_KEY_Z, "U+005A" },
  359. { GF_KEY_LEFTSQUAREBRACKET, "U+005B" },
  360. { GF_KEY_BACKSLASH, "U+005C" },
  361. { GF_KEY_RIGHTSQUAREBRACKET, "U+005D" },
  362. { GF_KEY_CIRCUM, "U+005E" },
  363. { GF_KEY_UNDERSCORE, "U+005F" },
  364. { GF_KEY_GRAVEACCENT, "U+0060" },
  365. { GF_KEY_LEFTCURLYBRACKET, "U+007B" },
  366. { GF_KEY_PIPE, "U+007C" },
  367. { GF_KEY_RIGHTCURLYBRACKET, "U+007D" },
  368. { GF_KEY_DEL, "U+007F" },
  369. { GF_KEY_INVERTEXCLAMATION, "U+00A1" },
  370. { GF_KEY_DEADGRAVE, "U+0300" },
  371. { GF_KEY_DEADEACUTE, "U+0301" },
  372. { GF_KEY_DEADCIRCUM, "U+0302" },
  373. { GF_KEY_DEADTILDE, "U+0303" },
  374. { GF_KEY_DEADMACRON, "U+0304" },
  375. { GF_KEY_DEADBREVE, "U+0306" },
  376. { GF_KEY_DEADABOVEDOT, "U+0307" },
  377. { GF_KEY_DEADDIARESIS, "U+0308" },
  378. { GF_KEY_DEADRINGABOVE, "U+030A" },
  379. { GF_KEY_DEADDOUBLEACUTE, "U+030B" },
  380. { GF_KEY_DEADCARON, "U+030C" },
  381. { GF_KEY_DEADCEDILLA, "U+0327" },
  382. { GF_KEY_DEADOGONEK, "U+0328" },
  383. { GF_KEY_DEADIOTA, "U+0345" },
  384. { GF_KEY_EURO, "U+20AC" },
  385. { GF_KEY_DEADVOICESOUND, "U+3099" },
  386. { GF_KEY_DEADSEMIVOICESOUND, "U+309A" },
  387. { GF_KEY_CHANNELUP, "ChannelUp" },
  388. { GF_KEY_CHANNELDOWN, "ChannelDown" },
  389. { GF_KEY_TEXT, "Text" },
  390. { GF_KEY_INFO, "Info" },
  391. { GF_KEY_EPG, "EPG" },
  392. { GF_KEY_RECORD, "Record" },
  393. { GF_KEY_BEGINPAGE, "BeginPage" }
  394. };
  395. GF_EXPORT
  396. const char *gf_dom_get_key_name(u32 key_identifier)
  397. {
  398. u32 count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid);
  399. if (!key_identifier || count<=key_identifier) return "Unknown";
  400. return predefined_key_identifiers[key_identifier-1].name;
  401. }
  402. u32 gf_dom_get_key_type(char *key_name)
  403. {
  404. if (strlen(key_name) == 1) {
  405. char c[2];
  406. c[0] = key_name[0];
  407. c[1] = 0;
  408. strupr(c);
  409. if (c[0] >= 'A' && c[0] <= 'Z')
  410. return (GF_KEY_A + (c[0] - 'A') );
  411. if (c[0] >= '0' && c[0] <= '9')
  412. return ( GF_KEY_0 + (c[0] - '0') );
  413. switch (c[0]) {
  414. case '@': return GF_KEY_AT;
  415. case '*': return GF_KEY_STAR;
  416. case '#': return GF_KEY_NUMBER;
  417. case ' ': return GF_KEY_SPACE;
  418. case '!': return GF_KEY_EXCLAMATION;
  419. case '"': return GF_KEY_QUOTATION;
  420. case '$': return GF_KEY_DOLLAR;
  421. case '&': return GF_KEY_AMPERSAND;
  422. case '\'': return GF_KEY_APOSTROPHE;
  423. case '(': return GF_KEY_LEFTPARENTHESIS;
  424. case ')': return GF_KEY_RIGHTPARENTHESIS;
  425. case '+': return GF_KEY_PLUS;
  426. case ',': return GF_KEY_COMMA;
  427. case '-': return GF_KEY_HYPHEN;
  428. case '.': return GF_KEY_FULLSTOP;
  429. case '/': return GF_KEY_SLASH;
  430. case ':': return GF_KEY_COLON;
  431. case ';': return GF_KEY_SEMICOLON;
  432. case '<': return GF_KEY_LESSTHAN;
  433. case '=': return GF_KEY_EQUALS;
  434. case '>': return GF_KEY_GREATERTHAN;
  435. case '?': return GF_KEY_QUESTION;
  436. case '[': return GF_KEY_LEFTSQUAREBRACKET;
  437. case '\\': return GF_KEY_BACKSLASH;
  438. case ']': return GF_KEY_RIGHTSQUAREBRACKET;
  439. case '^': return GF_KEY_CIRCUM;
  440. case '_': return GF_KEY_UNDERSCORE;
  441. case '`': return GF_KEY_GRAVEACCENT;
  442. case '{': return GF_KEY_LEFTCURLYBRACKET;
  443. case '|': return GF_KEY_PIPE;
  444. case '}': return GF_KEY_RIGHTCURLYBRACKET;
  445. case 'Ä„': return GF_KEY_INVERTEXCLAMATION;
  446. default: return GF_KEY_UNIDENTIFIED;
  447. }
  448. } else {
  449. u32 i, count;
  450. count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid);
  451. for (i=0; i<count; i++) {
  452. if (!stricmp(key_name, predefined_key_identifiers[i].name)) {
  453. return predefined_key_identifiers[i].key_code;
  454. }
  455. }
  456. return GF_KEY_UNIDENTIFIED;
  457. }
  458. }
  459. /* Basic SVG datatype parsing functions */
  460. static const struct predef_col { const char *name; u8 r; u8 g; u8 b; } predefined_colors[] =
  461. {
  462. {"aliceblue",240, 248, 255},
  463. {"antiquewhite",250, 235, 215},
  464. {"aqua", 0, 255, 255},
  465. {"aquamarine",127, 255, 212},
  466. {"azure",240, 255, 255},
  467. {"beige",245, 245, 220},
  468. {"bisque",255, 228, 196},
  469. {"black", 0, 0, 0},
  470. {"blanchedalmond",255, 235, 205},
  471. {"blue", 0, 0, 255},
  472. {"blueviolet",138, 43, 226},
  473. {"brown",165, 42, 42},
  474. {"burlywood",222, 184, 135},
  475. {"cadetblue", 95, 158, 160},
  476. {"chartreuse",127, 255, 0},
  477. {"chocolate",210, 105, 30},
  478. {"coral",255, 127, 80},
  479. {"lightpink",255, 182, 193},
  480. {"lightsalmon",255, 160, 122},
  481. {"lightseagreen", 32, 178, 170},
  482. {"lightskyblue",135, 206, 250},
  483. {"lightslategray",119, 136, 153},
  484. {"lightslategrey",119, 136, 153},
  485. {"lightsteelblue",176, 196, 222},
  486. {"lightyellow",255, 255, 224},
  487. {"lime", 0, 255, 0},
  488. {"limegreen", 50, 205, 50},
  489. {"linen",250, 240, 230},
  490. {"magenta",255, 0, 255},
  491. {"maroon",128, 0, 0},
  492. {"mediumaquamarine",102, 205, 170},
  493. {"mediumblue", 0, 0, 205},
  494. {"mediumorchid",186, 85, 211},
  495. {"cornflowerblue",100, 149, 237},
  496. {"cornsilk",255, 248, 220},
  497. {"crimson",220, 20, 60},
  498. {"cyan", 0, 255, 255},
  499. {"darkblue", 0, 0, 139},
  500. {"darkcyan", 0, 139, 139},
  501. {"darkgoldenrod",184, 134, 11},
  502. {"darkgray",169, 169, 169},
  503. {"darkgreen", 0, 100, 0},
  504. {"darkgrey",169, 169, 169},
  505. {"darkkhaki",189, 183, 107},
  506. {"darkmagenta",139, 0, 139},
  507. {"darkolivegreen", 85, 107, 47},
  508. {"darkorange",255, 140, 0},
  509. {"darkorchid",153, 50, 204},
  510. {"darkred",139, 0, 0},
  511. {"darksalmon",233, 150, 122},
  512. {"darkseagreen",143, 188, 143},
  513. {"darkslateblue", 72, 61, 139},
  514. {"darkslategray", 47, 79, 79},
  515. {"darkslategrey", 47, 79, 79},
  516. {"darkturquoise", 0, 206, 209},
  517. {"darkviolet",148, 0, 211},
  518. {"deeppink",255, 20, 147},
  519. {"deepskyblue", 0, 191, 255},
  520. {"dimgray",105, 105, 105},
  521. {"dimgrey",105, 105, 105},
  522. {"dodgerblue", 30, 144, 255},
  523. {"firebrick",178, 34, 34},
  524. {"floralwhite",255, 250, 240},
  525. {"forestgreen", 34, 139, 34},
  526. {"fuchsia",255, 0, 255},
  527. {"gainsboro",220, 220, 220},
  528. {"ghostwhite",248, 248, 255},
  529. {"gold",255, 215, 0},
  530. {"goldenrod",218, 165, 32},
  531. {"gray",128, 128, 128},
  532. {"grey",128, 128, 128},
  533. {"green", 0, 128, 0},
  534. {"greenyellow",173, 255, 47},
  535. {"honeydew",240, 255, 240},
  536. {"hotpink",255, 105, 180},
  537. {"indianred",205, 92, 92},
  538. {"indigo", 75, 0, 130},
  539. {"ivory",255, 255, 240},
  540. {"khaki",240, 230, 140},
  541. {"lavender",230, 230, 25},
  542. {"lavenderblush",255, 240, 245},
  543. {"mediumpurple",147, 112, 219},
  544. {"mediumseagreen", 60, 179, 113},
  545. {"mediumslateblue",123, 104, 238},
  546. {"mediumspringgreen", 0, 250, 154},
  547. {"mediumturquoise", 72, 209, 204},
  548. {"mediumvioletred",199, 21, 133},
  549. {"midnightblue", 25, 25, 112},
  550. {"mintcream",245, 255, 250},
  551. {"mistyrose",255, 228, 225},
  552. {"moccasin",255, 228, 181},
  553. {"navajowhite",255, 222, 173},
  554. {"navy", 0, 0, 128},
  555. {"oldlace",253, 245, 230},
  556. {"olive",128, 128, 0},
  557. {"olivedrab",107, 142, 35},
  558. {"orange",255, 165, 0},
  559. {"orangered",255, 69, 0},
  560. {"orchid",218, 112, 214},
  561. {"palegoldenrod",238, 232, 170},
  562. {"palegreen",152, 251, 152},
  563. {"paleturquoise",175, 238, 238},
  564. {"palevioletred",219, 112, 147},
  565. {"papayawhip",255, 239, 213},
  566. {"peachpuff",255, 218, 185},
  567. {"peru",205, 133, 63},
  568. {"pink",255, 192, 203},
  569. {"plum",221, 160, 221},
  570. {"powderblue",176, 224, 230},
  571. {"purple",128, 0, 128},
  572. {"red",255, 0, 0},
  573. {"rosybrown",188, 143, 143},
  574. {"royalblue", 65, 105, 225},
  575. {"saddlebrown",139, 69, 19},
  576. {"salmon",250, 128, 114},
  577. {"sandybrown",244, 164, 96},
  578. {"seagreen", 46, 139, 87},
  579. {"seashell",255, 245, 238},
  580. {"sienna",160, 82, 45},
  581. {"silver",192, 192, 192},
  582. {"skyblue",135, 206, 235},
  583. {"slateblue",106, 90, 205},
  584. {"slategray",112, 128, 144},
  585. {"slategrey",112, 128, 144},
  586. {"snow",255, 250, 250},
  587. {"springgreen", 0, 255, 127},
  588. {"steelblue", 70, 130, 180},
  589. {"tan",210, 180, 140},
  590. {"teal", 0, 128, 128},
  591. {"lawngreen",124, 252, 0},
  592. {"lemonchiffon",255, 250, 205},
  593. {"lightblue",173, 216, 230},
  594. {"lightcoral",240, 128, 128},
  595. {"lightcyan",224, 255, 255},
  596. {"lightgoldenrodyellow",250, 250, 210},
  597. {"lightgray",211, 211, 211},
  598. {"lightgreen",144, 238, 144},
  599. {"lightgrey",211, 211, 211},
  600. {"thistle",216, 191, 216},
  601. {"tomato",255, 99, 71},
  602. {"turquoise", 64, 224, 208},
  603. {"violet",238, 130, 238},
  604. {"wheat",245, 222, 179},
  605. {"white",255, 255, 255},
  606. {"whitesmoke",245, 245, 245},
  607. {"yellow",255, 255, 0},
  608. {"yellowgreen",154, 205, 50}
  609. };
  610. /* Basic SVG datatype parsing functions */
  611. static const struct sys_col { const char *name; u8 type; } system_colors[] =
  612. {
  613. {"ActiveBorder", SVG_COLOR_ACTIVE_BORDER},
  614. {"ActiveCaption", SVG_COLOR_ACTIVE_CAPTION},
  615. {"AppWorkspace", SVG_COLOR_APP_WORKSPACE},
  616. {"Background", SVG_COLOR_BACKGROUND},
  617. {"ButtonFace", SVG_COLOR_BUTTON_FACE},
  618. {"ButtonHighlight", SVG_COLOR_BUTTON_HIGHLIGHT},
  619. {"ButtonShadow", SVG_COLOR_BUTTON_SHADOW},
  620. {"ButtonText", SVG_COLOR_BUTTON_TEXT},
  621. {"CaptionText", SVG_COLOR_CAPTION_TEXT},
  622. {"GrayText", SVG_COLOR_GRAY_TEXT},
  623. {"Highlight", SVG_COLOR_HIGHLIGHT},
  624. {"HighlightText", SVG_COLOR_HIGHLIGHT_TEXT},
  625. {"InactiveBorder", SVG_COLOR_INACTIVE_BORDER},
  626. {"InactiveCaption", SVG_COLOR_INACTIVE_CAPTION},
  627. {"InactiveCaptionText", SVG_COLOR_INACTIVE_CAPTION_TEXT},
  628. {"InfoBackground", SVG_COLOR_INFO_BACKGROUND},
  629. {"InfoText", SVG_COLOR_INFO_TEXT},
  630. {"Menu", SVG_COLOR_MENU},
  631. {"MenuText", SVG_COLOR_MENU_TEXT},
  632. {"Scrollbar", SVG_COLOR_SCROLLBAR},
  633. {"ThreeDDarkShadow", SVG_COLOR_3D_DARK_SHADOW},
  634. {"ThreeDFace", SVG_COLOR_3D_FACE},
  635. {"ThreeDHighlight", SVG_COLOR_3D_HIGHLIGHT},
  636. {"ThreeDLightShadow", SVG_COLOR_3D_LIGHT_SHADOW},
  637. {"ThreeDShadow", SVG_COLOR_3D_SHADOW},
  638. {"Window", SVG_COLOR_WINDOW},
  639. {"WindowFrame", SVG_COLOR_WINDOW_FRAME},
  640. {"WindowText", SVG_COLOR_WINDOW_TEXT},
  641. };
  642. /* parses an color from a named color HTML or CSS 2 */
  643. static void svg_parse_named_color(SVG_Color *col, char *attribute_content)
  644. {
  645. u32 i, count;
  646. count = sizeof(predefined_colors) / sizeof(struct predef_col);
  647. for (i=0; i<count; i++) {
  648. if (!strcmp(attribute_content, predefined_colors[i].name)) {
  649. col->red = INT2FIX(predefined_colors[i].r) / 255;
  650. col->green = INT2FIX(predefined_colors[i].g) / 255;
  651. col->blue = INT2FIX(predefined_colors[i].b) / 255;
  652. col->type = SVG_COLOR_RGBCOLOR;
  653. return;
  654. }
  655. }
  656. count = sizeof(system_colors) / sizeof(struct sys_col);
  657. for (i=0; i<count; i++) {
  658. if (!strcmp(attribute_content, system_colors[i].name)) {
  659. col->type = system_colors[i].type;
  660. return;
  661. }
  662. }
  663. }
  664. const char *gf_svg_get_system_paint_server_name(u32 paint_type)
  665. {
  666. u32 i, count;
  667. count = sizeof(system_colors) / sizeof(struct sys_col);
  668. for (i=0; i<count; i++) {
  669. if (paint_type == system_colors[i].type) return system_colors[i].name;
  670. }
  671. return "undefined";
  672. }
  673. u32 gf_svg_get_system_paint_server_type(const char *name)
  674. {
  675. u32 i, count;
  676. count = sizeof(system_colors) / sizeof(struct sys_col);
  677. for (i=0; i<count; i++) {
  678. if (!strcmp(name, system_colors[i].name)) return system_colors[i].type;
  679. }
  680. return 0;
  681. }
  682. /* Reads an SVG Color
  683. either #RRGGBB, #RGB, rgb(r,g,b) in [0,255] , colorname, or 'r g b' in [0,1]
  684. ignores any space, comma, semi-column before and any space after
  685. TODO:
  686. transform the char into char and duplicate the input, instead of modifying it
  687. be more robust to errors in color description ex rgb(0 0 0)
  688. */
  689. static void svg_parse_color(SVG_Color *col, char *attribute_content)
  690. {
  691. char *str = attribute_content;
  692. while (str[strlen(attribute_content)-1] == ' ') str[strlen(attribute_content)-1] = 0;
  693. while (*str != 0 && (*str == ' ' || *str == ',' || *str == ';')) str++;
  694. if (!strcmp(str, "currentColor")) {
  695. col->type = SVG_COLOR_CURRENTCOLOR;
  696. return;
  697. } else if (!strcmp(str, "inherit")) {
  698. col->type = SVG_COLOR_INHERIT;
  699. return;
  700. } else if (str[0]=='#') {
  701. u32 val;
  702. sscanf(str+1, "%x", &val);
  703. if (strlen(str) == 7) {
  704. col->red = INT2FIX((val>>16) & 0xFF) / 255;
  705. col->green = INT2FIX((val>>8) & 0xFF) / 255;
  706. col->blue = INT2FIX(val & 0xFF) / 255;
  707. } else {
  708. col->red = INT2FIX((val>>8) & 0xF) / 15;
  709. col->green = INT2FIX((val>>4) & 0xF) / 15;
  710. col->blue = INT2FIX(val & 0xF) / 15;
  711. }
  712. col->type = SVG_COLOR_RGBCOLOR;
  713. } else if (strstr(str, "rgb(") || strstr(str, "RGB(")) {
  714. Float _val;
  715. u8 is_percentage= 0;
  716. if (strstr(str, "%")) is_percentage = 1;
  717. str = strstr(str, "(");
  718. str++;
  719. sscanf(str, "%f", &_val); col->red = FLT2FIX(_val);
  720. str = strstr(str, ",");
  721. if (!str) {
  722. /* space separated colors/percentages are not allowed neither in SVG 1.1 nor in SVG T1.2 */
  723. col->red = col->green = col->blue = 0;
  724. return;
  725. }
  726. str++;
  727. sscanf(str, "%f", &_val); col->green = FLT2FIX(_val);
  728. str = strstr(str, ",");
  729. if (!str) {
  730. /* space separated colors/percentages are not allowed neither in SVG 1.1 nor in SVG T1.2 */
  731. col->red = col->green = col->blue = 0;
  732. return;
  733. }
  734. str++;
  735. sscanf(str, "%f", &_val); col->blue = FLT2FIX(_val);
  736. if (is_percentage) {
  737. col->red /= 100;
  738. col->green /= 100;
  739. col->blue /= 100;
  740. } else {
  741. col->red /= 255;
  742. col->green /= 255;
  743. col->blue /= 255;
  744. }
  745. col->type = SVG_COLOR_RGBCOLOR;
  746. } else if ((str[0] >= 'a' && str[0] <= 'z')
  747. || (str[0] >= 'A' && str[0] <= 'Z')) {
  748. svg_parse_named_color(col, str);
  749. } else {
  750. Float _r, _g, _b;
  751. sscanf(str, "%f %f %f", &_r, &_g, &_b);
  752. col->red = FLT2FIX(_r);
  753. col->green = FLT2FIX(_g);
  754. col->blue = FLT2FIX(_b);
  755. col->type = SVG_COLOR_RGBCOLOR;
  756. }
  757. }
  758. /*
  759. Reads a number (i.e. without unit) according to the CSS syntax (same as SVG paths and transforms)
  760. trims any space, comma, semi-column before or after (TODO: fix this)
  761. reads an optional + or -
  762. then reads a digit between 0 and 9
  763. optionally followed by an '.' and digits between 0 and 9
  764. optionally followed by e or E and digits between 0 and 9
  765. Returns the number of chars read in d
  766. */
  767. static u32 svg_parse_number(char *d, Fixed *f, Bool is_angle)
  768. {
  769. u32 nb_digit_before = 0;
  770. u32 nb_digit_after = 0;
  771. Bool has_fractional = 0;
  772. Bool is_negative = 0;
  773. Float _val = 0;
  774. u32 i = 0;
  775. /* warning the comma and semicolumn should not be there when parsing a number in a path */
  776. while ((d[i] != 0) && strchr(" ,;\r\n\t", d[i])) i++;
  777. if (!d[i]) {
  778. GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Parsing] Parsing number with empty string or only spaces: %s\n", d));
  779. return 0;
  780. }
  781. if (d[i] == '+') {
  782. i++;
  783. } else if (d[i] == '-') {
  784. is_negative = 1;
  785. i++;
  786. }
  787. /* Warning: this is not normal, should be detected somehow by checking the BNF */
  788. /* if ((d[i]=='N') && (d[i+1]=='a') && (d[i+2]=='N')) {
  789. i+= 3;
  790. _val = 0;
  791. goto end;
  792. }*/
  793. /* read the digit-sequence token of the BNF */
  794. while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) {
  795. _val = _val*10 + (d[i]-'0');
  796. nb_digit_before++;
  797. i++;
  798. }
  799. if (d[i] == '.') {
  800. has_fractional = 1;
  801. i++;
  802. while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) {
  803. _val = _val*10 + (d[i]-'0');
  804. nb_digit_after++;
  805. i++;
  806. }
  807. if (nb_digit_after) {
  808. _val /= (Float)pow(10,nb_digit_after);
  809. } else if (nb_digit_before == 0) {
  810. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing number (expecting digits before or after a '.': %s\n", d));
  811. return 0;
  812. } else {
  813. /* dangling '.' without digits after. This is allowed by the BNF */
  814. }
  815. }
  816. if ((nb_digit_before == 0) && (has_fractional == 0)) {
  817. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing number (expecting digits):%s\n", d));
  818. return 0;
  819. }
  820. /* reading the exponent */
  821. if (d[i] == 'e' || d[i] == 'E') {
  822. Bool neg_exp = 0;
  823. u32 nb_exp_digits = 0;
  824. s32 exp = 0;
  825. i++;
  826. if (d[i] == '+') i++;
  827. else if (d[i] == '-') {
  828. i++;
  829. neg_exp=1;
  830. }
  831. while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) {
  832. exp = exp*10 + (d[i]-'0');
  833. nb_exp_digits++;
  834. i++;
  835. }
  836. if (nb_exp_digits) {
  837. _val *= (Float)pow(10, neg_exp ? -exp : exp);
  838. } else {
  839. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing exponent, 'e' or 'E' should be followed by digits: %s\n", d));
  840. return 0;
  841. }
  842. }
  843. /* We can now produce the final number */
  844. if (is_negative) _val *= -1;
  845. if (is_angle) {
  846. _val/=180;
  847. (*f) = gf_mulfix(FLT2FIX(_val), GF_PI);
  848. } else {
  849. (*f) = FLT2FIX(_val);
  850. }
  851. /* warning the comma and semicolumn should not be there when parsing a path number */
  852. while (d[i] != 0 && (d[i] == ' ' || d[i] == ',' || d[i] == ';')) i++;
  853. return i;
  854. }
  855. /*
  856. Parse an Offset Value, i.e +/- Clock Value
  857. */
  858. static GF_Err svg_parse_clock_value(char *d, Double *clock_value)
  859. {
  860. char *tmp;
  861. s32 sign = 1;
  862. if (!d) return GF_BAD_PARAM;
  863. if (!d[0]) return GF_BAD_PARAM;
  864. if (d[0] == '+') d++;
  865. else if (d[0] == '-') { sign = -1; d++; }
  866. if (!d[0]) return GF_BAD_PARAM;
  867. /* According to SVG, the following are invalid syntaxes (see animate-elem-225-t.svg)
  868. '+-2s'
  869. '1++s' even though sscanf returns the right values
  870. */
  871. if (strchr(d, '+') || strchr(d, '-')) return GF_BAD_PARAM;
  872. /* No embedded white space is allowed in clock values,
  873. although leading and trailing white space characters will be ignored.*/
  874. while (*d == ' ') d++;
  875. if ((tmp = strchr(d, ':'))) {
  876. /* Full or Partial Clock value */
  877. tmp++;
  878. if ((tmp = strchr(tmp, ':'))) {
  879. /* Full Clock value : hh:mm:ss(.frac) */
  880. u32 hours;
  881. u32 minutes;
  882. Float seconds;
  883. if (sscanf(d, "%u:%u:%f", &hours, &minutes, &seconds) < 3) return GF_BAD_PARAM;
  884. *clock_value = hours*3600 + minutes*60 + seconds;
  885. } else {
  886. /* Partial Clock value : mm:ss(.frac) */
  887. s32 minutes;
  888. Float seconds;
  889. if (sscanf(d, "%d:%f", &minutes, &seconds) < 2) return GF_BAD_PARAM;
  890. *clock_value = minutes*60 + seconds;
  891. }
  892. } else if ((tmp = strstr(d, "h"))) {
  893. Float f;
  894. if (sscanf(d, "%fh", &f) == 0) return GF_BAD_PARAM;
  895. *clock_value = 3600*f;
  896. } else if (strstr(d, "min")) {
  897. Float f;
  898. if (sscanf(d, "%fmin", &f) == 0) return GF_BAD_PARAM;
  899. *clock_value = 60*f;
  900. } else if ((tmp = strstr(d, "ms"))) {
  901. Float f;
  902. if (sscanf(d, "%fms", &f) == 0) return GF_BAD_PARAM;
  903. *clock_value = f/1000;
  904. } else if (strchr(d, 's')) {
  905. Float f;
  906. if (sscanf(d, "%fs", &f) == 0) return GF_BAD_PARAM;
  907. *clock_value = f;
  908. } else {
  909. Float f;
  910. if (sscanf(d, "%f", &f) == 0) return GF_BAD_PARAM;
  911. *clock_value = f;
  912. }
  913. *clock_value *= sign;
  914. return GF_OK;
  915. }
  916. /* Parses one SVG time value:
  917. indefinite,
  918. element_id.event_name
  919. wallclock,
  920. accessKey,
  921. events,
  922. clock value.
  923. */
  924. static GF_Err smil_parse_time(GF_Node *elt, SMIL_Time *v, char *d)
  925. {
  926. GF_Err e = GF_OK;
  927. char *tmp;
  928. /* Offset Values */
  929. if ((d[0] >= '0' && d[0] <= '9') || d[0] == '+' || d[0] == '-'){
  930. v->type = GF_SMIL_TIME_CLOCK;
  931. return svg_parse_clock_value(d, &(v->clock));
  932. }
  933. /* Indefinite Values */
  934. else if (!strcmp(d, "indefinite")) {
  935. v->type = GF_SMIL_TIME_INDEFINITE;
  936. return GF_OK;
  937. }
  938. /* Wallclock Values */
  939. else if ((tmp = strstr(d, "wallclock("))) {
  940. u32 year, month, day;
  941. u32 hours, minutes;
  942. u32 nhours, nminutes;
  943. Float seconds;
  944. char *tmp1, *tmp2;
  945. v->type = GF_SMIL_TIME_WALLCLOCK;
  946. tmp += 10;
  947. if ((tmp1 = strchr(tmp, 'T')) ) {
  948. /* From tmp to wallStartTime, we parse a date */
  949. sscanf(tmp, "%u-%u-%dT", &year, &month, &day);
  950. tmp1++;
  951. tmp = tmp1;
  952. }
  953. if ((tmp1 = strchr(tmp, ':')) ) {
  954. if ((tmp2 = strchr(tmp1, ':')) ) {
  955. /* HHMMSS */
  956. sscanf(tmp, "%u:%u:%f", &hours, &minutes, &seconds);
  957. } else {
  958. /* HHMM */
  959. sscanf(tmp, "%u:%u", &hours, &minutes);
  960. }
  961. }
  962. if (strchr(tmp, 'Z')) {
  963. return GF_OK;
  964. } else {
  965. if ( (tmp1 = strchr(tmp, '+')) ) {
  966. sscanf(tmp1, "%u:%u", &nhours, &nminutes);
  967. } else if ( (tmp1 = strchr(tmp, '-')) ) {
  968. sscanf(tmp1, "%u:%u", &nhours, &nminutes);
  969. }
  970. }
  971. return GF_OK;
  972. }
  973. /* AccessKey Values */
  974. else if ((tmp = strstr(d, "accessKey("))) {
  975. char *sep;
  976. v->type = GF_SMIL_TIME_EVENT;
  977. v->event.type = GF_EVENT_KEYDOWN;
  978. v->element = elt->sgprivate->scenegraph->RootNode;
  979. tmp+=10;
  980. sep = strchr(d, ')');
  981. sep[0] = 0;
  982. v->event.parameter = gf_dom_get_key_type(tmp);
  983. sep++;
  984. if ((tmp = strchr(sep, '+')) || (tmp = strchr(sep, '-'))) {
  985. char c = *tmp;
  986. tmp++;
  987. e = svg_parse_clock_value(tmp, &(v->clock));
  988. if (c == '-') v->clock *= -1;
  989. }
  990. return e;
  991. }
  992. else {
  993. Bool had_param = 0;
  994. char *tmp2;
  995. v->type = GF_SMIL_TIME_EVENT;
  996. if ((tmp = strchr(d, '.'))) {
  997. tmp[0] = 0;
  998. if (strlen(d) == 0) {
  999. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] expecting an id before '.' in SMIL Time .%s\n", tmp+1));
  1000. return GF_BAD_PARAM;
  1001. }
  1002. v->element_id = gf_strdup(d);
  1003. tmp[0] = '.';
  1004. tmp++;
  1005. } else {
  1006. tmp = d;
  1007. }
  1008. if ((tmp2 = strchr(tmp, '('))) {
  1009. tmp2[0] = 0;
  1010. v->event.type = gf_dom_event_type_by_name(tmp);
  1011. tmp2[0] = '(';
  1012. tmp2++;
  1013. had_param = 1;
  1014. v->event.parameter = atoi(tmp2);
  1015. tmp = strchr(tmp2, ')');
  1016. if (!tmp) {
  1017. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] expecting ')' in SMIL Time %s\n", d));
  1018. return GF_BAD_PARAM;
  1019. }
  1020. tmp++;
  1021. }
  1022. if ((tmp2 = strchr(tmp, '+')) || (tmp2 = strchr(tmp, '-'))) {
  1023. char c = *tmp2;
  1024. char *tmp3 = tmp2;
  1025. tmp2[0] = 0;
  1026. tmp3--;
  1027. while (*tmp3==' ') { *tmp3=0; tmp3--; }
  1028. if (v->event.type == 0) v->event.type = gf_dom_event_type_by_name(tmp);
  1029. if (!had_param && (v->event.type == GF_EVENT_REPEAT || v->event.type == GF_EVENT_REPEAT_EVENT))
  1030. v->event.parameter = 1;
  1031. tmp2[0] = c;
  1032. tmp2++;
  1033. e = svg_parse_clock_value(tmp2, &(v->clock));
  1034. if (c == '-') v->clock *= -1;
  1035. return e;
  1036. } else {
  1037. if (v->event.type == 0) v->event.type = gf_dom_event_type_by_name(tmp);
  1038. if (!had_param && (v->event.type == GF_EVENT_REPEAT || v->event.type == GF_EVENT_REPEAT_EVENT))
  1039. v->event.parameter = 1;
  1040. }
  1041. }
  1042. return GF_OK;
  1043. }
  1044. /* Parses a list of SVG transformations and collapses them in the given matrix */
  1045. Bool gf_svg_parse_transformlist(GF_Matrix2D *mat, char *attribute_content)
  1046. {
  1047. GF_Matrix2D tmp;
  1048. char *str;
  1049. u32 read_chars;
  1050. u32 i;
  1051. gf_mx2d_init(*mat);
  1052. str = attribute_content;
  1053. i = 0;
  1054. while (str[i] != 0) {
  1055. while (str[i] == ' ') i++;
  1056. if (str[i] == ',') i++;
  1057. while (str[i] == ' ') i++;
  1058. if (strstr(str+i, "scale")==str+i) {
  1059. i += 5;
  1060. while(str[i] == ' ') i++;
  1061. if (str[i] == '(') {
  1062. Fixed sx, sy;
  1063. i++;
  1064. read_chars = svg_parse_number(&(str[i]), &sx, 0);
  1065. if (!read_chars) {
  1066. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading sx component in scale: %s\n", attribute_content));
  1067. return 0;
  1068. }
  1069. i += read_chars;
  1070. if (str[i] == ')') {
  1071. sy = sx;
  1072. } else {
  1073. read_chars = svg_parse_number(&(str[i]), &sy, 0);
  1074. if (!read_chars) {
  1075. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading sy component in scale: %s\n", attribute_content));
  1076. return 0;
  1077. }
  1078. i += read_chars;
  1079. }
  1080. gf_mx2d_init(tmp);
  1081. gf_mx2d_add_scale(&tmp, sx, sy);
  1082. gf_mx2d_add_matrix(&tmp, mat);
  1083. gf_mx2d_copy(*mat, tmp);
  1084. while(str[i] == ' ') i++;
  1085. if (str[i] == ')') i++;
  1086. else {
  1087. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
  1088. return 0;
  1089. }
  1090. } else {
  1091. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
  1092. return 0;
  1093. }
  1094. } else if (strstr(str+i, "translate")==str+i) {
  1095. i += 9;
  1096. while(str[i] == ' ') i++;
  1097. if (str[i] == '(') {
  1098. Fixed tx, ty;
  1099. i++;
  1100. read_chars = svg_parse_number(&(str[i]), &tx, 0);
  1101. if (!read_chars) {
  1102. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading tx component in translate: %s\n", attribute_content));
  1103. return 0;
  1104. }
  1105. i += read_chars;
  1106. if (str[i] == ')') {
  1107. ty = 0;
  1108. } else {
  1109. read_chars = svg_parse_number(&(str[i]), &ty, 0);
  1110. if (!read_chars) {
  1111. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading ty component in translate: %s\n", attribute_content));
  1112. return 0;
  1113. }
  1114. i += read_chars;
  1115. }
  1116. gf_mx2d_init(tmp);
  1117. gf_mx2d_add_translation(&tmp, tx, ty);
  1118. gf_mx2d_add_matrix(&tmp, mat);
  1119. gf_mx2d_copy(*mat, tmp);
  1120. while(str[i] == ' ') i++;
  1121. if (str[i] == ')') i++;
  1122. else {
  1123. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
  1124. return 0;
  1125. }
  1126. } else {
  1127. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
  1128. return 0;
  1129. }
  1130. } else if (strstr(str+i, "rotate")==str+i) {
  1131. i += 6;
  1132. while(str[i] == ' ') i++;
  1133. if (str[i] == '(') {
  1134. Fixed angle, cx, cy;
  1135. i++;
  1136. read_chars = svg_parse_number(&(str[i]), &angle, 1);
  1137. if (!read_chars) {
  1138. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading angle component in rotate: %s\n", attribute_content));
  1139. return 0;
  1140. }
  1141. i += read_chars;
  1142. if (str[i] == ')') {
  1143. cx = cy = 0;
  1144. } else {
  1145. read_chars = svg_parse_number(&(str[i]), &cx, 0);
  1146. if (!read_chars) {
  1147. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading cx component in rotate: %s\n", attribute_content));
  1148. return 0;
  1149. }
  1150. i += read_chars;
  1151. read_chars = svg_parse_number(&(str[i]), &cy, 0);
  1152. if (!read_chars) {
  1153. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading cy component in rotate: %s\n", attribute_content));
  1154. return 0;
  1155. }
  1156. i += read_chars;
  1157. }
  1158. gf_mx2d_init(tmp);
  1159. gf_mx2d_add_rotation(&tmp, cx, cy, angle);
  1160. gf_mx2d_add_matrix(&tmp, mat);
  1161. gf_mx2d_copy(*mat, tmp);
  1162. while(str[i] == ' ') i++;
  1163. if (str[i] == ')') i++;
  1164. else {
  1165. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
  1166. return 0;
  1167. }
  1168. } else {
  1169. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
  1170. return 0;
  1171. }
  1172. } else if (strstr(str+i, "skewX")==str+i) {
  1173. i += 5;
  1174. while(str[i] == ' ') i++;
  1175. if (str[i] == '(') {
  1176. Fixed angle;
  1177. i++;
  1178. read_chars = svg_parse_number(&(str[i]), &angle, 1);
  1179. if (!read_chars) {
  1180. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading angle in skewX: %s\n", attribute_content));
  1181. return 0;
  1182. }
  1183. i += read_chars;
  1184. gf_mx2d_init(tmp);
  1185. gf_mx2d_add_skew_x(&tmp, angle);
  1186. gf_mx2d_add_matrix(&tmp, mat);
  1187. gf_mx2d_copy(*mat, tmp);
  1188. while(str[i] == ' ') i++;
  1189. if (str[i] == ')') i++;
  1190. else {
  1191. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
  1192. return 0;
  1193. }
  1194. } else {
  1195. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
  1196. return 0;
  1197. }
  1198. } else if (strstr(str+i, "skewY")==str+i) {
  1199. i += 5;
  1200. while(str[i] == ' ') i++;
  1201. if (str[i] == '(') {
  1202. Fixed angle;
  1203. i++;
  1204. read_chars = svg_parse_number(&(str[i]), &angle, 1);
  1205. if (!read_chars) {
  1206. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading angle component in skewY: %s\n", attribute_content));
  1207. return 0;
  1208. }
  1209. i += read_chars;
  1210. gf_mx2d_init(tmp);
  1211. gf_mx2d_add_skew_y(&tmp, angle);
  1212. gf_mx2d_add_matrix(&tmp, mat);
  1213. gf_mx2d_copy(*mat, tmp);
  1214. while(str[i] == ' ') i++;
  1215. if (str[i] == ')') i++;
  1216. else {
  1217. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
  1218. return 0;
  1219. }
  1220. } else {
  1221. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
  1222. return 0;
  1223. }
  1224. } else if (strstr(str+i, "matrix")==str+i) {
  1225. i+=6;
  1226. while(str[i] == ' ') i++;
  1227. if (str[i] == '(') {
  1228. i++;
  1229. read_chars = svg_parse_number(&(str[i]), &(tmp.m[0]), 0);
  1230. if (!read_chars) {
  1231. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient a in matrix: %s\n", attribute_content));
  1232. return 0;
  1233. }
  1234. i += read_chars;
  1235. read_chars = svg_parse_number(&(str[i]), &(tmp.m[3]), 0);
  1236. if (!read_chars) {
  1237. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient b in matrix: %s\n", attribute_content));
  1238. return 0;
  1239. }
  1240. i += read_chars;
  1241. read_chars = svg_parse_number(&(str[i]), &(tmp.m[1]), 0);
  1242. if (!read_chars) {
  1243. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient c in matrix: %s\n", attribute_content));
  1244. return 0;
  1245. }
  1246. i += read_chars;
  1247. read_chars = svg_parse_number(&(str[i]), &(tmp.m[4]), 0);
  1248. if (!read_chars) {
  1249. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient d in matrix: %s\n", attribute_content));
  1250. return 0;
  1251. }
  1252. i += read_chars;
  1253. read_chars = svg_parse_number(&(str[i]), &(tmp.m[2]), 0);
  1254. if (!read_chars) {
  1255. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient e in matrix: %s\n", attribute_content));
  1256. return 0;
  1257. }
  1258. i += read_chars;
  1259. read_chars = svg_parse_number(&(str[i]), &(tmp.m[5]), 0);
  1260. if (!read_chars) {
  1261. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient f in matrix: %s\n", attribute_content));
  1262. return 0;
  1263. }
  1264. i += read_chars;
  1265. gf_mx2d_add_matrix(&tmp, mat);
  1266. gf_mx2d_copy(*mat, tmp);
  1267. while(str[i] == ' ') i++;
  1268. if (str[i] == ')') i++;
  1269. else {
  1270. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
  1271. return 0;
  1272. }
  1273. } else {
  1274. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content));
  1275. return 0;
  1276. }
  1277. } else {
  1278. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Unrecognized transofrm type in attribute %s\n", attribute_content));
  1279. return 0;
  1280. }
  1281. /*for svgView parsing*/
  1282. if (str[i] == ')') i++;
  1283. }
  1284. return 1;
  1285. }
  1286. /* Parses an SVG transform attribute and collapses all in the given matrix */
  1287. static Bool svg_parse_transform(SVG_Transform *t, char *attribute_content)
  1288. {
  1289. char *str;
  1290. u32 i;
  1291. u32 read_chars;
  1292. str = attribute_content;
  1293. i = 0;
  1294. if ((str = strstr(attribute_content, "ref"))) {
  1295. t->is_ref = 1;
  1296. gf_mx2d_init(t->mat);
  1297. str+=2;
  1298. while (str[i] == ' ') i++;
  1299. if (str[i] == '(') {
  1300. i++;
  1301. while (str[i] == ' ') i++;
  1302. if (str[i] == 's' && str[i+1] == 'v' && str[i+2] == 'g') {
  1303. i+=3;
  1304. while (str[i] == ' ') i++;
  1305. if (str[i] == ',') {
  1306. i++;
  1307. } else if (str[i] == ')') {
  1308. i++;
  1309. return GF_OK;
  1310. }
  1311. read_chars = svg_parse_number(&(str[i]), &(t->mat.m[2]), 0);
  1312. if (!read_chars) {
  1313. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient tx in ref transform: %s\n", attribute_content));
  1314. return GF_BAD_PARAM;
  1315. }
  1316. i += read_chars;
  1317. read_chars = svg_parse_number(&(str[i]), &(t->mat.m[5]), 0);
  1318. if (!read_chars) {
  1319. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient ty in ref transform: %s\n", attribute_content));
  1320. return GF_BAD_PARAM;
  1321. }
  1322. i += read_chars;
  1323. } else {
  1324. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Unsupported syntax for ref transform attribute"));
  1325. }
  1326. while (str[i] == ' ') i++;
  1327. if (str[i] == ')') i++;
  1328. else {
  1329. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content));
  1330. }
  1331. return GF_OK;
  1332. } else {
  1333. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in ref transform attribute: %s\n", attribute_content));
  1334. return GF_BAD_PARAM;
  1335. }
  1336. } else {
  1337. read_chars = gf_svg_parse_transformlist(&t->mat, attribute_content);
  1338. if (!read_chars) {
  1339. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error parsing transform list: %s\n", attribute_content));
  1340. return GF_BAD_PARAM;
  1341. }
  1342. }
  1343. return GF_OK;
  1344. }
  1345. #undef REMOVE_ALLOC
  1346. #if USE_GF_PATH
  1347. //#define PARSE_PATH_ONLY
  1348. static void svg_parse_path(SVG_PathData *path, char *attribute_content)
  1349. {
  1350. char *d = attribute_content;
  1351. /* used to detect end of BNF production:
  1352. "The processing of the BNF must consume as much of a given BNF production as possible,
  1353. stopping at the point when a character is encountered which no longer satisfies the production." */
  1354. u32 read_chars = 0;
  1355. /* Point used to start a new subpath when the previous subpath is closed */
  1356. SVG_Point prev_m_pt;
  1357. /* Point used to convert relative 'lower-case commands' into absolute */
  1358. SVG_Point rel_ref_pt;
  1359. /* Points used to convert S, T commands into C, Q */
  1360. SVG_Point orig, ct_orig, ct_end, end;
  1361. /* Used by elliptical arcs */
  1362. Fixed x_axis_rotation, large_arc_flag, sweep_flag;
  1363. char c, prev_c;
  1364. u32 i;
  1365. if (*d == 0) return;
  1366. i = 0;
  1367. prev_c = 'M';
  1368. orig.x = orig.y = ct_orig.x = ct_orig.y = prev_m_pt.x = prev_m_pt.y = rel_ref_pt.x = rel_ref_pt.y = end.x = end.y = 0;
  1369. while(1) {
  1370. while ( (d[i]==' ') || (d[i] =='\t') || (d[i] =='\r') || (d[i] =='\n') ) i++;
  1371. c = d[i];
  1372. if (! c) break;
  1373. next_command:
  1374. switch (c) {
  1375. case 'm':
  1376. case 'M':
  1377. i++;
  1378. read_chars = svg_parse_number(&(d[i]), &(orig.x), 0);
  1379. if (!read_chars) return;
  1380. i += read_chars;
  1381. read_chars = svg_parse_number(&(d[i]), &(orig.y), 0);
  1382. if (!read_chars) return;
  1383. i += read_chars;
  1384. if (c == 'm') {
  1385. orig.x += rel_ref_pt.x;
  1386. orig.y += rel_ref_pt.y;
  1387. }
  1388. #ifndef PARSE_PATH_ONLY
  1389. gf_path_add_move_to(path, orig.x, orig.y);
  1390. #endif
  1391. rel_ref_pt = orig;
  1392. prev_m_pt = orig;
  1393. /*provision for nextCurveTo when no curve is specified:
  1394. "If there is no previous command or if the previous command was not an C, c, S or s,
  1395. assume the first control point is coincident with the current point.
  1396. */
  1397. ct_orig = orig;
  1398. prev_c = c;
  1399. break;
  1400. case 'L':
  1401. case 'l':
  1402. i++;
  1403. read_chars = svg_parse_number(&(d[i]), &(orig.x), 0);
  1404. if (!read_chars) return;
  1405. i += read_chars;
  1406. read_chars = svg_parse_number(&(d[i]), &(orig.y), 0);
  1407. if (!read_chars) return;
  1408. i += read_chars;
  1409. if (c == 'l') {
  1410. orig.x += rel_ref_pt.x;
  1411. orig.y += rel_ref_pt.y;
  1412. }
  1413. #ifndef PARSE_PATH_ONLY
  1414. gf_path_add_line_to(path, orig.x, orig.y);
  1415. #endif
  1416. rel_ref_pt = orig;
  1417. orig = end;
  1418. /*cf above*/
  1419. ct_orig = orig;
  1420. prev_c = c;
  1421. break;
  1422. case 'H':
  1423. case 'h':
  1424. i++;
  1425. read_chars = svg_parse_number(&(d[i]), &(orig.x), 0);
  1426. if (!read_chars) return;
  1427. i += read_chars;
  1428. if (c == 'h') {
  1429. orig.x += rel_ref_pt.x;
  1430. }
  1431. orig.y = rel_ref_pt.y;
  1432. #ifndef PARSE_PATH_ONLY
  1433. gf_path_add_line_to(path, orig.x, orig.y);
  1434. #endif
  1435. rel_ref_pt.x = orig.x;
  1436. orig = end;
  1437. /*cf above*/
  1438. ct_orig = orig;
  1439. prev_c = c;
  1440. break;
  1441. case 'V':
  1442. case 'v':
  1443. i++;
  1444. read_chars = svg_parse_number(&(d[i]), &(orig.y), 0);
  1445. if (!read_chars) return;
  1446. i += read_chars;
  1447. if (c == 'v') {
  1448. orig.y += rel_ref_pt.y;
  1449. }
  1450. orig.x = rel_ref_pt.x;
  1451. #ifndef PARSE_PATH_ONLY
  1452. gf_path_add_line_to(path, orig.x, orig.y);
  1453. #endif
  1454. rel_ref_pt.y = orig.y;
  1455. orig = end;
  1456. /*cf above*/
  1457. ct_orig = orig;
  1458. prev_c = c;
  1459. break;
  1460. case 'C':
  1461. case 'c':
  1462. i++;
  1463. read_chars = svg_parse_number(&(d[i]), &(ct_orig.x), 0);
  1464. if (!read_chars) return;
  1465. i += read_chars;
  1466. read_chars = svg_parse_number(&(d[i]), &(ct_orig.y), 0);
  1467. if (!read_chars) return;
  1468. i += read_chars;
  1469. if (c == 'c') {
  1470. ct_orig.x += rel_ref_pt.x;
  1471. ct_orig.y += rel_ref_pt.y;
  1472. }
  1473. read_chars = svg_parse_number(&(d[i]), &(ct_end.x), 0);
  1474. if (!read_chars) return;
  1475. i += read_chars;
  1476. read_chars = svg_parse_number(&(d[i]), &(ct_end.y), 0);
  1477. if (!read_chars) return;
  1478. i += read_chars;
  1479. if (c == 'c') {
  1480. ct_end.x += rel_ref_pt.x;
  1481. ct_end.y += rel_ref_pt.y;
  1482. }
  1483. read_chars = svg_parse_number(&(d[i]), &(end.x), 0);
  1484. if (!read_chars) return;
  1485. i += read_chars;
  1486. read_chars = svg_parse_number(&(d[i]), &(end.y), 0);
  1487. if (!read_chars) return;
  1488. i += read_chars;
  1489. if (c == 'c') {
  1490. end.x += rel_ref_pt.x;
  1491. end.y += rel_ref_pt.y;
  1492. }
  1493. #ifndef PARSE_PATH_ONLY
  1494. gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
  1495. #endif
  1496. rel_ref_pt = end;
  1497. ct_orig = ct_end;
  1498. orig = end;
  1499. prev_c = c;
  1500. break;
  1501. case 'S':
  1502. case 's':
  1503. i++;
  1504. ct_orig.x = 2*orig.x - ct_orig.x;
  1505. ct_orig.y = 2*orig.y - ct_orig.y;
  1506. read_chars = svg_parse_number(&(d[i]), &(ct_end.x), 0);
  1507. if (!read_chars) return;
  1508. i += read_chars;
  1509. read_chars = svg_parse_number(&(d[i]), &(ct_end.y), 0);
  1510. if (!read_chars) return;
  1511. i += read_chars;
  1512. if (c == 's') {
  1513. ct_end.x += rel_ref_pt.x;
  1514. ct_end.y += rel_ref_pt.y;
  1515. }
  1516. read_chars = svg_parse_number(&(d[i]), &(end.x), 0);
  1517. if (!read_chars) return;
  1518. i += read_chars;
  1519. read_chars = svg_parse_number(&(d[i]), &(end.y), 0);
  1520. if (!read_chars) return;
  1521. i += read_chars;
  1522. if (c == 's') {
  1523. end.x += rel_ref_pt.x;
  1524. end.y += rel_ref_pt.y;
  1525. }
  1526. #ifndef PARSE_PATH_ONLY
  1527. gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
  1528. #endif
  1529. rel_ref_pt = end;
  1530. ct_orig = ct_end;
  1531. orig = end;
  1532. prev_c = c;
  1533. break;
  1534. case 'Q':
  1535. case 'q':
  1536. i++;
  1537. read_chars = svg_parse_number(&(d[i]), &(ct_orig.x), 0);
  1538. if (!read_chars) return;
  1539. i += read_chars;
  1540. read_chars = svg_parse_number(&(d[i]), &(ct_orig.y), 0);
  1541. if (!read_chars) return;
  1542. i += read_chars;
  1543. if (c == 'q') {
  1544. ct_orig.x += rel_ref_pt.x;
  1545. ct_orig.y += rel_ref_pt.y;
  1546. }
  1547. read_chars = svg_parse_number(&(d[i]), &(end.x), 0);
  1548. if (!read_chars) return;
  1549. i += read_chars;
  1550. read_chars = svg_parse_number(&(d[i]), &(end.y), 0);
  1551. if (!read_chars) return;
  1552. i += read_chars;
  1553. if (c == 'q') {
  1554. end.x += rel_ref_pt.x;
  1555. end.y += rel_ref_pt.y;
  1556. }
  1557. #ifndef PARSE_PATH_ONLY
  1558. gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y);
  1559. #endif
  1560. rel_ref_pt = end;
  1561. orig = end;
  1562. prev_c = c;
  1563. break;
  1564. case 'T':
  1565. case 't':
  1566. i++;
  1567. ct_orig.x = 2*orig.x - ct_orig.x;
  1568. ct_orig.y = 2*orig.y - ct_orig.y;
  1569. read_chars = svg_parse_number(&(d[i]), &(end.x), 0);
  1570. if (!read_chars) return;
  1571. i += read_chars;
  1572. read_chars = svg_parse_number(&(d[i]), &(end.y), 0);
  1573. if (!read_chars) return;
  1574. i += read_chars;
  1575. if (c == 't') {
  1576. end.x += rel_ref_pt.x;
  1577. end.y += rel_ref_pt.y;
  1578. }
  1579. #ifndef PARSE_PATH_ONLY
  1580. gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y);
  1581. #endif
  1582. rel_ref_pt = end;
  1583. orig = end;
  1584. prev_c = c;
  1585. break;
  1586. case 'A':
  1587. case 'a':
  1588. i++;
  1589. read_chars = svg_parse_number(&(d[i]), &(orig.x), 0);
  1590. if (!read_chars) return;
  1591. i += read_chars;
  1592. read_chars = svg_parse_number(&(d[i]), &(orig.y), 0);
  1593. if (!read_chars) return;
  1594. i += read_chars;
  1595. read_chars = svg_parse_number(&(d[i]), &(x_axis_rotation), 0);
  1596. if (!read_chars) return;
  1597. i += read_chars;
  1598. read_chars = svg_parse_number(&(d[i]), &(large_arc_flag), 0);
  1599. if (!read_chars) return;
  1600. i += read_chars;
  1601. read_chars = svg_parse_number(&(d[i]), &(sweep_flag), 0);
  1602. if (!read_chars) return;
  1603. i += read_chars;
  1604. read_chars = svg_parse_number(&(d[i]), &(end.x), 0);
  1605. if (!read_chars) return;
  1606. i += read_chars;
  1607. read_chars = svg_parse_number(&(d[i]), &(end.y), 0);
  1608. if (!read_chars) return;
  1609. i += read_chars;
  1610. if (c == 'a') {
  1611. end.x += rel_ref_pt.x;
  1612. end.y += rel_ref_pt.y;
  1613. }
  1614. #ifndef PARSE_PATH_ONLY
  1615. gf_path_add_svg_arc_to(path, end.x, end.y, orig.x, orig.y, x_axis_rotation , (large_arc_flag == FIX_ONE ? 1 : 0), (sweep_flag == FIX_ONE ? 1 : 0));
  1616. #endif
  1617. rel_ref_pt = end;
  1618. ct_orig = end;
  1619. prev_c = c;
  1620. break;
  1621. case 'Z':
  1622. case 'z':
  1623. i++;
  1624. #ifndef PARSE_PATH_ONLY
  1625. gf_path_close(path);
  1626. #endif
  1627. prev_c = c;
  1628. rel_ref_pt = prev_m_pt;
  1629. break;
  1630. default:
  1631. i--;
  1632. switch (prev_c) {
  1633. case 'M':
  1634. c = 'L';
  1635. break;
  1636. case 'm':
  1637. c = 'l';
  1638. break;
  1639. default:
  1640. c = prev_c;
  1641. }
  1642. goto next_command;
  1643. }
  1644. }
  1645. }
  1646. #else
  1647. /* TODO: Change the function to handle elliptical arcs, requires changing data structure */
  1648. static void svg_parse_path(SVG_PathData *d_attribute, char *attribute_content)
  1649. {
  1650. GF_List *d_commands = d_attribute->commands;
  1651. GF_List *d_points = d_attribute->points;
  1652. char *d = attribute_content;
  1653. if (strlen(d)) {
  1654. SVG_Point *pt, cur_pt, prev_m_pt;
  1655. u8 *command;
  1656. u32 i, k;
  1657. char c, prev_c = 'M';
  1658. #ifdef REMOVE_ALLOC
  1659. GF_SAFEALLOC(pt, SVG_Point)
  1660. #endif
  1661. i = 0;
  1662. cur_pt.x = cur_pt.y = 0;
  1663. prev_m_pt.x = prev_m_pt.y = 0;
  1664. while(1) {
  1665. while ( (d[i]==' ') || (d[i] =='\t') ) i++;
  1666. c = d[i];
  1667. if (! c) break;
  1668. next_command:
  1669. switch (c) {
  1670. case 'm':
  1671. case 'M':
  1672. i++;
  1673. #ifndef REMOVE_ALLOC
  1674. GF_SAFEALLOC(command, u8)
  1675. gf_list_add(d_commands, command);
  1676. *command = SVG_PATHCOMMAND_M;
  1677. GF_SAFEALLOC(pt, SVG_Point)
  1678. gf_list_add(d_points, pt);
  1679. #endif
  1680. i += svg_parse_number(&(d[i]), &(pt->x), 0);
  1681. i += svg_parse_number(&(d[i]), &(pt->y), 0);
  1682. if (c == 'm') {
  1683. pt->x += cur_pt.x;
  1684. pt->y += cur_pt.y;
  1685. }
  1686. cur_pt.x = pt->x;
  1687. cur_pt.y = pt->y;
  1688. prev_m_pt = cur_pt;
  1689. prev_c = c;
  1690. break;
  1691. case 'L':
  1692. case 'l':
  1693. i++;
  1694. #ifndef REMOVE_ALLOC
  1695. GF_SAFEALLOC(command, u8)
  1696. gf_list_add(d_commands, command);
  1697. *command = SVG_PATHCOMMAND_L;
  1698. GF_SAFEALLOC(pt, SVG_Point)
  1699. gf_list_add(d_points, pt);
  1700. #endif
  1701. i += svg_parse_number(&(d[i]), &(pt->x), 0);
  1702. i += svg_parse_number(&(d[i]), &(pt->y), 0);
  1703. if (c == 'l') {
  1704. pt->x += cur_pt.x;
  1705. pt->y += cur_pt.y;
  1706. }
  1707. cur_pt.x = pt->x;
  1708. cur_pt.y = pt->y;
  1709. prev_c = c;
  1710. break;
  1711. case 'H':
  1712. case 'h':
  1713. i++;
  1714. #ifndef REMOVE_ALLOC
  1715. GF_SAFEALLOC(command, u8)
  1716. gf_list_add(d_commands, command);
  1717. *command = SVG_PATHCOMMAND_L;
  1718. GF_SAFEALLOC(pt, SVG_Point)
  1719. gf_list_add(d_points, pt);
  1720. #endif
  1721. i += svg_parse_number(&(d[i]), &(pt->x), 0);
  1722. if (c == 'h') {
  1723. pt->x += cur_pt.x;
  1724. }
  1725. pt->y = cur_pt.y;
  1726. cur_pt.x = pt->x;
  1727. prev_c = c;
  1728. break;
  1729. case 'V':
  1730. case 'v':
  1731. i++;
  1732. #ifndef REMOVE_ALLOC
  1733. GF_SAFEALLOC(command, u8)
  1734. gf_list_add(d_commands, command);
  1735. *command = SVG_PATHCOMMAND_L;
  1736. GF_SAFEALLOC(pt, SVG_Point)
  1737. gf_list_add(d_points, pt);
  1738. #endif
  1739. i += svg_parse_number(&(d[i]), &(pt->y), 0);
  1740. if (c == 'v') {
  1741. pt->y += cur_pt.y;
  1742. }
  1743. pt->x = cur_pt.x;
  1744. cur_pt.y = pt->y;
  1745. prev_c = c;
  1746. break;
  1747. case 'C':
  1748. case 'c':
  1749. i++;
  1750. #ifndef REMOVE_ALLOC
  1751. GF_SAFEALLOC(command, u8)
  1752. gf_list_add(d_commands, command);
  1753. *command = SVG_PATHCOMMAND_C;
  1754. #endif
  1755. for (k=0; k<3; k++) {
  1756. #ifndef REMOVE_ALLOC
  1757. GF_SAFEALLOC(pt, SVG_Point)
  1758. gf_list_add(d_points, pt);
  1759. #endif
  1760. i += svg_parse_number(&(d[i]), &(pt->x), 0);
  1761. i += svg_parse_number(&(d[i]), &(pt->y), 0);
  1762. if (c == 'c') {
  1763. pt->x += cur_pt.x;
  1764. pt->y += cur_pt.y;
  1765. }
  1766. }
  1767. cur_pt.x = pt->x;
  1768. cur_pt.y = pt->y;
  1769. prev_c = c;
  1770. break;
  1771. case 'S':
  1772. case 's':
  1773. i++;
  1774. #ifndef REMOVE_ALLOC
  1775. GF_SAFEALLOC(command, u8)
  1776. gf_list_add(d_commands, command);
  1777. *command = SVG_PATHCOMMAND_S;
  1778. #endif
  1779. for (k=0; k<2; k++) {
  1780. #ifndef REMOVE_ALLOC
  1781. GF_SAFEALLOC(pt, SVG_Point)
  1782. gf_list_add(d_points, pt);
  1783. #endif
  1784. i += svg_parse_number(&(d[i]), &(pt->x), 0);
  1785. i += svg_parse_number(&(d[i]), &(pt->y), 0);
  1786. if (c == 's') {
  1787. pt->x += cur_pt.x;
  1788. pt->y += cur_pt.y;
  1789. }
  1790. }
  1791. cur_pt.x = pt->x;
  1792. cur_pt.y = pt->y;
  1793. prev_c = c;
  1794. break;
  1795. case 'Q':
  1796. case 'q':
  1797. i++;
  1798. #ifndef REMOVE_ALLOC
  1799. GF_SAFEALLOC(command, u8)
  1800. gf_list_add(d_commands, command);
  1801. *command = SVG_PATHCOMMAND_Q;
  1802. #endif
  1803. for (k=0; k<2; k++) {
  1804. #ifndef REMOVE_ALLOC
  1805. GF_SAFEALLOC(pt, SVG_Point)
  1806. gf_list_add(d_points, pt);
  1807. #endif
  1808. i += svg_parse_number(&(d[i]), &(pt->x), 0);
  1809. i += svg_parse_number(&(d[i]), &(pt->y), 0);
  1810. if (c == 'q') {
  1811. pt->x += cur_pt.x;
  1812. pt->y += cur_pt.y;
  1813. }
  1814. }
  1815. cur_pt.x = pt->x;
  1816. cur_pt.y = pt->y;
  1817. prev_c = c;
  1818. break;
  1819. case 'T':
  1820. case 't':
  1821. i++;
  1822. #ifndef REMOVE_ALLOC
  1823. GF_SAFEALLOC(command, u8)
  1824. gf_list_add(d_commands, command);
  1825. *command = SVG_PATHCOMMAND_T;
  1826. GF_SAFEALLOC(pt, SVG_Point)
  1827. gf_list_add(d_points, pt);
  1828. #endif
  1829. i += svg_parse_number(&(d[i]), &(pt->x), 0);
  1830. i += svg_parse_number(&(d[i]), &(pt->y), 0);
  1831. if (c == 't') {
  1832. pt->x += cur_pt.x;
  1833. pt->y += cur_pt.y;
  1834. }
  1835. cur_pt.x = pt->x;
  1836. cur_pt.y = pt->y;
  1837. prev_c = c;
  1838. break;
  1839. case 'A':
  1840. case 'a':
  1841. {
  1842. Fixed tmp;
  1843. i++;
  1844. #ifndef REMOVE_ALLOC
  1845. GF_SAFEALLOC(command, u8)
  1846. gf_list_add(d_commands, command);
  1847. *command = SVG_PATHCOMMAND_A;
  1848. GF_SAFEALLOC(pt, SVG_Point)
  1849. gf_list_add(d_points, pt);
  1850. #endif
  1851. i += svg_parse_number(&(d[i]), &(pt->x), 0);
  1852. i += svg_parse_number(&(d[i]), &(pt->y), 0);
  1853. i += svg_parse_number(&(d[i]), &(tmp), 0);
  1854. i += svg_parse_number(&(d[i]), &(tmp), 0);
  1855. i += svg_parse_number(&(d[i]), &(tmp), 0);
  1856. #ifndef REMOVE_ALLOC
  1857. GF_SAFEALLOC(pt, SVG_Point)
  1858. gf_list_add(d_points, pt);
  1859. #endif
  1860. i += svg_parse_number(&(d[i]), &(pt->x), 0);
  1861. i += svg_parse_number(&(d[i]), &(pt->y), 0);
  1862. if (c == 'a') {
  1863. pt->x += cur_pt.x;
  1864. pt->y += cur_pt.y;
  1865. }
  1866. cur_pt.x = pt->x;
  1867. cur_pt.y = pt->y;
  1868. }
  1869. prev_c = c;
  1870. break;
  1871. case 'Z':
  1872. case 'z':
  1873. i++;
  1874. #ifndef REMOVE_ALLOC
  1875. GF_SAFEALLOC(command, u8)
  1876. gf_list_add(d_commands, command);
  1877. *command = SVG_PATHCOMMAND_Z;
  1878. #endif
  1879. prev_c = c;
  1880. cur_pt = prev_m_pt;
  1881. break;
  1882. default:
  1883. i--;
  1884. switch (prev_c) {
  1885. case 'M':
  1886. c = 'L';
  1887. break;
  1888. case 'm':
  1889. c = 'l';
  1890. break;
  1891. default:
  1892. c = prev_c;
  1893. }
  1894. goto next_command;
  1895. }
  1896. }
  1897. }
  1898. }
  1899. #endif
  1900. static void svg_parse_iri(GF_Node *elt, XMLRI *iri, char *attribute_content)
  1901. {
  1902. if (iri->string) {
  1903. gf_free(iri->string);
  1904. iri->string = NULL;
  1905. }
  1906. /* TODO: Handle xpointer(id()) syntax */
  1907. if (attribute_content[0] == '#') {
  1908. iri->string = gf_strdup(attribute_content);
  1909. iri->target = gf_sg_find_node_by_name(elt->sgprivate->scenegraph, attribute_content + 1);
  1910. if (!iri->target) {
  1911. iri->type = XMLRI_STRING;
  1912. } else {
  1913. iri->type = XMLRI_ELEMENTID;
  1914. gf_node_register_iri(elt->sgprivate->scenegraph, iri);
  1915. }
  1916. } else {
  1917. iri->type = XMLRI_STRING;
  1918. iri->string = gf_strdup(attribute_content);
  1919. }
  1920. }
  1921. static void svg_parse_idref(GF_Node *elt, XML_IDREF *iri, char *attribute_content)
  1922. {
  1923. iri->type = XMLRI_ELEMENTID;
  1924. iri->target = gf_sg_find_node_by_name(elt->sgprivate->scenegraph, attribute_content);
  1925. if (!iri->target) {
  1926. iri->string = gf_strdup(attribute_content);
  1927. } else {
  1928. gf_node_register_iri(elt->sgprivate->scenegraph, iri);
  1929. }
  1930. }
  1931. /* Parses a paint attribute: none, inherit or color */
  1932. static void svg_parse_paint(GF_Node *n, SVG_Paint *paint, char *attribute_content)
  1933. {
  1934. if (!strcmp(attribute_content, "none")) {
  1935. paint->type = SVG_PAINT_NONE;
  1936. } else if (!strcmp(attribute_content, "inherit")) {
  1937. paint->type = SVG_PAINT_INHERIT;
  1938. } else if (!strncmp(attribute_content, "url(", 4) ) {
  1939. char *ext = strrchr(attribute_content, ')');
  1940. paint->type = SVG_PAINT_URI;
  1941. if (ext) ext[0] = 0;
  1942. svg_parse_iri(n, &paint->iri, attribute_content+4);
  1943. if (ext) ext[0] = ')';
  1944. } else {
  1945. paint->type = SVG_PAINT_COLOR;
  1946. svg_parse_color(&paint->color, attribute_content);
  1947. }
  1948. }
  1949. /* Parses a length which is a number with a unit */
  1950. static u32 svg_parse_length(SVG_Number *number, char *value_string, Bool clamp0to1)
  1951. {
  1952. char c = '\0';
  1953. char *unit = NULL;
  1954. u32 len = 0;
  1955. u32 unit_pos = 0;
  1956. u32 unit_len = 0;
  1957. u32 read_chars;
  1958. if (!strcmp(value_string, "inherit")) {
  1959. number->type = SVG_NUMBER_INHERIT;
  1960. return 7;
  1961. } else if (!strcmp(value_string, "auto")) {
  1962. number->type = SVG_NUMBER_AUTO;
  1963. return 4;
  1964. } else if (!strcmp(value_string, "auto-reverse")) {
  1965. number->type = SVG_NUMBER_AUTO_REVERSE;
  1966. return 12;
  1967. } else if ((unit = strstr(value_string, "%")) ) {
  1968. number->type = SVG_NUMBER_PERCENTAGE;
  1969. unit_len = 1;
  1970. } else if ((unit = strstr(value_string, "em"))) {
  1971. number->type = SVG_NUMBER_EMS;
  1972. } else if ((unit = strstr(value_string, "ex"))) {
  1973. number->type = SVG_NUMBER_EXS;
  1974. } else if ((unit = strstr(value_string, "px"))) {
  1975. number->type = SVG_NUMBER_PX;
  1976. } else if ((unit = strstr(value_string, "cm"))) {
  1977. number->type = SVG_NUMBER_CM;
  1978. } else if ((unit = strstr(value_string, "mm"))) {
  1979. number->type = SVG_NUMBER_MM;
  1980. } else if ((unit = strstr(value_string, "in"))) {
  1981. number->type = SVG_NUMBER_IN;
  1982. } else if ((unit = strstr(value_string, "pt"))) {
  1983. number->type = SVG_NUMBER_PT;
  1984. } else if ((unit = strstr(value_string, "pc"))) {
  1985. number->type = SVG_NUMBER_PC;
  1986. } else {
  1987. number->type = SVG_NUMBER_VALUE;
  1988. }
  1989. if (unit) {
  1990. if (!unit_len) unit_len = 2;
  1991. unit_pos = (u32) (unit - value_string);
  1992. /* setting the first unit character to 0 for the svg_parse_number method to finish */
  1993. c = value_string[unit_pos];
  1994. value_string[unit_pos] = 0;
  1995. }
  1996. read_chars = svg_parse_number(value_string, &(number->value), 0);
  1997. if (unit) {
  1998. value_string[unit_pos] = c;
  1999. }
  2000. if (!read_chars) {
  2001. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing: %s\n", value_string));
  2002. len = 0;
  2003. } else {
  2004. len = unit_len + read_chars;
  2005. }
  2006. if (clamp0to1) number->value = MAX(0, MIN(1, number->value));
  2007. return len;
  2008. }
  2009. static void svg_parse_visibility(SVG_Visibility *value, char *value_string)
  2010. {
  2011. if (!strcmp(value_string, "inherit")) {
  2012. *value = SVG_VISIBILITY_INHERIT;
  2013. } else if (!strcmp(value_string, "visible")) {
  2014. *value = SVG_VISIBILITY_VISIBLE;
  2015. } else if (!strcmp(value_string, "hidden")) {
  2016. *value = SVG_VISIBILITY_HIDDEN;
  2017. } else if (!strcmp(value_string, "collapse")) {
  2018. *value = SVG_VISIBILITY_COLLAPSE;
  2019. }
  2020. }
  2021. static void svg_parse_display(SVG_Display *value, char *value_string)
  2022. {
  2023. if (!strcmp(value_string, "inherit")) {
  2024. *value = SVG_DISPLAY_INHERIT;
  2025. } else if (!strcmp(value_string, "none")) {
  2026. *value = SVG_DISPLAY_NONE;
  2027. } else if (!strcmp(value_string, "inline")) {
  2028. *value = SVG_DISPLAY_INLINE;
  2029. } else if (!strcmp(value_string, "block")) {
  2030. *value = SVG_DISPLAY_BLOCK;
  2031. } else if (!strcmp(value_string, "list-item")) {
  2032. *value = SVG_DISPLAY_LIST_ITEM;
  2033. } else if (!strcmp(value_string, "run-in")) {
  2034. *value = SVG_DISPLAY_RUN_IN;
  2035. } else if (!strcmp(value_string, "compact")) {
  2036. *value = SVG_DISPLAY_COMPACT;
  2037. } else if (!strcmp(value_string, "marker")) {
  2038. *value = SVG_DISPLAY_MARKER;
  2039. } else if (!strcmp(value_string, "table")) {
  2040. *value = SVG_DISPLAY_TABLE;
  2041. } else if (!strcmp(value_string, "inline-table")) {
  2042. *value = SVG_DISPLAY_INLINE_TABLE;
  2043. } else if (!strcmp(value_string, "table-row-group")) {
  2044. *value = SVG_DISPLAY_TABLE_ROW_GROUP;
  2045. } else if (!strcmp(value_string, "table-header-group")) {
  2046. *value = SVG_DISPLAY_TABLE_HEADER_GROUP;
  2047. } else if (!strcmp(value_string, "table-footer-group")) {
  2048. *value = SVG_DISPLAY_TABLE_FOOTER_GROUP;
  2049. } else if (!strcmp(value_string, "table-row")) {
  2050. *value = SVG_DISPLAY_TABLE_ROW;
  2051. } else if (!strcmp(value_string, "table-column-group")) {
  2052. *value = SVG_DISPLAY_TABLE_COLUMN_GROUP;
  2053. } else if (!strcmp(value_string, "table-column")) {
  2054. *value = SVG_DISPLAY_TABLE_COLUMN;
  2055. } else if (!strcmp(value_string, "table-cell")) {
  2056. *value = SVG_DISPLAY_TABLE_CELL;
  2057. } else if (!strcmp(value_string, "table-caption")) {
  2058. *value = SVG_DISPLAY_TABLE_CAPTION;
  2059. }
  2060. }
  2061. static void svg_parse_displayalign(SVG_DisplayAlign *value, char *value_string)
  2062. {
  2063. if (!strcmp(value_string, "inherit")) {
  2064. *value = SVG_DISPLAYALIGN_INHERIT;
  2065. } else if (!strcmp(value_string, "auto")) {
  2066. *value = SVG_DISPLAYALIGN_AUTO;
  2067. } else if (!strcmp(value_string, "before")) {
  2068. *value = SVG_DISPLAYALIGN_BEFORE;
  2069. } else if (!strcmp(value_string, "center")) {
  2070. *value = SVG_DISPLAYALIGN_CENTER;
  2071. } else if (!strcmp(value_string, "after")) {
  2072. *value = SVG_DISPLAYALIGN_AFTER;
  2073. }
  2074. }
  2075. static void svg_parse_textalign(SVG_TextAlign *value, char *value_string)
  2076. {
  2077. if (!strcmp(value_string, "inherit")) {
  2078. *value = SVG_TEXTALIGN_INHERIT;
  2079. } else if (!strcmp(value_string, "start")) {
  2080. *value = SVG_TEXTALIGN_START;
  2081. } else if (!strcmp(value_string, "center")) {
  2082. *value = SVG_TEXTALIGN_CENTER;
  2083. } else if (!strcmp(value_string, "end")) {
  2084. *value = SVG_TEXTALIGN_END;
  2085. }
  2086. }
  2087. static void svg_parse_pointerevents(SVG_PointerEvents *value, char *value_string)
  2088. {
  2089. if (!strcmp(value_string, "inherit")) {
  2090. *value = SVG_POINTEREVENTS_INHERIT;
  2091. } else if (!strcmp(value_string, "visiblePainted")) {
  2092. *value = SVG_POINTEREVENTS_VISIBLEPAINTED;
  2093. } else if (!strcmp(value_string, "visibleFill")) {
  2094. *value = SVG_POINTEREVENTS_VISIBLEFILL;
  2095. } else if (!strcmp(value_string, "visibleStroke")) {
  2096. *value = SVG_POINTEREVENTS_VISIBLESTROKE;
  2097. } else if (!strcmp(value_string, "visible")) {
  2098. *value = SVG_POINTEREVENTS_VISIBLE;
  2099. } else if (!strcmp(value_string, "painted")) {
  2100. *value = SVG_POINTEREVENTS_PAINTED;
  2101. } else if (!strcmp(value_string, "fill")) {
  2102. *value = SVG_POINTEREVENTS_FILL;
  2103. } else if (!strcmp(value_string, "stroke")) {
  2104. *value = SVG_POINTEREVENTS_STROKE;
  2105. } else if (!strcmp(value_string, "all")) {
  2106. *value = SVG_POINTEREVENTS_ALL;
  2107. } else if (!strcmp(value_string, "boundingBox")) {
  2108. *value = SVG_POINTEREVENTS_BOUNDINGBOX;
  2109. } else if (!strcmp(value_string, "none")) {
  2110. *value = SVG_POINTEREVENTS_NONE;
  2111. }
  2112. }
  2113. static void svg_parse_renderinghint(SVG_RenderingHint *value, char *value_string)
  2114. {
  2115. if (!strcmp(value_string, "inherit")) {
  2116. *value = SVG_RENDERINGHINT_INHERIT;
  2117. } else if (!strcmp(value_string, "auto")) {
  2118. *value = SVG_RENDERINGHINT_AUTO;
  2119. } else if (!strcmp(value_string, "optimizeQuality")) {
  2120. *value = SVG_RENDERINGHINT_OPTIMIZEQUALITY;
  2121. } else if (!strcmp(value_string, "optimizeSpeed")) {
  2122. *value = SVG_RENDERINGHINT_OPTIMIZESPEED;
  2123. } else if (!strcmp(value_string, "optimizeLegibility")) {
  2124. *value = SVG_RENDERINGHINT_OPTIMIZELEGIBILITY;
  2125. } else if (!strcmp(value_string, "crispEdges")) {
  2126. *value = SVG_RENDERINGHINT_CRISPEDGES;
  2127. } else if (!strcmp(value_string, "geometricPrecision")) {
  2128. *value = SVG_RENDERINGHINT_GEOMETRICPRECISION;
  2129. }
  2130. }
  2131. static void svg_parse_vectoreffect(SVG_VectorEffect *value, char *value_string)
  2132. {
  2133. if (!strcmp(value_string, "inherit")) {
  2134. *value = SVG_VECTOREFFECT_INHERIT;
  2135. } else if (!strcmp(value_string, "none")) {
  2136. *value = SVG_VECTOREFFECT_NONE;
  2137. } else if (!strcmp(value_string, "non-scaling-stroke")) {
  2138. *value = SVG_VECTOREFFECT_NONSCALINGSTROKE;
  2139. }
  2140. }
  2141. static void svg_parse_playbackorder(SVG_VectorEffect *value, char *value_string)
  2142. {
  2143. if (!strcmp(value_string, "forwardOnly")) {
  2144. *value = SVG_PLAYBACKORDER_FORWARDONLY;
  2145. } else if (!strcmp(value_string, "all")) {
  2146. *value = SVG_PLAYBACKORDER_ALL;
  2147. }
  2148. }
  2149. static void svg_parse_timelinebegin(SVG_TimelineBegin *value, char *value_string)
  2150. {
  2151. if (!strcmp(value_string, "onStart")) {
  2152. *value = SVG_TIMELINEBEGIN_ONSTART;
  2153. } else if (!strcmp(value_string, "onLoad")) {
  2154. *value = SVG_TIMELINEBEGIN_ONLOAD;
  2155. }
  2156. }
  2157. static void svg_parse_xmlspace(XML_Space *value, char *value_string)
  2158. {
  2159. if (!strcmp(value_string, "default")) {
  2160. *value = XML_SPACE_DEFAULT;
  2161. } else if (!strcmp(value_string, "preserve")) {
  2162. *value = XML_SPACE_PRESERVE;
  2163. }
  2164. }
  2165. static void svg_parse_xmlev_propagate(XMLEV_Propagate *value, char *value_string)
  2166. {
  2167. if (!strcmp(value_string, "continue")) {
  2168. *value = XMLEVENT_PROPAGATE_CONTINUE;
  2169. } else if (!strcmp(value_string, "stop")) {
  2170. *value = XMLEVENT_PROPAGATE_STOP;
  2171. }
  2172. }
  2173. static void svg_parse_xmlev_defaultAction(XMLEV_DefaultAction *value, char *value_string)
  2174. {
  2175. if (!strcmp(value_string, "cancel")) {
  2176. *value = XMLEVENT_DEFAULTACTION_CANCEL;
  2177. } else if (!strcmp(value_string, "perform")) {
  2178. *value = XMLEVENT_DEFAULTACTION_PERFORM;
  2179. }
  2180. }
  2181. static void svg_parse_xmlev_phase(XMLEV_Phase *value, char *value_string)
  2182. {
  2183. if (!strcmp(value_string, "default")) {
  2184. *value = XMLEVENT_PHASE_DEFAULT;
  2185. } else if (!strcmp(value_string, "capture")) {
  2186. *value = XMLEVENT_PHASE_CAPTURE;
  2187. }
  2188. }
  2189. static void svg_parse_overflow(SVG_Overflow *value, char *value_string)
  2190. {
  2191. if (!strcmp(value_string, "inherit")) {
  2192. *value = SVG_OVERFLOW_INHERIT;
  2193. } else if (!strcmp(value_string, "visible")) {
  2194. *value = SVG_OVERFLOW_VISIBLE;
  2195. } else if (!strcmp(value_string, "hidden")) {
  2196. *value = SVG_OVERFLOW_HIDDEN;
  2197. } else if (!strcmp(value_string, "scroll")) {
  2198. *value = SVG_OVERFLOW_SCROLL;
  2199. } else if (!strcmp(value_string, "auto")) {
  2200. *value = SVG_OVERFLOW_AUTO;
  2201. }
  2202. }
  2203. static void svg_parse_textanchor(SVG_TextAnchor *value, char *value_string)
  2204. {
  2205. if (!strcmp(value_string, "inherit")) {
  2206. *value = SVG_TEXTANCHOR_INHERIT;
  2207. } else if (!strcmp(value_string, "start")) {
  2208. *value = SVG_TEXTANCHOR_START;
  2209. } else if (!strcmp(value_string, "middle")) {
  2210. *value = SVG_TEXTANCHOR_MIDDLE;
  2211. } else if (!strcmp(value_string, "end")) {
  2212. *value = SVG_TEXTANCHOR_END;
  2213. }
  2214. }
  2215. static void svg_parse_clipfillrule(SVG_FillRule *value, char *value_string)
  2216. {
  2217. if (!strcmp(value_string, "inherit")) {
  2218. *value = SVG_FILLRULE_INHERIT;
  2219. } else if (!strcmp(value_string, "nonzero")) {
  2220. *value = SVG_FILLRULE_NONZERO;
  2221. } else if (!strcmp(value_string, "evenodd")) {
  2222. *value = SVG_FILLRULE_EVENODD;
  2223. }
  2224. }
  2225. static void svg_parse_strokelinejoin(SVG_StrokeLineJoin *value, char *value_string)
  2226. {
  2227. if (!strcmp(value_string, "inherit")) {
  2228. *value = SVG_STROKELINEJOIN_INHERIT;
  2229. } else if (!strcmp(value_string, "miter")) {
  2230. *value = SVG_STROKELINEJOIN_MITER;
  2231. } else if (!strcmp(value_string, "round")) {
  2232. *value = SVG_STROKELINEJOIN_ROUND;
  2233. } else if (!strcmp(value_string, "bevel")) {
  2234. *value = SVG_STROKELINEJOIN_BEVEL;
  2235. }
  2236. }
  2237. static void svg_parse_strokelinecap(SVG_StrokeLineCap *value, char *value_string)
  2238. {
  2239. if (!strcmp(value_string, "inherit")) {
  2240. *value = SVG_STROKELINECAP_INHERIT;
  2241. } else if (!strcmp(value_string, "butt")) {
  2242. *value = SVG_STROKELINECAP_BUTT;
  2243. } else if (!strcmp(value_string, "round")) {
  2244. *value = SVG_STROKELINECAP_ROUND;
  2245. } else if (!strcmp(value_string, "square")) {
  2246. *value = SVG_STROKELINECAP_SQUARE;
  2247. }
  2248. }
  2249. static void svg_parse_fontfamily(SVG_FontFamily *value, char *value_string)
  2250. {
  2251. if (!strcmp(value_string, "inherit")) {
  2252. value->type = SVG_FONTFAMILY_INHERIT;
  2253. } else {
  2254. value->type = SVG_FONTFAMILY_VALUE;
  2255. value->value = gf_strdup(value_string);
  2256. }
  2257. }
  2258. static void svg_parse_fontstyle(SVG_FontStyle *value, char *value_string)
  2259. {
  2260. if (!strcmp(value_string, "inherit")) {
  2261. *value = SVG_FONTSTYLE_INHERIT;
  2262. } else if (!strcmp(value_string, "normal")) {
  2263. *value = SVG_FONTSTYLE_NORMAL;
  2264. } else if (!strcmp(value_string, "italic")) {
  2265. *value = SVG_FONTSTYLE_ITALIC;
  2266. } else if (!strcmp(value_string, "oblique")) {
  2267. *value = SVG_FONTSTYLE_OBLIQUE;
  2268. }
  2269. }
  2270. static void svg_parse_fontweight(SVG_FontWeight *value, char *value_string)
  2271. {
  2272. if (!strcmp(value_string, "inherit")) {
  2273. *value = SVG_FONTWEIGHT_INHERIT;
  2274. } else if (!strcmp(value_string, "normal")) {
  2275. *value = SVG_FONTWEIGHT_NORMAL;
  2276. } else if (!strcmp(value_string, "bold")) {
  2277. *value = SVG_FONTWEIGHT_BOLD;
  2278. } else if (!strcmp(value_string, "bolder")) {
  2279. *value = SVG_FONTWEIGHT_BOLDER;
  2280. } else if (!strcmp(value_string, "lighter")) {
  2281. *value = SVG_FONTWEIGHT_LIGHTER;
  2282. } else if (!strcmp(value_string, "100")) {
  2283. *value = SVG_FONTWEIGHT_100;
  2284. } else if (!strcmp(value_string, "200")) {
  2285. *value = SVG_FONTWEIGHT_200;
  2286. } else if (!strcmp(value_string, "300")) {
  2287. *value = SVG_FONTWEIGHT_300;
  2288. } else if (!strcmp(value_string, "400")) {
  2289. *value = SVG_FONTWEIGHT_400;
  2290. } else if (!strcmp(value_string, "500")) {
  2291. *value = SVG_FONTWEIGHT_500;
  2292. } else if (!strcmp(value_string, "600")) {
  2293. *value = SVG_FONTWEIGHT_600;
  2294. } else if (!strcmp(value_string, "700")) {
  2295. *value = SVG_FONTWEIGHT_700;
  2296. } else if (!strcmp(value_string, "800")) {
  2297. *value = SVG_FONTWEIGHT_800;
  2298. } else if (!strcmp(value_string, "900")) {
  2299. *value = SVG_FONTWEIGHT_900;
  2300. }
  2301. }
  2302. static void svg_parse_fontvariant(SVG_FontVariant *value, char *value_string)
  2303. {
  2304. if (!strcmp(value_string, "inherit")) {
  2305. *value = SVG_FONTVARIANT_INHERIT;
  2306. } else if (!strcmp(value_string, "normal")) {
  2307. *value = SVG_FONTVARIANT_NORMAL;
  2308. } else if (!strcmp(value_string, "small-caps")) {
  2309. *value = SVG_FONTVARIANT_SMALLCAPS;
  2310. }
  2311. }
  2312. static void svg_parse_boolean(SVG_Boolean *value, char *value_string)
  2313. {
  2314. /*simple for text editable*/
  2315. if (!strcmp(value_string, "1") || !strcmp(value_string, "true") || !strcmp(value_string, "simple"))
  2316. *value = 1;
  2317. else
  2318. *value = 0;
  2319. }
  2320. static void smil_parse_time_list(GF_Node *e, GF_List *values, char *begin_or_end_list)
  2321. {
  2322. SMIL_Time *value;
  2323. char value_string[500];
  2324. char *str = begin_or_end_list, *tmp;
  2325. u32 len;
  2326. /* get rid of leading spaces */
  2327. while (*str == ' ') str++;
  2328. while (1) {
  2329. tmp = strchr(str, ';');
  2330. if (tmp) len = (u32) (tmp-str);
  2331. else len = (u32) strlen(str);
  2332. memcpy(value_string, str, len);
  2333. while (value_string[len - 1] == ' ' && len > 0) len--;
  2334. value_string[len] = 0;
  2335. GF_SAFEALLOC(value, SMIL_Time)
  2336. gf_list_add(values, value);
  2337. if (smil_parse_time(e, value, value_string) != GF_OK) goto err;
  2338. if (!tmp) break;
  2339. str = tmp + 1;
  2340. while (*str == ' ') str++;
  2341. }
  2342. /* sorting timing values */
  2343. if (gf_list_count(values) > 1) {
  2344. SMIL_Time *v, *sv;
  2345. GF_List *sorted = gf_list_new();
  2346. u32 i, count;
  2347. u8 added = 0;
  2348. do {
  2349. v = (SMIL_Time*)gf_list_get(values, 0);
  2350. gf_list_rem(values, 0);
  2351. added = 0;
  2352. count = gf_list_count(sorted);
  2353. for (i=0; i<count; i++) {
  2354. sv = (SMIL_Time*)gf_list_get(sorted, i);
  2355. if (v->type >= GF_SMIL_TIME_EVENT) {
  2356. /* unresolved or indefinite so add at the end of the sorted list */
  2357. gf_list_add(sorted, v);
  2358. added = 1;
  2359. break;
  2360. } else {
  2361. if (sv->type >= GF_SMIL_TIME_EVENT) {
  2362. gf_list_insert(sorted, v, i);
  2363. added = 1;
  2364. break;
  2365. } else {
  2366. if (v->clock <= sv->clock) {
  2367. gf_list_insert(sorted, v, i);
  2368. added = 1;
  2369. break;
  2370. }
  2371. }
  2372. }
  2373. }
  2374. if (!added) gf_list_add(sorted, v);
  2375. } while (gf_list_count(values) > 0);
  2376. count = gf_list_count(sorted);
  2377. for (i = 0; i < count; i++) {
  2378. gf_list_add(values, gf_list_get(sorted, i));
  2379. }
  2380. gf_list_del(sorted);
  2381. }
  2382. return;
  2383. err:
  2384. /* See SVG spec:
  2385. "If the 'begin' attribute is
  2386. syntactically invalid, in the list itself or in any of the individual
  2387. list values, it is equivalent to a single 'begin' value of 'indefinite'."*/
  2388. len = gf_list_count(values);
  2389. while (len) {
  2390. SMIL_Time *v = (SMIL_Time*)gf_list_get(values, 0);
  2391. if (v->element_id) gf_free(v->element_id);
  2392. gf_list_rem(values, 0);
  2393. gf_free(v);
  2394. len--;
  2395. }
  2396. GF_SAFEALLOC(value, SMIL_Time)
  2397. gf_list_add(values, value);
  2398. switch (e->sgprivate->tag) {
  2399. case TAG_SVG_discard:
  2400. value->type = GF_SMIL_TIME_CLOCK;
  2401. value->clock = 0;
  2402. break;
  2403. default:
  2404. value->type = GF_SMIL_TIME_INDEFINITE;
  2405. break;
  2406. }
  2407. return;
  2408. }
  2409. static void smil_parse_attributeType(SMIL_AttributeType *value, char *value_string)
  2410. {
  2411. if (!strcmp(value_string, "auto")) {
  2412. *value = SMIL_ATTRIBUTETYPE_AUTO;
  2413. } else if (!strcmp(value_string, "XML")) {
  2414. *value = SMIL_ATTRIBUTETYPE_XML;
  2415. } else if (!strcmp(value_string, "CSS")) {
  2416. *value = SMIL_ATTRIBUTETYPE_CSS;
  2417. }
  2418. }
  2419. static void smil_parse_min_max_dur_repeatdur(SMIL_Duration *value, char *value_string)
  2420. {
  2421. if (!strcmp(value_string, "indefinite")) {
  2422. value->type = SMIL_DURATION_INDEFINITE;
  2423. } else if (!strcmp(value_string, "media")) {
  2424. value->type = SMIL_DURATION_MEDIA;
  2425. } else {
  2426. Double ftime;
  2427. if ((svg_parse_clock_value(value_string, &ftime) == GF_OK) && (ftime >= 0)) {
  2428. value->clock_value = ftime;
  2429. value->type = SMIL_DURATION_DEFINED;
  2430. } else {
  2431. /* WARNING: Should this attribute in error be removed ? */
  2432. value->type = SMIL_DURATION_INDEFINITE;
  2433. }
  2434. }
  2435. }
  2436. static void smil_parse_repeatcount(SMIL_RepeatCount *value, char *value_string)
  2437. {
  2438. if (!strcmp(value_string, "indefinite")) {
  2439. value->type = SMIL_REPEATCOUNT_INDEFINITE;
  2440. } else {
  2441. Float _val;
  2442. sscanf(value_string, "%f", &_val);
  2443. value->type = SMIL_REPEATCOUNT_DEFINED;
  2444. value->count = FLT2FIX(_val);
  2445. }
  2446. }
  2447. static void smil_parse_fill(SMIL_Fill *value, char *value_string)
  2448. {
  2449. if (!strcmp(value_string, "freeze")) {
  2450. *value = SMIL_FILL_FREEZE;
  2451. } else if (!strcmp(value_string, "remove")) {
  2452. *value = SMIL_FILL_REMOVE;
  2453. }
  2454. }
  2455. static void smil_parse_restart(SMIL_Restart *value, char *value_string)
  2456. {
  2457. if (!strcmp(value_string, "always")) {
  2458. *value = SMIL_RESTART_ALWAYS;
  2459. } else if (!strcmp(value_string, "whenNotActive")) {
  2460. *value = SMIL_RESTART_WHENNOTACTIVE;
  2461. } else if (!strcmp(value_string, "never")) {
  2462. *value = SMIL_RESTART_NEVER;
  2463. }
  2464. }
  2465. static void smil_parse_calcmode(SMIL_CalcMode *value, char *value_string)
  2466. {
  2467. if (!strcmp(value_string, "discrete")) {
  2468. *value = SMIL_CALCMODE_DISCRETE;
  2469. } else if (!strcmp(value_string, "linear")) {
  2470. *value = SMIL_CALCMODE_LINEAR;
  2471. } else if (!strcmp(value_string, "paced")) {
  2472. *value = SMIL_CALCMODE_PACED;
  2473. } else if (!strcmp(value_string, "spline")) {
  2474. *value = SMIL_CALCMODE_SPLINE;
  2475. }
  2476. }
  2477. static void smil_parse_additive(SMIL_Additive *value, char *value_string)
  2478. {
  2479. if (!strcmp(value_string, "replace")) {
  2480. *value = SMIL_ADDITIVE_REPLACE;
  2481. } else if (!strcmp(value_string, "sum")) {
  2482. *value = SMIL_ADDITIVE_SUM;
  2483. }
  2484. }
  2485. static void smil_parse_accumulate(SMIL_Accumulate *value, char *value_string)
  2486. {
  2487. if (!strcmp(value_string, "none")) {
  2488. *value = SMIL_ACCUMULATE_NONE;
  2489. } else if (!strcmp(value_string, "sum")) {
  2490. *value = SMIL_ACCUMULATE_SUM;
  2491. }
  2492. }
  2493. static void smil_parse_syncBehaviorOrDefault(SMIL_SyncBehavior *value, char *value_string)
  2494. {
  2495. if (!strcmp(value_string, "inherit")) {
  2496. *value = SMIL_SYNCBEHAVIOR_INHERIT;
  2497. } else if (!strcmp(value_string, "default")) {
  2498. *value = SMIL_SYNCBEHAVIOR_DEFAULT;
  2499. } else if (!strcmp(value_string, "locked")) {
  2500. *value = SMIL_SYNCBEHAVIOR_LOCKED;
  2501. } else if (!strcmp(value_string, "canSlip")) {
  2502. *value = SMIL_SYNCBEHAVIOR_CANSLIP;
  2503. } else if (!strcmp(value_string, "independent")) {
  2504. *value = SMIL_SYNCBEHAVIOR_INDEPENDENT;
  2505. }
  2506. }
  2507. static void smil_parse_syncToleranceOrDefault(SMIL_SyncTolerance *value, char *value_string)
  2508. {
  2509. if (!strcmp(value_string, "inherit")) {
  2510. value->type = SMIL_SYNCTOLERANCE_INHERIT;
  2511. } else if (!strcmp(value_string, "default")) {
  2512. value->type = SMIL_SYNCTOLERANCE_DEFAULT;
  2513. } else {
  2514. value->type = SMIL_SYNCBEHAVIOR_LOCKED;
  2515. svg_parse_clock_value(value_string, &(value->value));
  2516. }
  2517. }
  2518. static void svg_parse_viewbox(SVG_ViewBox *value, char *value_string)
  2519. {
  2520. u32 read_chars;
  2521. char *str = value_string;
  2522. if (!strcmp(str, "none")) {
  2523. value->is_set = 0;
  2524. } else {
  2525. u32 i = 0;
  2526. value->is_set = 1;
  2527. read_chars = svg_parse_number(&(str[i]), &(value->x), 0);
  2528. if (!read_chars) return;
  2529. i += read_chars;
  2530. read_chars = svg_parse_number(&(str[i]), &(value->y), 0);
  2531. if (!read_chars) return;
  2532. i += read_chars;
  2533. read_chars = svg_parse_number(&(str[i]), &(value->width), 0);
  2534. if (!read_chars) return;
  2535. i += read_chars;
  2536. read_chars = svg_parse_number(&(str[i]), &(value->height), 0);
  2537. if (!read_chars) return;
  2538. i += read_chars;
  2539. }
  2540. }
  2541. /* Parses a list of coordinates or a list of lengths (in SVG, length and coordinate is the same type )*/
  2542. static void svg_parse_coordinates(GF_List *values, char *value_string)
  2543. {
  2544. SVG_Coordinate *c;
  2545. u32 i = 0;
  2546. char *str = value_string;
  2547. u32 len = (u32) strlen(str);
  2548. while (gf_list_count(values)) {
  2549. c = (SVG_Coordinate*)gf_list_get(values, 0);
  2550. gf_list_rem(values, 0);
  2551. gf_free(c);
  2552. }
  2553. while (i < len) {
  2554. u32 sub;
  2555. GF_SAFEALLOC(c, SVG_Coordinate)
  2556. sub = svg_parse_length(c, &(str[i]), 0);
  2557. if (!sub) {
  2558. gf_free(c);
  2559. return;
  2560. }
  2561. i+=sub;
  2562. gf_list_add(values, c);
  2563. }
  2564. }
  2565. /* Parse a point as a pair of number without units */
  2566. u32 svg_parse_point(SVG_Point *p, char *value_string)
  2567. {
  2568. u32 i = 0, j = 0;
  2569. i = svg_parse_number(&(value_string[i]), &(p->x), 0);
  2570. /* TODO: handle cases where a point has an invalid syntax */
  2571. j = svg_parse_number(&(value_string[i]), &(p->y), 0);
  2572. /* we need to detect an odd number of coordinates in polygon points list
  2573. cf. http://www.w3.org/TR/SVGMobile12/shapes.html#PolygonElement
  2574. see svg_parse_points */
  2575. if (j == 0) return 0;
  2576. else return i+j;
  2577. }
  2578. static u32 svg_parse_point_into_matrix(GF_Matrix2D *p, char *value_string)
  2579. {
  2580. u32 i = 0, j = 0;
  2581. gf_mx2d_init(*p);
  2582. i = svg_parse_number(&(value_string[i]), &(p->m[2]), 0);
  2583. if (i == 0) return 0;
  2584. j = svg_parse_number(&(value_string[i]), &(p->m[5]), 0);
  2585. if (j == 0) return 0;
  2586. return i+j;
  2587. }
  2588. /* Parses the points attribute of a polygon or polyline element */
  2589. static void svg_parse_points(GF_List *values, char *value_string)
  2590. {
  2591. u32 i = 0, j;
  2592. char *str = value_string;
  2593. u32 len = (u32) strlen(str);
  2594. while (i < len) {
  2595. SVG_Point *p;
  2596. GF_SAFEALLOC(p, SVG_Point)
  2597. j = svg_parse_point(p, &str[i]);
  2598. if (j == 0) {
  2599. /* cf. http://www.w3.org/TR/SVGMobile12/shapes.html#PolygonElement
  2600. If an odd number of coordinates is provided, then the element
  2601. is treated as if the attribute had not been specified.*/
  2602. while (gf_list_count(values)) {
  2603. p = (SVG_Point *)gf_list_get(values, 0);
  2604. gf_free(p);
  2605. gf_list_rem(values, 0);
  2606. }
  2607. return;
  2608. }
  2609. i += j;
  2610. gf_list_add(values, p);
  2611. }
  2612. }
  2613. /* Parses a list of numbers */
  2614. static void svg_parse_numbers(GF_List *values, char *value_string, Bool is_angle)
  2615. {
  2616. u32 read_chars;
  2617. u32 i = 0;
  2618. char *str = value_string;
  2619. u32 len = (u32) strlen(str);
  2620. while (i < len) {
  2621. Fixed *f;
  2622. GF_SAFEALLOC(f, Fixed)
  2623. read_chars = svg_parse_number(&(str[i]), f, is_angle);
  2624. if (!read_chars) {
  2625. gf_free(f);
  2626. return;
  2627. }
  2628. i += read_chars;
  2629. gf_list_add(values, f);
  2630. }
  2631. }
  2632. static void svg_string_list_add(GF_List *values, char *string, u32 string_type)
  2633. {
  2634. XMLRI *iri;
  2635. switch (string_type) {
  2636. case 1:
  2637. iri = (XMLRI*)gf_malloc(sizeof(XMLRI));
  2638. iri->type = XMLRI_STRING;
  2639. iri->string = gf_strdup(string);
  2640. gf_list_add(values, iri);
  2641. break;
  2642. default:
  2643. gf_list_add(values, gf_strdup(string));
  2644. break;
  2645. }
  2646. }
  2647. static void svg_parse_strings(GF_List *values, char *value_string, u32 string_type)
  2648. {
  2649. char *next, *sep = value_string;
  2650. while (gf_list_count(values)) {
  2651. next = (char*)gf_list_last(values);
  2652. gf_list_rem_last(values);
  2653. gf_free(next);
  2654. }
  2655. while (1) {
  2656. while (sep && sep[0]==' ') sep++;
  2657. if (!sep) break;
  2658. next = sep+1;
  2659. while (next[0]) {
  2660. if (strchr(" ;,", next[0])) break;
  2661. next++;
  2662. }
  2663. if (!next[0]) {
  2664. svg_string_list_add(values, sep, string_type);
  2665. break;
  2666. }
  2667. next[0]=0;
  2668. svg_string_list_add(values, sep, string_type);
  2669. next[0]=';';
  2670. sep = next+1;
  2671. while (strchr(" ,;", sep[0])) sep++;
  2672. }
  2673. }
  2674. static void svg_parse_strokedasharray(SVG_StrokeDashArray *value, char *value_string)
  2675. {
  2676. u32 read_chars;
  2677. if (!strcmp(value_string, "none")) {
  2678. value->type = SVG_STROKEDASHARRAY_NONE;
  2679. } else if (!strcmp(value_string, "inherit")) {
  2680. value->type = SVG_STROKEDASHARRAY_INHERIT;
  2681. } else {
  2682. UnitArray *vals = &(value->array);
  2683. GF_List *values = gf_list_new();
  2684. u32 i = 0;
  2685. u32 len = (u32) strlen(value_string);
  2686. char *str = value_string;
  2687. while (i < len) {
  2688. SVG_Length *f;
  2689. GF_SAFEALLOC(f, SVG_Length)
  2690. read_chars = svg_parse_length(f, &(str[i]), 0);
  2691. if (!read_chars) {
  2692. gf_free(f);
  2693. return;
  2694. }
  2695. i += read_chars;
  2696. gf_list_add(values, f);
  2697. }
  2698. vals->count = gf_list_count(values);
  2699. vals->units = (u8 *) gf_malloc(sizeof(u8)*vals->count);
  2700. vals->vals = (Fixed *) gf_malloc(sizeof(Fixed)*vals->count);
  2701. for (i = 0; i < vals->count; i++) {
  2702. SVG_Length *f = (SVG_Length *)gf_list_get(values, i);
  2703. vals->vals[i] = f->value;
  2704. vals->units[i] = f->type;
  2705. gf_free(f);
  2706. }
  2707. gf_list_del(values);
  2708. value->type = SVG_STROKEDASHARRAY_ARRAY;
  2709. }
  2710. }
  2711. static void svg_parse_zoomandpan(SVG_ZoomAndPan *value, char *value_string)
  2712. {
  2713. if (!strcmp(value_string, "disable")) {
  2714. *value = SVG_ZOOMANDPAN_DISABLE;
  2715. } else if (!strcmp(value_string, "magnify")) {
  2716. *value = SVG_ZOOMANDPAN_MAGNIFY;
  2717. }
  2718. }
  2719. static void svg_parse_preserveaspectratio(SVG_PreserveAspectRatio *par, char *attribute_content)
  2720. {
  2721. char *content = attribute_content;
  2722. while (*content == ' ') content++;
  2723. if (strstr(content, "defer")) {
  2724. par->defer = 1;
  2725. content += 4;
  2726. } else {
  2727. content = attribute_content;
  2728. }
  2729. while (*content == ' ') content++;
  2730. if (strstr(content, "none")) {
  2731. par->align = SVG_PRESERVEASPECTRATIO_NONE;
  2732. content+=4;
  2733. } else if (strstr(content, "xMinYMin")) {
  2734. par->align = SVG_PRESERVEASPECTRATIO_XMINYMIN;
  2735. content+=8;
  2736. } else if (strstr(content, "xMidYMin")) {
  2737. par->align = SVG_PRESERVEASPECTRATIO_XMIDYMIN;
  2738. content+=8;
  2739. } else if (strstr(content, "xMaxYMin")) {
  2740. par->align = SVG_PRESERVEASPECTRATIO_XMAXYMIN;
  2741. content+=8;
  2742. } else if (strstr(content, "xMinYMid")) {
  2743. par->align = SVG_PRESERVEASPECTRATIO_XMINYMID;
  2744. content+=8;
  2745. } else if (strstr(content, "xMidYMid")) {
  2746. par->align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
  2747. content+=8;
  2748. } else if (strstr(content, "xMaxYMid")) {
  2749. par->align = SVG_PRESERVEASPECTRATIO_XMAXYMID;
  2750. content+=8;
  2751. } else if (strstr(content, "xMinYMax")) {
  2752. par->align = SVG_PRESERVEASPECTRATIO_XMINYMAX;
  2753. content+=8;
  2754. } else if (strstr(content, "xMidYMax")) {
  2755. par->align = SVG_PRESERVEASPECTRATIO_XMIDYMAX;
  2756. content+=8;
  2757. } else if (strstr(content, "xMaxYMax")) {
  2758. par->align = SVG_PRESERVEASPECTRATIO_XMAXYMAX;
  2759. content+=8;
  2760. }
  2761. while (*content == ' ') content++;
  2762. if (*content == 0) return;
  2763. if (strstr(content, "meet")) {
  2764. par->meetOrSlice = SVG_MEETORSLICE_MEET;
  2765. } else if (strstr(content, "slice")) {
  2766. par->meetOrSlice = SVG_MEETORSLICE_SLICE;
  2767. }
  2768. }
  2769. static void svg_parse_animatetransform_type(SVG_TransformType *anim_transform_type, char *attribute_content)
  2770. {
  2771. *anim_transform_type = SVG_TRANSFORM_MATRIX;
  2772. if (!strcmp(attribute_content, "scale")) {
  2773. *anim_transform_type = SVG_TRANSFORM_SCALE;
  2774. } else if (!strcmp(attribute_content, "rotate")) {
  2775. *anim_transform_type = SVG_TRANSFORM_ROTATE;
  2776. } else if (!strcmp(attribute_content, "translate")) {
  2777. *anim_transform_type = SVG_TRANSFORM_TRANSLATE;
  2778. } else if (!strcmp(attribute_content, "skewX")) {
  2779. *anim_transform_type = SVG_TRANSFORM_SKEWX;
  2780. } else if (!strcmp(attribute_content, "skewY")) {
  2781. *anim_transform_type = SVG_TRANSFORM_SKEWY;
  2782. }
  2783. }
  2784. static void svg_parse_focushighlight(SVG_FocusHighlight *fh, char *attribute_content)
  2785. {
  2786. if (!strcmp(attribute_content, "auto")) {
  2787. *fh = SVG_FOCUSHIGHLIGHT_AUTO;
  2788. } else if (!strcmp(attribute_content, "none")) {
  2789. *fh = SVG_FOCUSHIGHLIGHT_NONE;
  2790. }
  2791. }
  2792. static void svg_parse_focusable(SVG_Focusable *f, char *attribute_content)
  2793. {
  2794. if (!strcmp(attribute_content, "true")) {
  2795. *f = SVG_FOCUSABLE_TRUE;
  2796. } else if (!strcmp(attribute_content, "false")) {
  2797. *f = SVG_FOCUSABLE_FALSE;
  2798. } else {
  2799. *f = SVG_FOCUSABLE_AUTO;
  2800. }
  2801. }
  2802. static void svg_parse_initialvisibility(SVG_InitialVisibility *iv, char *attribute_content)
  2803. {
  2804. if (!strcmp(attribute_content, "whenStarted")) {
  2805. *iv = SVG_INITIALVISIBILTY_WHENSTARTED;
  2806. } else if (!strcmp(attribute_content, "always")) {
  2807. *iv = SVG_INITIALVISIBILTY_ALWAYS;
  2808. }
  2809. }
  2810. static void svg_parse_overlay(SVG_Overlay *o, char *attribute_content)
  2811. {
  2812. if (!strcmp(attribute_content, "none")) {
  2813. *o = SVG_OVERLAY_NONE;
  2814. } else if (!strcmp(attribute_content, "top")) {
  2815. *o = SVG_OVERLAY_TOP;
  2816. }
  2817. }
  2818. static void svg_parse_transformbehavior(SVG_TransformBehavior *tb, char *attribute_content)
  2819. {
  2820. if (!strcmp(attribute_content, "geometric")) {
  2821. *tb = SVG_TRANSFORMBEHAVIOR_GEOMETRIC;
  2822. } else if (!strcmp(attribute_content, "pinned")) {
  2823. *tb = SVG_TRANSFORMBEHAVIOR_PINNED;
  2824. } else if (!strcmp(attribute_content, "pinned90")) {
  2825. *tb = SVG_TRANSFORMBEHAVIOR_PINNED90;
  2826. } else if (!strcmp(attribute_content, "pinned180")) {
  2827. *tb = SVG_TRANSFORMBEHAVIOR_PINNED180;
  2828. } else if (!strcmp(attribute_content, "pinned270")) {
  2829. *tb = SVG_TRANSFORMBEHAVIOR_PINNED270;
  2830. }
  2831. }
  2832. static void svg_parse_focus(GF_Node *e, SVG_Focus *o, char *attribute_content)
  2833. {
  2834. if (o->target.string) gf_free(o->target.string);
  2835. o->target.string = NULL;
  2836. o->target.target = NULL;
  2837. if (!strcmp(attribute_content, "self")) o->type = SVG_FOCUS_SELF;
  2838. else if (!strcmp(attribute_content, "auto")) o->type = SVG_FOCUS_AUTO;
  2839. else if (!strnicmp(attribute_content, "url(", 4)) {
  2840. char *sep = strrchr(attribute_content, ')');
  2841. if (sep) sep[0] = 0;
  2842. o->type = SVG_FOCUS_IRI;
  2843. svg_parse_iri(e, &o->target, attribute_content+4);
  2844. if (sep) sep[0] = ')';
  2845. }
  2846. }
  2847. /* end of Basic SVG datatype parsing functions */
  2848. void svg_parse_one_anim_value(GF_Node *n, SMIL_AnimateValue *anim_value, char *attribute_content, u8 anim_value_type)
  2849. {
  2850. GF_FieldInfo info;
  2851. info.fieldType = anim_value_type;
  2852. info.far_ptr = gf_svg_create_attribute_value(anim_value_type);
  2853. if (info.far_ptr) gf_svg_parse_attribute(n, &info, attribute_content, 0);
  2854. anim_value->value = info.far_ptr;
  2855. anim_value->type = anim_value_type;
  2856. }
  2857. void svg_parse_anim_values(GF_Node *n, SMIL_AnimateValues *anim_values, char *anim_values_string, u8 anim_value_type)
  2858. {
  2859. u32 i = 0;
  2860. char *str;
  2861. s32 psemi = -1;
  2862. GF_FieldInfo info;
  2863. info.fieldType = anim_value_type;
  2864. anim_values->type = anim_value_type;
  2865. str = anim_values_string;
  2866. while (1) {
  2867. if (str[i] == ';' || str[i] == 0) {
  2868. u32 single_value_len = 0;
  2869. char c;
  2870. single_value_len = i - (psemi+1);
  2871. c = str [ (psemi+1) + single_value_len];
  2872. str [ (psemi+1) + single_value_len] = 0;
  2873. info.far_ptr = gf_svg_create_attribute_value(anim_value_type);
  2874. if (info.far_ptr) {
  2875. gf_svg_parse_attribute(n, &info, str + (psemi+1), anim_value_type);
  2876. gf_list_add(anim_values->values, info.far_ptr);
  2877. }
  2878. str [ (psemi+1) + single_value_len] = c;
  2879. psemi = i;
  2880. if (!str[i]) return;
  2881. }
  2882. i++;
  2883. }
  2884. }
  2885. GF_Err laser_parse_choice(LASeR_Choice *choice, char *attribute_content)
  2886. {
  2887. if (!strcmp(attribute_content, "none")) {
  2888. choice->type = LASeR_CHOICE_NONE;
  2889. } else if (!strcmp(attribute_content, "all")) {
  2890. choice->type = LASeR_CHOICE_ALL;
  2891. } else {
  2892. choice->type = LASeR_CHOICE_N;
  2893. choice->choice_index = atoi(attribute_content);
  2894. }
  2895. return GF_OK;
  2896. }
  2897. GF_Err laser_parse_size(LASeR_Size *size, char *attribute_content)
  2898. {
  2899. char *str = attribute_content;
  2900. u32 i = 0;
  2901. i+=svg_parse_number(&(str[i]), &(size->width), 0);
  2902. i+=svg_parse_number(&(str[i]), &(size->height), 0);
  2903. return GF_OK;
  2904. }
  2905. GF_Err gf_svg_parse_element_id(GF_Node *n, const char *nodename, Bool warning_if_defined)
  2906. {
  2907. GF_SceneGraph *sg = gf_node_get_graph((GF_Node *)n);
  2908. u32 id = gf_sg_get_max_node_id(sg) + 1;
  2909. gf_node_set_id(n, id, nodename);
  2910. return GF_OK;
  2911. }
  2912. /* Parse an SVG attribute */
  2913. GF_EXPORT
  2914. GF_Err gf_svg_parse_attribute(GF_Node *n, GF_FieldInfo *info, char *attribute_content, u8 anim_value_type)
  2915. {
  2916. /* for all attributes, except strings, apply some sort of white space normalization*/
  2917. if (info->fieldType != DOM_String_datatype && strlen(attribute_content)) {
  2918. u32 i, len;
  2919. /*remove spaces at the begining*/
  2920. while (attribute_content[0] && (strchr("\r\n\t ", attribute_content[0])))
  2921. attribute_content++;
  2922. /*change all special chars in spaces*/
  2923. i=0;
  2924. len = (u32) strlen(attribute_content);
  2925. while (i<len) {
  2926. if (strchr("\r\n\t", attribute_content[i]))
  2927. attribute_content[i] = ' ';
  2928. i++;
  2929. }
  2930. /*remove spaces in the end*/
  2931. while (len && attribute_content[len-1]==' ') {
  2932. attribute_content[len-1] = 0;
  2933. len--;
  2934. }
  2935. }
  2936. switch (info->fieldType) {
  2937. case SVG_Boolean_datatype:
  2938. svg_parse_boolean((SVG_Boolean *)info->far_ptr, attribute_content);
  2939. break;
  2940. case SVG_Color_datatype:
  2941. svg_parse_color((SVG_Color *)info->far_ptr, attribute_content);
  2942. break;
  2943. case SVG_Paint_datatype:
  2944. svg_parse_paint(n, (SVG_Paint *)info->far_ptr, attribute_content);
  2945. break;
  2946. /* beginning of keyword type parsing */
  2947. case SVG_FillRule_datatype:
  2948. svg_parse_clipfillrule((SVG_FillRule *)info->far_ptr, attribute_content);
  2949. break;
  2950. case SVG_StrokeLineJoin_datatype:
  2951. svg_parse_strokelinejoin((SVG_StrokeLineJoin *)info->far_ptr, attribute_content);
  2952. break;
  2953. case SVG_StrokeLineCap_datatype:
  2954. svg_parse_strokelinecap((SVG_StrokeLineCap *)info->far_ptr, attribute_content);
  2955. break;
  2956. case SVG_FontStyle_datatype:
  2957. svg_parse_fontstyle((SVG_FontStyle *)info->far_ptr, attribute_content);
  2958. break;
  2959. case SVG_FontWeight_datatype:
  2960. svg_parse_fontweight((SVG_FontWeight *)info->far_ptr, attribute_content);
  2961. break;
  2962. case SVG_FontVariant_datatype:
  2963. svg_parse_fontvariant((SVG_FontVariant *)info->far_ptr, attribute_content);
  2964. break;
  2965. case SVG_TextAnchor_datatype:
  2966. svg_parse_textanchor((SVG_TextAnchor *)info->far_ptr, attribute_content);
  2967. break;
  2968. case SVG_Display_datatype:
  2969. svg_parse_display((SVG_Display *)info->far_ptr, attribute_content);
  2970. break;
  2971. case SVG_Visibility_datatype:
  2972. svg_parse_visibility((SVG_Visibility *)info->far_ptr, attribute_content);
  2973. break;
  2974. case SVG_Overflow_datatype:
  2975. svg_parse_overflow((SVG_Overflow *)info->far_ptr, attribute_content);
  2976. break;
  2977. case SVG_ZoomAndPan_datatype:
  2978. svg_parse_zoomandpan((SVG_ZoomAndPan *)info->far_ptr, attribute_content);
  2979. break;
  2980. case SVG_DisplayAlign_datatype:
  2981. svg_parse_displayalign((SVG_DisplayAlign *)info->far_ptr, attribute_content);
  2982. break;
  2983. case SVG_TextAlign_datatype:
  2984. svg_parse_textalign((SVG_TextAlign *)info->far_ptr, attribute_content);
  2985. break;
  2986. case SVG_PointerEvents_datatype:
  2987. svg_parse_pointerevents((SVG_PointerEvents *)info->far_ptr, attribute_content);
  2988. break;
  2989. case SVG_RenderingHint_datatype:
  2990. svg_parse_renderinghint((SVG_RenderingHint *)info->far_ptr, attribute_content);
  2991. break;
  2992. case SVG_VectorEffect_datatype:
  2993. svg_parse_vectoreffect((SVG_VectorEffect *)info->far_ptr, attribute_content);
  2994. break;
  2995. case SVG_PlaybackOrder_datatype:
  2996. svg_parse_playbackorder((SVG_PlaybackOrder *)info->far_ptr, attribute_content);
  2997. break;
  2998. case SVG_TimelineBegin_datatype:
  2999. svg_parse_timelinebegin((SVG_TimelineBegin *)info->far_ptr, attribute_content);
  3000. break;
  3001. case XML_Space_datatype:
  3002. svg_parse_xmlspace((XML_Space *)info->far_ptr, attribute_content);
  3003. break;
  3004. case XMLEV_Propagate_datatype:
  3005. svg_parse_xmlev_propagate((XMLEV_Propagate *)info->far_ptr, attribute_content);
  3006. break;
  3007. case XMLEV_DefaultAction_datatype:
  3008. svg_parse_xmlev_defaultAction((XMLEV_DefaultAction *)info->far_ptr, attribute_content);
  3009. break;
  3010. case XMLEV_Phase_datatype:
  3011. svg_parse_xmlev_phase((XMLEV_Phase *)info->far_ptr, attribute_content);
  3012. break;
  3013. case SMIL_SyncBehavior_datatype:
  3014. smil_parse_syncBehaviorOrDefault((SMIL_SyncBehavior *)info->far_ptr, attribute_content);
  3015. break;
  3016. case SMIL_SyncTolerance_datatype:
  3017. smil_parse_syncToleranceOrDefault((SMIL_SyncTolerance *)info->far_ptr, attribute_content);
  3018. break;
  3019. case SMIL_AttributeType_datatype:
  3020. smil_parse_attributeType((SMIL_AttributeType *)info->far_ptr, attribute_content);
  3021. break;
  3022. case SMIL_CalcMode_datatype:
  3023. smil_parse_calcmode((SMIL_CalcMode *)info->far_ptr, attribute_content);
  3024. break;
  3025. case SMIL_Additive_datatype:
  3026. smil_parse_additive((SMIL_CalcMode *)info->far_ptr, attribute_content);
  3027. break;
  3028. case SMIL_Accumulate_datatype:
  3029. smil_parse_accumulate((SMIL_Accumulate *)info->far_ptr, attribute_content);
  3030. break;
  3031. case SMIL_Restart_datatype:
  3032. smil_parse_restart((SMIL_Restart *)info->far_ptr, attribute_content);
  3033. break;
  3034. case SMIL_Fill_datatype:
  3035. smil_parse_fill((SMIL_Fill *)info->far_ptr, attribute_content);
  3036. break;
  3037. case SVG_GradientUnit_datatype:
  3038. *((SVG_GradientUnit *)info->far_ptr) = !strcmp(attribute_content, "userSpaceOnUse") ? SVG_GRADIENTUNITS_USER : SVG_GRADIENTUNITS_OBJECT;
  3039. break;
  3040. case SVG_FocusHighlight_datatype:
  3041. svg_parse_focushighlight((SVG_FocusHighlight*)info->far_ptr, attribute_content);
  3042. break;
  3043. case SVG_Focusable_datatype:
  3044. svg_parse_focusable((SVG_Focusable*)info->far_ptr, attribute_content);
  3045. break;
  3046. case SVG_InitialVisibility_datatype:
  3047. svg_parse_initialvisibility((SVG_InitialVisibility*)info->far_ptr, attribute_content);
  3048. break;
  3049. case SVG_Overlay_datatype:
  3050. svg_parse_overlay((SVG_Overlay*)info->far_ptr, attribute_content);
  3051. break;
  3052. case SVG_TransformBehavior_datatype:
  3053. svg_parse_transformbehavior((SVG_TransformBehavior*)info->far_ptr, attribute_content);
  3054. break;
  3055. case SVG_SpreadMethod_datatype:
  3056. if (!strcmp(attribute_content, "reflect")) *(u8*)info->far_ptr = SVG_SPREAD_REFLECT;
  3057. else if (!strcmp(attribute_content, "repeat")) *(u8*)info->far_ptr = SVG_SPREAD_REPEAT;
  3058. else *(u8*)info->far_ptr = SVG_SPREAD_PAD;
  3059. break;
  3060. case SVG_Filter_TransferType_datatype:
  3061. if (!strcmp(attribute_content, "table")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_TABLE;
  3062. else if (!strcmp(attribute_content, "discrete")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_DISCRETE;
  3063. else if (!strcmp(attribute_content, "linear")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_LINEAR;
  3064. else if (!strcmp(attribute_content, "gamma")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_GAMMA;
  3065. else *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_IDENTITY;
  3066. break;
  3067. /* end of keyword type parsing */
  3068. /* keyword | numbers (with possibly units) */
  3069. case SVG_Length_datatype:
  3070. case SVG_Coordinate_datatype:
  3071. case SVG_FontSize_datatype:
  3072. case SVG_Rotate_datatype:
  3073. case SVG_Number_datatype:
  3074. svg_parse_length((SVG_Number*)info->far_ptr, attribute_content, 0);
  3075. break;
  3076. case SMIL_AnimateValue_datatype:
  3077. svg_parse_one_anim_value(n, (SMIL_AnimateValue*)info->far_ptr, attribute_content, anim_value_type);
  3078. break;
  3079. case SMIL_AnimateValues_datatype:
  3080. svg_parse_anim_values(n, (SMIL_AnimateValues*)info->far_ptr, attribute_content, anim_value_type);
  3081. break;
  3082. case XMLRI_datatype:
  3083. svg_parse_iri(n, (XMLRI*)info->far_ptr, attribute_content);
  3084. break;
  3085. case XML_IDREF_datatype:
  3086. svg_parse_idref(n, (XMLRI*)info->far_ptr, attribute_content);
  3087. break;
  3088. case SMIL_AttributeName_datatype:
  3089. ((SMIL_AttributeName *)info->far_ptr)->name = gf_strdup(attribute_content);
  3090. break;
  3091. case SMIL_Times_datatype:
  3092. smil_parse_time_list(n, *(GF_List **)info->far_ptr, attribute_content);
  3093. break;
  3094. case SMIL_Duration_datatype:
  3095. smil_parse_min_max_dur_repeatdur((SMIL_Duration*)info->far_ptr, attribute_content);
  3096. break;
  3097. case SMIL_RepeatCount_datatype:
  3098. smil_parse_repeatcount((SMIL_RepeatCount*)info->far_ptr, attribute_content);
  3099. break;
  3100. case SVG_PathData_datatype:
  3101. svg_parse_path((SVG_PathData*)info->far_ptr, attribute_content);
  3102. break;
  3103. case SVG_Points_datatype:
  3104. svg_parse_points(*(GF_List **)(info->far_ptr), attribute_content);
  3105. break;
  3106. case SMIL_KeyTimes_datatype:
  3107. case SMIL_KeyPoints_datatype:
  3108. case SMIL_KeySplines_datatype:
  3109. case SVG_Numbers_datatype:
  3110. svg_parse_numbers(*(GF_List **)(info->far_ptr), attribute_content, 0);
  3111. break;
  3112. case SVG_Coordinates_datatype:
  3113. svg_parse_coordinates(*(GF_List **)(info->far_ptr), attribute_content);
  3114. break;
  3115. case SVG_ViewBox_datatype:
  3116. svg_parse_viewbox((SVG_ViewBox*)info->far_ptr, attribute_content);
  3117. break;
  3118. case SVG_StrokeDashArray_datatype:
  3119. svg_parse_strokedasharray((SVG_StrokeDashArray*)info->far_ptr, attribute_content);
  3120. break;
  3121. case SVG_FontFamily_datatype:
  3122. svg_parse_fontfamily((SVG_FontFamily*)info->far_ptr, attribute_content);
  3123. break;
  3124. case SVG_Motion_datatype:
  3125. svg_parse_point_into_matrix((GF_Matrix2D*)info->far_ptr, attribute_content);
  3126. break;
  3127. case SVG_Transform_datatype:
  3128. svg_parse_transform((SVG_Transform*)info->far_ptr, attribute_content);
  3129. break;
  3130. case SVG_Transform_Translate_datatype:
  3131. {
  3132. u32 i = 0;
  3133. SVG_Point *p = (SVG_Point *)info->far_ptr;;
  3134. i+=svg_parse_number(&(attribute_content[i]), &(p->x), 0);
  3135. if (attribute_content[i] == 0) {
  3136. p->y = 0;
  3137. } else {
  3138. i+=svg_parse_number(&(attribute_content[i]), &(p->y), 0);
  3139. }
  3140. }
  3141. break;
  3142. case SVG_Transform_Scale_datatype:
  3143. {
  3144. u32 i = 0;
  3145. SVG_Point *p = (SVG_Point *)info->far_ptr;;
  3146. i+=svg_parse_number(&(attribute_content[i]), &(p->x), 0);
  3147. if (attribute_content[i] == 0) {
  3148. p->y = p->x;
  3149. } else {
  3150. i+=svg_parse_number(&(attribute_content[i]), &(p->y), 0);
  3151. }
  3152. }
  3153. break;
  3154. case SVG_Transform_SkewX_datatype:
  3155. case SVG_Transform_SkewY_datatype:
  3156. {
  3157. Fixed *p = (Fixed *)info->far_ptr;
  3158. svg_parse_number(attribute_content, p, 1);
  3159. }
  3160. break;
  3161. case SVG_Transform_Rotate_datatype:
  3162. {
  3163. u32 i = 0;
  3164. SVG_Point_Angle *p = (SVG_Point_Angle *)info->far_ptr;;
  3165. i+=svg_parse_number(&(attribute_content[i]), &(p->angle), 1);
  3166. if (attribute_content[i] == 0) {
  3167. p->y = p->x = 0;
  3168. } else {
  3169. i+=svg_parse_number(&(attribute_content[i]), &(p->x), 0);
  3170. i+=svg_parse_number(&(attribute_content[i]), &(p->y), 0);
  3171. }
  3172. }
  3173. break;
  3174. case SVG_PreserveAspectRatio_datatype:
  3175. svg_parse_preserveaspectratio((SVG_PreserveAspectRatio*)info->far_ptr, attribute_content);
  3176. break;
  3177. case SVG_TransformType_datatype:
  3178. svg_parse_animatetransform_type((SVG_TransformType*)info->far_ptr, attribute_content);
  3179. break;
  3180. case SVG_ID_datatype:
  3181. case DOM_String_datatype:
  3182. case SVG_ContentType_datatype:
  3183. case SVG_LanguageID_datatype:
  3184. if (*(SVG_String *)info->far_ptr) gf_free(*(SVG_String *)info->far_ptr);
  3185. *(SVG_String *)info->far_ptr = gf_strdup(attribute_content);
  3186. break;
  3187. case DOM_StringList_datatype:
  3188. svg_parse_strings(*(GF_List **)info->far_ptr, attribute_content, 0);
  3189. break;
  3190. case XMLRI_List_datatype:
  3191. svg_parse_strings(*(GF_List **)info->far_ptr, attribute_content, 1);
  3192. break;
  3193. case XMLEV_Event_datatype:
  3194. {
  3195. XMLEV_Event *xml_ev = (XMLEV_Event *)info->far_ptr;
  3196. char *sep = strchr(attribute_content, '(');
  3197. if (sep) {
  3198. sep[0] = 0;
  3199. xml_ev->type = gf_dom_event_type_by_name(attribute_content);
  3200. sep[0] = '(';
  3201. if ((xml_ev->type == GF_EVENT_REPEAT) || (xml_ev->type == GF_EVENT_REPEAT_EVENT)) {
  3202. char _v;
  3203. sscanf(sep, "(%c)", &_v);
  3204. xml_ev->parameter = _v;
  3205. } else { /* key events ... */
  3206. char *sep2 = strchr(attribute_content, ')');
  3207. sep2[0] = 0;
  3208. xml_ev->parameter = gf_dom_get_key_type(sep+1);
  3209. sep2[0] = ')';
  3210. }
  3211. } else {
  3212. xml_ev->parameter = 0;
  3213. xml_ev->type = gf_dom_event_type_by_name(attribute_content);
  3214. }
  3215. }
  3216. break;
  3217. case SVG_Focus_datatype:
  3218. svg_parse_focus(n, (SVG_Focus*)info->far_ptr, attribute_content);
  3219. break;
  3220. case LASeR_Choice_datatype:
  3221. laser_parse_choice((LASeR_Choice*)info->far_ptr, attribute_content);
  3222. break;
  3223. case LASeR_Size_datatype:
  3224. laser_parse_size((LASeR_Size*)info->far_ptr, attribute_content);
  3225. break;
  3226. case SVG_Clock_datatype:
  3227. svg_parse_clock_value(attribute_content, (SVG_Clock*)info->far_ptr);
  3228. break;
  3229. case SVG_Unknown_datatype:
  3230. if (*(SVG_String *)info->far_ptr) gf_free(*(SVG_String *)info->far_ptr);
  3231. *(SVG_String *)info->far_ptr = gf_strdup(attribute_content);
  3232. break;
  3233. default:
  3234. GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Parsing] Cannot parse attribute %s\n", info->name, gf_svg_attribute_type_to_string(info->fieldType)));
  3235. break;
  3236. }
  3237. return GF_OK;
  3238. }
  3239. void svg_parse_one_style(GF_Node *n, char *one_style)
  3240. {
  3241. GF_FieldInfo info;
  3242. char *c, sep;
  3243. u32 attributeNameLen;
  3244. while (*one_style == ' ') one_style++;
  3245. c = strchr(one_style, ':');
  3246. if (!c) return;
  3247. attributeNameLen = (u32) (c - one_style);
  3248. sep = one_style[attributeNameLen];
  3249. one_style[attributeNameLen] = 0;
  3250. while (strchr("\r\n\t ", one_style[0]))
  3251. one_style++;
  3252. if (!gf_node_get_field_by_name(n, one_style, &info)) {
  3253. c++;
  3254. gf_svg_parse_attribute(n, &info, c, 0);
  3255. } else {
  3256. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Attribute %s does not belong to element %s.\n", one_style, gf_node_get_class_name(n)));
  3257. }
  3258. one_style[attributeNameLen] = sep;
  3259. }
  3260. void gf_svg_parse_style(GF_Node *n, char *style)
  3261. {
  3262. u32 i = 0;
  3263. char *str = style;
  3264. s32 psemi = -1;
  3265. while (1) {
  3266. if (str[i] == ';' || str[i] == 0) {
  3267. u32 single_value_len = 0;
  3268. single_value_len = i - (psemi+1);
  3269. if (single_value_len) {
  3270. char c = str[psemi+1 + single_value_len];
  3271. str[psemi+1 + single_value_len] = 0;
  3272. svg_parse_one_style(n, str + psemi+1);
  3273. str[psemi+1 + single_value_len] = c;
  3274. psemi = i;
  3275. }
  3276. if (!str[i]) return;
  3277. }
  3278. i++;
  3279. }
  3280. }
  3281. GF_EXPORT
  3282. void *gf_svg_create_attribute_value(u32 attribute_type)
  3283. {
  3284. switch (attribute_type) {
  3285. case SVG_Boolean_datatype:
  3286. {
  3287. SVG_Boolean *b;
  3288. GF_SAFEALLOC(b, SVG_Boolean)
  3289. return b;
  3290. }
  3291. break;
  3292. case SVG_Color_datatype:
  3293. {
  3294. SVG_Color *color;
  3295. GF_SAFEALLOC(color, SVG_Color)
  3296. return color;
  3297. }
  3298. break;
  3299. case SVG_Paint_datatype:
  3300. {
  3301. SVG_Paint *paint;
  3302. GF_SAFEALLOC(paint, SVG_Paint)
  3303. return paint;
  3304. }
  3305. break;
  3306. /* keyword types */
  3307. case SVG_FillRule_datatype:
  3308. case SVG_StrokeLineJoin_datatype:
  3309. case SVG_StrokeLineCap_datatype:
  3310. case SVG_FontStyle_datatype:
  3311. case SVG_FontWeight_datatype:
  3312. case SVG_FontVariant_datatype:
  3313. case SVG_TextAnchor_datatype:
  3314. case SVG_Display_datatype:
  3315. case SVG_Visibility_datatype:
  3316. case SVG_Overflow_datatype:
  3317. case SVG_ZoomAndPan_datatype:
  3318. case SVG_DisplayAlign_datatype:
  3319. case SVG_TextAlign_datatype:
  3320. case SVG_PointerEvents_datatype:
  3321. case SVG_RenderingHint_datatype:
  3322. case SVG_VectorEffect_datatype:
  3323. case SVG_PlaybackOrder_datatype:
  3324. case SVG_TimelineBegin_datatype:
  3325. case XML_Space_datatype:
  3326. case XMLEV_Propagate_datatype:
  3327. case XMLEV_DefaultAction_datatype:
  3328. case XMLEV_Phase_datatype:
  3329. case SMIL_SyncBehavior_datatype:
  3330. case SMIL_AttributeType_datatype:
  3331. case SMIL_CalcMode_datatype:
  3332. case SMIL_Additive_datatype:
  3333. case SMIL_Accumulate_datatype:
  3334. case SMIL_Restart_datatype:
  3335. case SMIL_Fill_datatype:
  3336. case SVG_TransformType_datatype:
  3337. case SVG_FocusHighlight_datatype:
  3338. case SVG_InitialVisibility_datatype:
  3339. case SVG_GradientUnit_datatype:
  3340. case SVG_Overlay_datatype:
  3341. case SVG_TransformBehavior_datatype:
  3342. case SVG_SpreadMethod_datatype:
  3343. case SVG_Focusable_datatype:
  3344. case SVG_Filter_TransferType_datatype:
  3345. {
  3346. u8 *keyword;
  3347. GF_SAFEALLOC(keyword, u8)
  3348. return keyword;
  3349. }
  3350. break;
  3351. case SMIL_SyncTolerance_datatype:
  3352. {
  3353. SMIL_SyncTolerance *st;
  3354. GF_SAFEALLOC(st, SMIL_SyncTolerance)
  3355. return st;
  3356. }
  3357. break;
  3358. /* inheritable floats */
  3359. case SVG_FontSize_datatype:
  3360. case SVG_Length_datatype:
  3361. case SVG_Coordinate_datatype:
  3362. case SVG_Rotate_datatype:
  3363. case SVG_Number_datatype:
  3364. {
  3365. SVG_Number *number;
  3366. GF_SAFEALLOC(number, SVG_Number)
  3367. return number;
  3368. }
  3369. break;
  3370. case SVG_StrokeDashArray_datatype:
  3371. {
  3372. SVG_StrokeDashArray *array;
  3373. GF_SAFEALLOC(array, SVG_StrokeDashArray)
  3374. return array;
  3375. }
  3376. break;
  3377. case SVG_Motion_datatype:
  3378. {
  3379. GF_Matrix2D *p;
  3380. GF_SAFEALLOC(p, GF_Matrix2D)
  3381. gf_mx2d_init(*p);
  3382. return p;
  3383. }
  3384. break;
  3385. case SVG_Transform_datatype:
  3386. {
  3387. SVG_Transform *p;
  3388. GF_SAFEALLOC(p, SVG_Transform)
  3389. gf_mx2d_init(p->mat);
  3390. return p;
  3391. }
  3392. break;
  3393. case SVG_Transform_Translate_datatype:
  3394. case SVG_Transform_Scale_datatype:
  3395. {
  3396. SVG_Point *p;
  3397. GF_SAFEALLOC(p, SVG_Point)
  3398. return p;
  3399. }
  3400. break;
  3401. case SVG_Transform_SkewX_datatype:
  3402. case SVG_Transform_SkewY_datatype:
  3403. {
  3404. Fixed *p;
  3405. GF_SAFEALLOC(p, Fixed)
  3406. return p;
  3407. }
  3408. break;
  3409. case SVG_Transform_Rotate_datatype:
  3410. {
  3411. SVG_Point_Angle *p;
  3412. GF_SAFEALLOC(p, SVG_Point_Angle)
  3413. return p;
  3414. }
  3415. break;
  3416. case SVG_ViewBox_datatype:
  3417. {
  3418. SVG_ViewBox *viewbox;
  3419. GF_SAFEALLOC(viewbox, SVG_ViewBox)
  3420. return viewbox;
  3421. }
  3422. break;
  3423. case XMLRI_datatype:
  3424. case XML_IDREF_datatype:
  3425. {
  3426. XMLRI *iri;
  3427. GF_SAFEALLOC(iri, XMLRI)
  3428. return iri;
  3429. }
  3430. break;
  3431. case SVG_FontFamily_datatype:
  3432. {
  3433. SVG_FontFamily *fontfamily;
  3434. GF_SAFEALLOC(fontfamily, SVG_FontFamily)
  3435. return fontfamily;
  3436. }
  3437. break;
  3438. case DOM_String_datatype:
  3439. case SVG_ContentType_datatype:
  3440. case SVG_LanguageID_datatype:
  3441. case SVG_ID_datatype:
  3442. {
  3443. SVG_String *string;
  3444. GF_SAFEALLOC(string, SVG_String)
  3445. return string;
  3446. }
  3447. break;
  3448. case DOM_StringList_datatype:
  3449. case XMLRI_List_datatype:
  3450. case SVG_Points_datatype:
  3451. case SVG_Coordinates_datatype:
  3452. case SMIL_Times_datatype:
  3453. case SMIL_KeySplines_datatype:
  3454. case SMIL_KeyTimes_datatype:
  3455. case SMIL_KeyPoints_datatype:
  3456. case SVG_Numbers_datatype:
  3457. {
  3458. ListOfXXX *list;
  3459. GF_SAFEALLOC(list, ListOfXXX)
  3460. *list = gf_list_new();
  3461. return list;
  3462. }
  3463. break;
  3464. case SVG_PreserveAspectRatio_datatype:
  3465. {
  3466. SVG_PreserveAspectRatio *par;
  3467. GF_SAFEALLOC(par, SVG_PreserveAspectRatio)
  3468. return par;
  3469. }
  3470. break;
  3471. case SVG_PathData_datatype:
  3472. {
  3473. SVG_PathData *path;
  3474. GF_SAFEALLOC(path, SVG_PathData);
  3475. #if USE_GF_PATH
  3476. gf_path_reset(path);
  3477. path->fineness = FIX_ONE;
  3478. #else
  3479. path->commands = gf_list_new();
  3480. path->points = gf_list_new();
  3481. #endif
  3482. return path;
  3483. }
  3484. break;
  3485. case LASeR_Choice_datatype:
  3486. {
  3487. LASeR_Choice *ch;
  3488. GF_SAFEALLOC(ch, LASeR_Choice)
  3489. return ch;
  3490. }
  3491. case SVG_Focus_datatype:
  3492. {
  3493. SVG_Focus *foc;
  3494. GF_SAFEALLOC(foc, SVG_Focus)
  3495. return foc;
  3496. }
  3497. case SMIL_AttributeName_datatype:
  3498. {
  3499. SMIL_AttributeName *an;
  3500. GF_SAFEALLOC(an, SMIL_AttributeName)
  3501. return an;
  3502. }
  3503. case SMIL_RepeatCount_datatype:
  3504. {
  3505. SMIL_RepeatCount *rc;
  3506. GF_SAFEALLOC(rc, SMIL_RepeatCount)
  3507. return rc;
  3508. }
  3509. case SMIL_Duration_datatype:
  3510. {
  3511. SMIL_Duration *sd;
  3512. GF_SAFEALLOC(sd, SMIL_Duration)
  3513. return sd;
  3514. }
  3515. case SMIL_AnimateValue_datatype:
  3516. {
  3517. SMIL_AnimateValue *av;
  3518. GF_SAFEALLOC(av, SMIL_AnimateValue)
  3519. return av;
  3520. }
  3521. break;
  3522. case SMIL_AnimateValues_datatype:
  3523. {
  3524. SMIL_AnimateValues *av;
  3525. GF_SAFEALLOC(av, SMIL_AnimateValues)
  3526. av->values = gf_list_new();
  3527. return av;
  3528. }
  3529. break;
  3530. case SVG_Clock_datatype:
  3531. {
  3532. SVG_Clock *ck;
  3533. GF_SAFEALLOC(ck, SVG_Clock)
  3534. return ck;
  3535. }
  3536. break;
  3537. case XMLEV_Event_datatype:
  3538. {
  3539. XMLEV_Event *e;
  3540. GF_SAFEALLOC(e, XMLEV_Event);
  3541. return e;
  3542. }
  3543. break;
  3544. case LASeR_Size_datatype:
  3545. {
  3546. LASeR_Size *s;
  3547. GF_SAFEALLOC(s, LASeR_Size);
  3548. return s;
  3549. }
  3550. break;
  3551. case 0:
  3552. {
  3553. SVG_String *string;
  3554. GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Attributes] Unspecified attribute type - defaulting to string.\n"));
  3555. GF_SAFEALLOC(string, SVG_String);
  3556. return string;
  3557. }
  3558. default:
  3559. GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Attributes] Cannot create attribute value: Type %s not supported.\n", gf_svg_attribute_type_to_string(attribute_type)));
  3560. break;
  3561. }
  3562. return NULL;
  3563. }
  3564. static char *svg_dump_color(SVG_Color *col)
  3565. {
  3566. char *res;
  3567. if (col->type == SVG_COLOR_CURRENTCOLOR) return gf_strdup("currentColor");
  3568. else if (col->type == SVG_COLOR_INHERIT) return gf_strdup("inherit");
  3569. else if (col->type !=SVG_COLOR_RGBCOLOR) {
  3570. u32 i, count;
  3571. count = sizeof(system_colors) / sizeof(struct sys_col);
  3572. for (i=0; i<count; i++) {
  3573. if (col->type == system_colors[i].type) {
  3574. return gf_strdup(system_colors[i].name);
  3575. }
  3576. }
  3577. } else {
  3578. u32 i, count = sizeof(predefined_colors) / sizeof(struct predef_col);
  3579. u32 r, g, b;
  3580. r = FIX2INT(255*col->red);
  3581. g = FIX2INT(255*col->green);
  3582. b = FIX2INT(255*col->blue);
  3583. for (i=0; i<count; i++) {
  3584. if (
  3585. (r == predefined_colors[i].r)
  3586. && (g == predefined_colors[i].g)
  3587. && (b == predefined_colors[i].b)
  3588. ) {
  3589. return gf_strdup(predefined_colors[i].name);
  3590. }
  3591. }
  3592. res = gf_malloc(sizeof(char)*8);
  3593. sprintf(res, "#%02X%02X%02X", r, g, b);
  3594. /*compress it...*/
  3595. if ( (res[1]==res[2]) && (res[3]==res[4]) && (res[5]==res[6]) )
  3596. sprintf(res, "#%c%c%c", res[1], res[3], res[5]);
  3597. return res;
  3598. }
  3599. return NULL;
  3600. }
  3601. static char *svg_dump_number(SVG_Number *l)
  3602. {
  3603. char tmp[100];
  3604. if (l->type==SVG_NUMBER_INHERIT) return gf_strdup("inherit");
  3605. else if (l->type == SVG_NUMBER_AUTO) return gf_strdup("auto");
  3606. else if (l->type == SVG_NUMBER_AUTO_REVERSE) return gf_strdup("auto-reverse");
  3607. else {
  3608. sprintf(tmp, "%g", FIX2FLT(l->value) );
  3609. if (l->type == SVG_NUMBER_PERCENTAGE) strcat(tmp, "%");
  3610. else if (l->type == SVG_NUMBER_EMS) strcat(tmp, "em");
  3611. else if (l->type == SVG_NUMBER_EXS) strcat(tmp, "ex");
  3612. else if (l->type == SVG_NUMBER_PX) strcat(tmp, "px");
  3613. else if (l->type == SVG_NUMBER_CM) strcat(tmp, "cm");
  3614. else if (l->type == SVG_NUMBER_MM) strcat(tmp, "mm");
  3615. else if (l->type == SVG_NUMBER_IN) strcat(tmp, "in");
  3616. else if (l->type == SVG_NUMBER_PT) strcat(tmp, "pt");
  3617. else if (l->type == SVG_NUMBER_PC) strcat(tmp, "pc");
  3618. return gf_strdup(tmp);
  3619. }
  3620. }
  3621. static char *svg_dump_iri(XMLRI*iri)
  3622. {
  3623. if (iri->type == XMLRI_ELEMENTID) {
  3624. const char *name;
  3625. char *res;
  3626. name = gf_node_get_name((GF_Node *)iri->target);
  3627. if (name) {
  3628. res = gf_malloc(sizeof(char)*(strlen(name)+2));
  3629. sprintf(res, "#%s", name);
  3630. } else if (iri->target) {
  3631. res = gf_malloc(sizeof(char)*32);
  3632. sprintf(res, "#N%d", gf_node_get_id((GF_Node *)iri->target) - 1);
  3633. } else {
  3634. res = gf_strdup("");
  3635. }
  3636. return res;
  3637. }
  3638. else if ((iri->type == XMLRI_STRING) && iri->string)
  3639. return gf_strdup(iri->string);
  3640. else
  3641. return gf_strdup("");
  3642. }
  3643. static char *svg_dump_idref(XMLRI*iri)
  3644. {
  3645. const char *name;
  3646. if (iri->target) {
  3647. name = gf_node_get_name((GF_Node *)iri->target);
  3648. if (name) return gf_strdup(name);
  3649. else {
  3650. char tmp[50];
  3651. sprintf(tmp, "N%d", gf_node_get_id((GF_Node *)iri->target) - 1);
  3652. return gf_strdup(tmp);
  3653. }
  3654. }
  3655. if (iri->string) return gf_strdup(iri->string);
  3656. return gf_strdup("");
  3657. }
  3658. #if USE_GF_PATH
  3659. static char *svg_dump_path(SVG_PathData *path)
  3660. {
  3661. char szT[1000];
  3662. GF_Point2D *pt, last_pt, *ct1, *ct2, *end;
  3663. u32 i, *contour;
  3664. char *res = gf_malloc(sizeof(char));
  3665. res[0] = 0;
  3666. contour = path->contours;
  3667. last_pt.x = last_pt.y = 0;
  3668. for (i=0; i<path->n_points; ) {
  3669. szT[0] = 0;
  3670. switch (path->tags[i]) {
  3671. case GF_PATH_CURVE_ON:
  3672. case GF_PATH_CLOSE:
  3673. pt = &path->points[i];
  3674. if (!i || (*contour == i-1) ) {
  3675. sprintf(szT, "M%g %g", FIX2FLT(pt->x), FIX2FLT(pt->y));
  3676. if (i) contour++;
  3677. } else if (path->tags[i]==GF_PATH_CLOSE) {
  3678. sprintf(szT, "z");
  3679. } else {
  3680. if (i && (last_pt.x==pt->x)) sprintf(szT, "V%g", FIX2FLT(pt->y));
  3681. else if (i && (last_pt.y==pt->y)) sprintf(szT, "H%g", FIX2FLT(pt->x));
  3682. else sprintf(szT, "L%g %g", FIX2FLT(pt->x), FIX2FLT(pt->y));
  3683. }
  3684. last_pt = *pt;
  3685. i++;
  3686. break;
  3687. case GF_PATH_CURVE_CONIC:
  3688. ct1 = &path->points[i];
  3689. end = &path->points[i+1];
  3690. sprintf(szT, "Q%g %g %g %g", FIX2FLT(ct1->x), FIX2FLT(ct1->y), FIX2FLT(end->x), FIX2FLT(end->y));
  3691. last_pt = *end;
  3692. if (path->tags[i+2]==GF_PATH_CLOSE) {
  3693. strcat(szT, "z");
  3694. }
  3695. i+=2;
  3696. break;
  3697. case GF_PATH_CURVE_CUBIC:
  3698. ct1 = &path->points[i];
  3699. ct2 = &path->points[i+1];
  3700. end = &path->points[i+2];
  3701. sprintf(szT, "C%g %g %g %g %g %g", FIX2FLT(ct1->x), FIX2FLT(ct1->y), FIX2FLT(ct2->x), FIX2FLT(ct2->y), FIX2FLT(end->x), FIX2FLT(end->y));
  3702. last_pt = *end;
  3703. if (path->tags[i+2]==GF_PATH_CLOSE) {
  3704. strcat(szT, "z");
  3705. }
  3706. i+=3;
  3707. break;
  3708. }
  3709. if (szT[0]) {
  3710. res = gf_realloc(res, sizeof(char)*(strlen(szT)+strlen(res)+1));
  3711. strcat(res, szT);
  3712. }
  3713. }
  3714. return res;
  3715. }
  3716. #else
  3717. static void svg_dump_point(SVG_Point *pt, char *attValue)
  3718. {
  3719. if (pt) sprintf(attValue, "%g %g ", FIX2FLT(pt->x), FIX2FLT(pt->y) );
  3720. }
  3721. static void svg_dump_path(SVG_PathData *path, char *attValue)
  3722. {
  3723. char szT[1000];
  3724. u32 i, pt_i, count;
  3725. count = gf_list_count(path->commands);
  3726. pt_i = 0;
  3727. strcpy(attValue, "");
  3728. for (i = 0; i < count; i++) {
  3729. u8 command = *(u8 *)gf_list_get(path->commands, i);
  3730. switch(command) {
  3731. case SVG_PATHCOMMAND_M:
  3732. strcat(attValue, "M");
  3733. svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
  3734. strcat(attValue, szT);
  3735. pt_i++;
  3736. break;
  3737. case SVG_PATHCOMMAND_L:
  3738. strcat(attValue, "L");
  3739. svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
  3740. strcat(attValue, szT);
  3741. pt_i++;
  3742. break;
  3743. case SVG_PATHCOMMAND_C:
  3744. strcat(attValue, "C");
  3745. svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
  3746. strcat(attValue, szT);
  3747. pt_i++;
  3748. svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
  3749. strcat(attValue, szT);
  3750. pt_i++;
  3751. svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
  3752. strcat(attValue, szT);
  3753. pt_i++;
  3754. break;
  3755. case SVG_PATHCOMMAND_S:
  3756. strcat(attValue, "S");
  3757. svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
  3758. strcat(attValue, szT);
  3759. pt_i++;
  3760. svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
  3761. strcat(attValue, szT);
  3762. pt_i++;
  3763. break;
  3764. case SVG_PATHCOMMAND_Q:
  3765. strcat(attValue, "Q");
  3766. svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
  3767. strcat(attValue, szT);
  3768. pt_i++;
  3769. svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
  3770. strcat(attValue, szT);
  3771. pt_i++;
  3772. break;
  3773. case SVG_PATHCOMMAND_T:
  3774. strcat(attValue, "T");
  3775. svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
  3776. strcat(attValue, szT);
  3777. pt_i++;
  3778. break;
  3779. case SVG_PATHCOMMAND_A:
  3780. strcat(attValue, "A");
  3781. svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
  3782. strcat(attValue, szT);
  3783. pt_i++;
  3784. strcat(attValue, "0 0 0 ");
  3785. svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT);
  3786. strcat(attValue, szT);
  3787. pt_i++;
  3788. break;
  3789. case SVG_PATHCOMMAND_Z:
  3790. strcat(attValue, "Z");
  3791. break;
  3792. default:
  3793. GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Dumping] unknown path command %d\n", command));
  3794. break;
  3795. }
  3796. }
  3797. }
  3798. #endif
  3799. static void svg_dump_access_key(XMLEV_Event *evt, char *attValue)
  3800. {
  3801. u32 i, count;
  3802. strcpy(attValue, "accessKey(");
  3803. count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid);
  3804. for (i=0; i<count; i++) {
  3805. if (evt->parameter == predefined_key_identifiers[i].key_code) {
  3806. strcat(attValue, predefined_key_identifiers[i].name);
  3807. break;
  3808. }
  3809. }
  3810. /* OLD LASeR CODE
  3811. switch (evt->parameter) {
  3812. case 0: strcat(attValue, "UP"); break;
  3813. case 1: strcat(attValue, "DOWN"); break;
  3814. case 2: strcat(attValue, "LEFT"); break;
  3815. case 3: strcat(attValue, "RIGHT"); break;
  3816. case 4: strcat(attValue, "FIRE"); break;
  3817. case 5: strcat(attValue, "NO_KEY"); break;
  3818. case 6: strcat(attValue, "ANY_KEY"); break;
  3819. case 7: strcat(attValue, "SOFT_KEY_1"); break;
  3820. case 8: strcat(attValue, "SOFT_KEY_2"); break;
  3821. case 35: strcat(attValue, "#"); break;
  3822. case 42: strcat(attValue, "*"); break;
  3823. case 48: strcat(attValue, "0"); break;
  3824. case 49: strcat(attValue, "1"); break;
  3825. case 50: strcat(attValue, "2"); break;
  3826. case 51: strcat(attValue, "3"); break;
  3827. case 52: strcat(attValue, "4"); break;
  3828. case 53: strcat(attValue, "5"); break;
  3829. case 54: strcat(attValue, "6"); break;
  3830. case 55: strcat(attValue, "7"); break;
  3831. case 56: strcat(attValue, "8"); break;
  3832. case 57: strcat(attValue, "9"); break;
  3833. */
  3834. strcat(attValue, ")");
  3835. }
  3836. static char *gf_svg_dump_matrix(GF_Matrix2D *matrix)
  3837. {
  3838. char attValue[1024];
  3839. attValue[0]=0;
  3840. /*try to do a simple decomposition...*/
  3841. if (!matrix->m[1] && !matrix->m[3]) {
  3842. if (matrix->m[2] != 0 || matrix->m[5] != 0) sprintf(attValue, "translate(%g,%g)", FIX2FLT(matrix->m[2]), FIX2FLT(matrix->m[5]) );
  3843. if ((matrix->m[0]!=FIX_ONE) || (matrix->m[4]!=FIX_ONE)) {
  3844. char szT[1024];
  3845. if ((matrix->m[0]==-FIX_ONE) && (matrix->m[4]==-FIX_ONE)) {
  3846. strcpy(szT, " rotate(180)");
  3847. } else {
  3848. sprintf(szT, " scale(%g,%g)", FIX2FLT(matrix->m[0]), FIX2FLT(matrix->m[4]) );
  3849. }
  3850. strcat(attValue, szT);
  3851. }
  3852. } else if (matrix->m[1] == - matrix->m[3]) {
  3853. Fixed angle = gf_asin(matrix->m[3]);
  3854. Fixed cos_a = gf_cos(angle);
  3855. if (ABS(cos_a)>FIX_EPSILON) {
  3856. Fixed sx, sy;
  3857. sx = gf_divfix(matrix->m[0], cos_a);
  3858. sy = gf_divfix(matrix->m[4], cos_a);
  3859. angle = gf_divfix(180*angle, GF_PI);
  3860. if ((sx==sy) && ( ABS(FIX_ONE - ABS(sx) ) < FIX_ONE/100)) {
  3861. if (matrix->m[2] != 0 || matrix->m[5] != 0)
  3862. sprintf(attValue, "translate(%g,%g) rotate(%g)", FIX2FLT(matrix->m[2]), FIX2FLT(matrix->m[5]), FIX2FLT(gf_divfix(angle*180, GF_PI) ) );
  3863. else
  3864. sprintf(attValue, "rotate(%g)", FIX2FLT(gf_divfix(angle*180, GF_PI) ) );
  3865. } else {
  3866. if (matrix->m[2] != 0 || matrix->m[5] != 0)
  3867. sprintf(attValue, "translate(%g,%g) scale(%g,%g) rotate(%g)", FIX2FLT(matrix->m[2]), FIX2FLT(matrix->m[5]), FIX2FLT(sx), FIX2FLT(sy), FIX2FLT(gf_divfix(angle*180, GF_PI) ) );
  3868. else
  3869. sprintf(attValue, "scale(%g,%g) rotate(%g)", FIX2FLT(sx), FIX2FLT(sy), FIX2FLT(gf_divfix(angle*180, GF_PI) ) );
  3870. }
  3871. } else {
  3872. Fixed a = angle;
  3873. if (a<0) a += GF_2PI;
  3874. if (matrix->m[2] != 0 || matrix->m[5] != 0)
  3875. sprintf(attValue, "translate(%g,%g) rotate(%g)", FIX2FLT(matrix->m[2]), FIX2FLT(matrix->m[5]), FIX2FLT(gf_divfix(a*180, GF_PI) ) );
  3876. else
  3877. sprintf(attValue, "rotate(%g)", FIX2FLT(gf_divfix(a*180, GF_PI) ) );
  3878. }
  3879. }
  3880. /*default*/
  3881. if (!strlen(attValue))
  3882. sprintf(attValue, "matrix(%g %g %g %g %g %g)", FIX2FLT(matrix->m[0]), FIX2FLT(matrix->m[3]), FIX2FLT(matrix->m[1]), FIX2FLT(matrix->m[4]), FIX2FLT(matrix->m[2]), FIX2FLT(matrix->m[5]) );
  3883. return gf_strdup(attValue);
  3884. }
  3885. char *gf_svg_dump_attribute(GF_Node *elt, GF_FieldInfo *info)
  3886. {
  3887. char tmp[1024];
  3888. u8 intVal;
  3889. if (!info->far_ptr) return gf_strdup("");
  3890. intVal = *(u8 *)info->far_ptr;
  3891. switch (info->fieldType) {
  3892. case SVG_Boolean_datatype:
  3893. return gf_strdup( *(SVG_Boolean *)info->far_ptr ? "true" : "false");
  3894. case SVG_Color_datatype:
  3895. return svg_dump_color((SVG_Color *)info->far_ptr);
  3896. case SVG_Paint_datatype:
  3897. {
  3898. SVG_Paint *paint = (SVG_Paint *)info->far_ptr;
  3899. if (paint->type == SVG_PAINT_NONE) return gf_strdup("none");
  3900. else if (paint->type == SVG_PAINT_INHERIT) return gf_strdup("inherit");
  3901. else if (paint->type == SVG_PAINT_URI) {
  3902. char *tmp = svg_dump_iri(&paint->iri);
  3903. char *res = gf_malloc(sizeof(char)*(strlen(tmp)+6));
  3904. sprintf(res, "url(%s)", tmp);
  3905. gf_free(tmp);
  3906. return res;
  3907. } else {
  3908. return svg_dump_color(&paint->color);
  3909. }
  3910. }
  3911. break;
  3912. /* beginning of keyword type parsing */
  3913. case SVG_FillRule_datatype:
  3914. if (intVal == SVG_FILLRULE_INHERIT) return gf_strdup("inherit");
  3915. else if (intVal == SVG_FILLRULE_NONZERO) return gf_strdup("nonzero");
  3916. else return gf_strdup("evenodd");
  3917. break;
  3918. case SVG_StrokeLineJoin_datatype:
  3919. if (intVal==SVG_STROKELINEJOIN_INHERIT) return gf_strdup("inherit");
  3920. else if (intVal==SVG_STROKELINEJOIN_MITER) return gf_strdup("miter");
  3921. else if (intVal==SVG_STROKELINEJOIN_ROUND) return gf_strdup("round");
  3922. else if (intVal==SVG_STROKELINEJOIN_BEVEL) return gf_strdup("bevel");
  3923. break;
  3924. case SVG_StrokeLineCap_datatype:
  3925. if (intVal==SVG_STROKELINECAP_INHERIT) return gf_strdup("inherit");
  3926. else if (intVal==SVG_STROKELINECAP_BUTT) return gf_strdup("butt");
  3927. else if (intVal==SVG_STROKELINECAP_ROUND) return gf_strdup("round");
  3928. else if (intVal==SVG_STROKELINECAP_SQUARE) return gf_strdup("square");
  3929. break;
  3930. case SVG_FontStyle_datatype:
  3931. if (intVal==SVG_FONTSTYLE_INHERIT) return gf_strdup("inherit");
  3932. else if (intVal==SVG_FONTSTYLE_NORMAL) return gf_strdup("normal");
  3933. else if (intVal==SVG_FONTSTYLE_ITALIC) return gf_strdup("italic");
  3934. else if (intVal==SVG_FONTSTYLE_OBLIQUE) return gf_strdup("oblique");
  3935. break;
  3936. case SVG_FontWeight_datatype:
  3937. if (intVal==SVG_FONTWEIGHT_INHERIT) return gf_strdup("inherit");
  3938. else if (intVal==SVG_FONTWEIGHT_NORMAL) return gf_strdup("normal");
  3939. else if (intVal==SVG_FONTWEIGHT_BOLD) return gf_strdup("bold");
  3940. else if (intVal==SVG_FONTWEIGHT_BOLDER) return gf_strdup("bolder");
  3941. else if (intVal==SVG_FONTWEIGHT_LIGHTER) return gf_strdup("lighter");
  3942. else if (intVal==SVG_FONTWEIGHT_100) return gf_strdup("100");
  3943. else if (intVal==SVG_FONTWEIGHT_200) return gf_strdup("200");
  3944. else if (intVal==SVG_FONTWEIGHT_300) return gf_strdup("300");
  3945. else if (intVal==SVG_FONTWEIGHT_400) return gf_strdup("400");
  3946. else if (intVal==SVG_FONTWEIGHT_500) return gf_strdup("500");
  3947. else if (intVal==SVG_FONTWEIGHT_600) return gf_strdup("600");
  3948. else if (intVal==SVG_FONTWEIGHT_700) return gf_strdup("700");
  3949. else if (intVal==SVG_FONTWEIGHT_800) return gf_strdup("800");
  3950. else if (intVal==SVG_FONTWEIGHT_900) return gf_strdup("900");
  3951. break;
  3952. case SVG_FontVariant_datatype:
  3953. if (intVal==SVG_FONTVARIANT_INHERIT) return gf_strdup("inherit");
  3954. else if (intVal==SVG_FONTVARIANT_NORMAL) return gf_strdup("normal");
  3955. else if (intVal==SVG_FONTVARIANT_SMALLCAPS) return gf_strdup("small-caps");
  3956. break;
  3957. case SVG_TextAnchor_datatype:
  3958. if (intVal==SVG_TEXTANCHOR_INHERIT) return gf_strdup("inherit");
  3959. else if (intVal==SVG_TEXTANCHOR_START) return gf_strdup("start");
  3960. else if (intVal==SVG_TEXTANCHOR_MIDDLE) return gf_strdup("middle");
  3961. else if (intVal==SVG_TEXTANCHOR_END) return gf_strdup("end");
  3962. break;
  3963. case SVG_Display_datatype:
  3964. if (intVal==SVG_DISPLAY_INHERIT) return gf_strdup("inherit");
  3965. else if (intVal==SVG_DISPLAY_NONE) return gf_strdup("none");
  3966. else if (intVal==SVG_DISPLAY_INLINE) return gf_strdup("inline");
  3967. else if (intVal==SVG_DISPLAY_BLOCK) return gf_strdup("block");
  3968. else if (intVal==SVG_DISPLAY_LIST_ITEM) return gf_strdup("list-item");
  3969. else if (intVal==SVG_DISPLAY_RUN_IN) return gf_strdup("run-in");
  3970. else if (intVal==SVG_DISPLAY_COMPACT) return gf_strdup("compact");
  3971. else if (intVal==SVG_DISPLAY_MARKER) return gf_strdup("marker");
  3972. else if (intVal==SVG_DISPLAY_TABLE) return gf_strdup("table");
  3973. else if (intVal==SVG_DISPLAY_INLINE_TABLE) return gf_strdup("inline-table");
  3974. else if (intVal==SVG_DISPLAY_TABLE_ROW_GROUP) return gf_strdup("table-row-group");
  3975. else if (intVal==SVG_DISPLAY_TABLE_HEADER_GROUP) return gf_strdup("table-header-group");
  3976. else if (intVal==SVG_DISPLAY_TABLE_FOOTER_GROUP) return gf_strdup("table-footer-group");
  3977. else if (intVal==SVG_DISPLAY_TABLE_ROW) return gf_strdup("table-row");
  3978. else if (intVal==SVG_DISPLAY_TABLE_COLUMN_GROUP) return gf_strdup("table-column-group");
  3979. else if (intVal==SVG_DISPLAY_TABLE_COLUMN) return gf_strdup("table-column");
  3980. else if (intVal==SVG_DISPLAY_TABLE_CELL) return gf_strdup("table-cell");
  3981. else if (intVal==SVG_DISPLAY_TABLE_CAPTION) return gf_strdup("table-caption");
  3982. break;
  3983. case SVG_Visibility_datatype:
  3984. if (intVal==SVG_VISIBILITY_INHERIT) return gf_strdup("inherit");
  3985. else if (intVal==SVG_VISIBILITY_VISIBLE) return gf_strdup("visible");
  3986. else if (intVal==SVG_VISIBILITY_HIDDEN) return gf_strdup("hidden");
  3987. else if (intVal==SVG_VISIBILITY_COLLAPSE) return gf_strdup("collapse");
  3988. break;
  3989. case SVG_Overflow_datatype:
  3990. if (intVal==SVG_OVERFLOW_INHERIT) return gf_strdup("inherit");
  3991. else if (intVal==SVG_OVERFLOW_VISIBLE) return gf_strdup("visible");
  3992. else if (intVal==SVG_OVERFLOW_HIDDEN) return gf_strdup("hidden");
  3993. else if (intVal==SVG_OVERFLOW_SCROLL) return gf_strdup("scroll");
  3994. else if (intVal==SVG_OVERFLOW_AUTO) return gf_strdup("auto");
  3995. break;
  3996. case SVG_ZoomAndPan_datatype:
  3997. if (intVal==SVG_ZOOMANDPAN_DISABLE) return gf_strdup("disable");
  3998. else return gf_strdup("magnify");
  3999. break;
  4000. case SVG_DisplayAlign_datatype:
  4001. if (intVal==SVG_DISPLAYALIGN_INHERIT) return gf_strdup("inherit");
  4002. else if (intVal==SVG_DISPLAYALIGN_AUTO) return gf_strdup("auto");
  4003. else if (intVal==SVG_DISPLAYALIGN_BEFORE) return gf_strdup("before");
  4004. else if (intVal==SVG_DISPLAYALIGN_CENTER) return gf_strdup("center");
  4005. else if (intVal==SVG_DISPLAYALIGN_AFTER) return gf_strdup("after");
  4006. break;
  4007. case SVG_TextAlign_datatype:
  4008. if (intVal==SVG_TEXTALIGN_INHERIT) return gf_strdup("inherit");
  4009. else if (intVal==SVG_TEXTALIGN_START) return gf_strdup("start");
  4010. else if (intVal==SVG_TEXTALIGN_CENTER) return gf_strdup("center");
  4011. else if (intVal==SVG_TEXTALIGN_END) return gf_strdup("end");
  4012. break;
  4013. case SVG_PointerEvents_datatype:
  4014. if (intVal==SVG_POINTEREVENTS_INHERIT) return gf_strdup("inherit");
  4015. else if (intVal==SVG_POINTEREVENTS_VISIBLEPAINTED) return gf_strdup("visiblePainted");
  4016. else if (intVal==SVG_POINTEREVENTS_VISIBLEFILL) return gf_strdup("visibleFill");
  4017. else if (intVal==SVG_POINTEREVENTS_VISIBLESTROKE) return gf_strdup("visibleStroke");
  4018. else if (intVal==SVG_POINTEREVENTS_VISIBLE) return gf_strdup("visible");
  4019. else if (intVal==SVG_POINTEREVENTS_PAINTED) return gf_strdup("painted");
  4020. else if (intVal==SVG_POINTEREVENTS_FILL) return gf_strdup("fill");
  4021. else if (intVal==SVG_POINTEREVENTS_STROKE) return gf_strdup("stroke");
  4022. else if (intVal==SVG_POINTEREVENTS_ALL) return gf_strdup("all");
  4023. else if (intVal==SVG_POINTEREVENTS_NONE) return gf_strdup("none");
  4024. else if (intVal==SVG_POINTEREVENTS_BOUNDINGBOX) return gf_strdup("boundingBox");
  4025. break;
  4026. case SVG_RenderingHint_datatype:
  4027. if (intVal==SVG_RENDERINGHINT_INHERIT) return gf_strdup("inherit");
  4028. else if (intVal==SVG_RENDERINGHINT_AUTO) return gf_strdup("auto");
  4029. else if (intVal==SVG_RENDERINGHINT_OPTIMIZEQUALITY) return gf_strdup("optimizeQuality");
  4030. else if (intVal==SVG_RENDERINGHINT_OPTIMIZESPEED) return gf_strdup("optimizeSpeed");
  4031. else if (intVal==SVG_RENDERINGHINT_OPTIMIZELEGIBILITY) return gf_strdup("optimizeLegibility");
  4032. else if (intVal==SVG_RENDERINGHINT_CRISPEDGES) return gf_strdup("crispEdges");
  4033. else if (intVal==SVG_RENDERINGHINT_GEOMETRICPRECISION) return gf_strdup("geometricPrecision");
  4034. break;
  4035. case SVG_VectorEffect_datatype:
  4036. if (intVal==SVG_VECTOREFFECT_INHERIT) return gf_strdup("inherit");
  4037. else if (intVal==SVG_VECTOREFFECT_NONE) return gf_strdup("none");
  4038. else if (intVal==SVG_VECTOREFFECT_NONSCALINGSTROKE) return gf_strdup("non-scaling-stroke");
  4039. break;
  4040. case SVG_PlaybackOrder_datatype:
  4041. if (intVal== SVG_PLAYBACKORDER_FORWARDONLY) return gf_strdup("forwardOnly");
  4042. else if (intVal== SVG_PLAYBACKORDER_ALL) return gf_strdup("all");
  4043. break;
  4044. case SVG_TimelineBegin_datatype:
  4045. if (intVal== SVG_TIMELINEBEGIN_ONSTART) return gf_strdup("onStart");
  4046. else if (intVal== SVG_TIMELINEBEGIN_ONLOAD) return gf_strdup("onLoad");
  4047. break;
  4048. case XML_Space_datatype:
  4049. if (intVal==XML_SPACE_DEFAULT) return gf_strdup("default");
  4050. else if (intVal==XML_SPACE_PRESERVE) return gf_strdup("preserve");
  4051. break;
  4052. case XMLEV_Propagate_datatype:
  4053. if (intVal==XMLEVENT_PROPAGATE_CONTINUE) return gf_strdup("continue");
  4054. else if (intVal==XMLEVENT_PROPAGATE_STOP) return gf_strdup("stop");
  4055. break;
  4056. case XMLEV_DefaultAction_datatype:
  4057. if (intVal==XMLEVENT_DEFAULTACTION_CANCEL) return gf_strdup("cancel");
  4058. else if (intVal==XMLEVENT_DEFAULTACTION_PERFORM) return gf_strdup("perform");
  4059. break;
  4060. case XMLEV_Phase_datatype:
  4061. if (intVal==XMLEVENT_PHASE_DEFAULT) return gf_strdup("default");
  4062. else if (intVal==XMLEVENT_PHASE_CAPTURE) return gf_strdup("capture");
  4063. break;
  4064. case SMIL_SyncBehavior_datatype:
  4065. if (intVal==SMIL_SYNCBEHAVIOR_INHERIT) return gf_strdup("inherit");
  4066. else if (intVal==SMIL_SYNCBEHAVIOR_DEFAULT) return gf_strdup("default");
  4067. else if (intVal==SMIL_SYNCBEHAVIOR_LOCKED) return gf_strdup("locked");
  4068. else if (intVal==SMIL_SYNCBEHAVIOR_CANSLIP) return gf_strdup("canSlip");
  4069. else if (intVal==SMIL_SYNCBEHAVIOR_INDEPENDENT) return gf_strdup("independent");
  4070. break;
  4071. case SMIL_SyncTolerance_datatype:
  4072. if (((SMIL_SyncTolerance*)info->far_ptr)->type==SMIL_SYNCTOLERANCE_INHERIT) return gf_strdup("inherit");
  4073. else if (((SMIL_SyncTolerance*)info->far_ptr)->type==SMIL_SYNCTOLERANCE_DEFAULT) return gf_strdup("default");
  4074. else if (((SMIL_SyncTolerance*)info->far_ptr)->type==SMIL_SYNCBEHAVIOR_LOCKED) {
  4075. sprintf(tmp, "%g", ((SMIL_SyncTolerance*)info->far_ptr)->value);
  4076. return gf_strdup(tmp);
  4077. }
  4078. break;
  4079. case SMIL_AttributeType_datatype:
  4080. if (intVal==SMIL_ATTRIBUTETYPE_AUTO) return gf_strdup("auto");
  4081. else if (intVal==SMIL_ATTRIBUTETYPE_XML) return gf_strdup("XML");
  4082. else if (intVal==SMIL_ATTRIBUTETYPE_CSS) return gf_strdup("CSS");
  4083. break;
  4084. case SMIL_CalcMode_datatype:
  4085. if (intVal==SMIL_CALCMODE_DISCRETE) return gf_strdup("discrete");
  4086. else if (intVal==SMIL_CALCMODE_LINEAR) return gf_strdup("linear");
  4087. else if (intVal==SMIL_CALCMODE_PACED) return gf_strdup("paced");
  4088. else if (intVal==SMIL_CALCMODE_SPLINE) return gf_strdup("spline");
  4089. break;
  4090. case SMIL_Additive_datatype:
  4091. if (intVal==SMIL_ADDITIVE_REPLACE) return gf_strdup("replace");
  4092. else if (intVal==SMIL_ADDITIVE_SUM) return gf_strdup("sum");
  4093. break;
  4094. case SMIL_Accumulate_datatype:
  4095. if (intVal==SMIL_ACCUMULATE_NONE) return gf_strdup("none");
  4096. else if (intVal==SMIL_ACCUMULATE_SUM) return gf_strdup("sum");
  4097. break;
  4098. case SMIL_Restart_datatype:
  4099. if (intVal==SMIL_RESTART_ALWAYS) return gf_strdup("always");
  4100. else if (intVal==SMIL_RESTART_WHENNOTACTIVE) return gf_strdup("whenNotActive");
  4101. else if (intVal==SMIL_RESTART_NEVER) return gf_strdup("never");
  4102. break;
  4103. case SMIL_Fill_datatype:
  4104. if (intVal==SMIL_FILL_FREEZE) return gf_strdup("freeze");
  4105. else if (intVal==SMIL_FILL_REMOVE) return gf_strdup("remove");
  4106. break;
  4107. case SVG_GradientUnit_datatype:
  4108. if (intVal==SVG_GRADIENTUNITS_USER) return gf_strdup("userSpaceOnUse");
  4109. else if (intVal==SVG_GRADIENTUNITS_OBJECT) return gf_strdup("objectBoundingBox");
  4110. break;
  4111. case SVG_InitialVisibility_datatype:
  4112. if (intVal==SVG_INITIALVISIBILTY_WHENSTARTED) return gf_strdup("whenStarted");
  4113. else if (intVal==SVG_INITIALVISIBILTY_ALWAYS) return gf_strdup("always");
  4114. break;
  4115. case SVG_FocusHighlight_datatype:
  4116. if (intVal==SVG_FOCUSHIGHLIGHT_AUTO) return gf_strdup("auto");
  4117. else if (intVal==SVG_FOCUSHIGHLIGHT_NONE) return gf_strdup("none");
  4118. break;
  4119. case SVG_Overlay_datatype:
  4120. if (intVal==SVG_OVERLAY_NONE) return gf_strdup("none");
  4121. else if (intVal==SVG_OVERLAY_TOP) return gf_strdup("top");
  4122. break;
  4123. case SVG_TransformBehavior_datatype:
  4124. if (intVal==SVG_TRANSFORMBEHAVIOR_GEOMETRIC) return gf_strdup("geometric");
  4125. else if (intVal==SVG_TRANSFORMBEHAVIOR_PINNED) return gf_strdup("pinned");
  4126. else if (intVal==SVG_TRANSFORMBEHAVIOR_PINNED90) return gf_strdup("pinned90");
  4127. else if (intVal==SVG_TRANSFORMBEHAVIOR_PINNED180) return gf_strdup("pinned180");
  4128. else if (intVal==SVG_TRANSFORMBEHAVIOR_PINNED270) return gf_strdup("pinned270");
  4129. break;
  4130. case SVG_SpreadMethod_datatype:
  4131. if (intVal==SVG_SPREAD_REFLECT) return gf_strdup("reflect");
  4132. else if (intVal==SVG_SPREAD_REPEAT) return gf_strdup("repeat");
  4133. else return gf_strdup("pad");
  4134. break;
  4135. case SVG_Filter_TransferType_datatype:
  4136. if (intVal==SVG_FILTER_TRANSFER_TABLE) return gf_strdup("table");
  4137. else if (intVal==SVG_FILTER_TRANSFER_DISCRETE) return gf_strdup("discrete");
  4138. else if (intVal==SVG_FILTER_TRANSFER_LINEAR) return gf_strdup("linear");
  4139. else if (intVal==SVG_FILTER_TRANSFER_GAMMA) return gf_strdup("gamma");
  4140. else return gf_strdup("identity");
  4141. break;
  4142. case LASeR_Choice_datatype:
  4143. if (intVal==LASeR_CHOICE_ALL) return gf_strdup("all");
  4144. else if (intVal==LASeR_CHOICE_NONE) return gf_strdup("none");
  4145. else if (intVal==LASeR_CHOICE_N) {
  4146. sprintf(tmp, "%d", ((LASeR_Choice *)info->far_ptr)->choice_index);
  4147. return gf_strdup(tmp);
  4148. }
  4149. break;
  4150. case LASeR_Size_datatype:
  4151. sprintf(tmp, "%g %g", FIX2FLT(((LASeR_Size *)info->far_ptr)->width), FIX2FLT(((LASeR_Size *)info->far_ptr)->height));
  4152. return gf_strdup(tmp);
  4153. /* end of keyword type parsing */
  4154. /* inheritable floats */
  4155. case SVG_FontSize_datatype:
  4156. case SVG_Length_datatype:
  4157. case SVG_Coordinate_datatype:
  4158. case SVG_Rotate_datatype:
  4159. case SVG_Number_datatype:
  4160. #if DUMP_COORDINATES
  4161. return svg_dump_number((SVG_Number *)info->far_ptr);
  4162. #endif
  4163. case XMLRI_datatype:
  4164. return svg_dump_iri((XMLRI*)info->far_ptr);
  4165. case XML_IDREF_datatype:
  4166. return svg_dump_idref((XMLRI*)info->far_ptr);
  4167. case XMLRI_List_datatype:
  4168. {
  4169. GF_List *l = *(GF_List **)info->far_ptr;
  4170. u32 i, count = gf_list_count(l);
  4171. char *attVal = gf_malloc(sizeof(char));
  4172. attVal[0] = 0;
  4173. for (i=0; i<count; i++) {
  4174. u32 len;
  4175. char *szT;
  4176. XMLRI *iri = (XMLRI *)gf_list_get(l, i);
  4177. szT = svg_dump_iri(iri);
  4178. len = (u32) strlen(szT);
  4179. if (len) {
  4180. attVal = gf_realloc(attVal, sizeof(char)*(len+strlen(attVal)+ (i ? 2 : 1) ));
  4181. if (i) strcat(attVal, " ");
  4182. strcat(attVal, szT);
  4183. }
  4184. gf_free(szT);
  4185. }
  4186. return attVal;
  4187. }
  4188. break;
  4189. case SVG_PathData_datatype:
  4190. #if DUMP_COORDINATES
  4191. return svg_dump_path((SVG_PathData *)info->far_ptr);
  4192. #endif
  4193. break;
  4194. case SVG_Points_datatype:
  4195. {
  4196. #if DUMP_COORDINATES
  4197. GF_List *l = *(GF_List **) info->far_ptr;
  4198. u32 i = 0;
  4199. u32 count = gf_list_count(l);
  4200. char *attVal = gf_malloc(sizeof(char));
  4201. attVal[0] = 0;
  4202. for (i=0; i<count; i++) {
  4203. char szT[200];
  4204. SVG_Point *p = (SVG_Point *)gf_list_get(l, i);
  4205. sprintf(szT, "%g %g", FIX2FLT(p->x), FIX2FLT(p->y));
  4206. attVal = gf_realloc(attVal, sizeof(char)*(strlen(szT)+strlen(attVal)+ (i ? 2 : 1) ));
  4207. if (i) strcat(attVal, " ");
  4208. strcat(attVal, szT);
  4209. }
  4210. return attVal;
  4211. #endif
  4212. }
  4213. break;
  4214. case SMIL_KeyTimes_datatype:
  4215. case SMIL_KeyPoints_datatype:
  4216. case SMIL_KeySplines_datatype:
  4217. {
  4218. GF_List *l = *(GF_List **) info->far_ptr;
  4219. u32 i = 0;
  4220. u32 count = gf_list_count(l);
  4221. char *attVal = gf_malloc(sizeof(char));
  4222. attVal[0] = 0;
  4223. for (i=0; i<count; i++) {
  4224. char szT[1000];
  4225. Fixed *p = (Fixed *)gf_list_get(l, i);
  4226. sprintf(szT, "%g", FIX2FLT(*p));
  4227. attVal = gf_realloc(attVal, sizeof(char)*(strlen(szT)+strlen(attVal)+ (i ? 2 : 1) ));
  4228. if (i) strcat(attVal, " ");
  4229. strcat(attVal, szT);
  4230. }
  4231. return attVal;
  4232. }
  4233. break;
  4234. case SVG_Coordinates_datatype:
  4235. {
  4236. #if DUMP_COORDINATES
  4237. GF_List *l = *(GF_List **) info->far_ptr;
  4238. u32 i = 0;
  4239. u32 count = gf_list_count(l);
  4240. char *attVal = gf_malloc(sizeof(char));
  4241. attVal[0]=0;
  4242. for (i=0; i<count; i++) {
  4243. char *szT;
  4244. SVG_Coordinate *p = (SVG_Coordinate *)gf_list_get(l, i);
  4245. szT = svg_dump_number((SVG_Length *)p);
  4246. attVal = gf_realloc(attVal, sizeof(char)*(strlen(szT)+strlen(attVal)+ (i ? 2 : 1) ));
  4247. if (i) strcat(attVal, " ");
  4248. strcat(attVal, szT);
  4249. gf_free(szT);
  4250. }
  4251. return attVal;
  4252. #endif
  4253. }
  4254. break;
  4255. case SVG_ViewBox_datatype:
  4256. {
  4257. SVG_ViewBox *v = (SVG_ViewBox *)info->far_ptr;
  4258. if (v->is_set) {
  4259. sprintf(tmp, "%g %g %g %g", FIX2FLT(v->x), FIX2FLT(v->y), FIX2FLT(v->width), FIX2FLT(v->height) );
  4260. return gf_strdup(tmp);
  4261. } else
  4262. return gf_strdup("none");
  4263. }
  4264. break;
  4265. case SVG_StrokeDashArray_datatype:
  4266. {
  4267. SVG_StrokeDashArray *p = (SVG_StrokeDashArray *)info->far_ptr;
  4268. if (p->type==SVG_STROKEDASHARRAY_NONE) return gf_strdup("none");
  4269. else if (p->type==SVG_STROKEDASHARRAY_INHERIT) return gf_strdup("inherit");
  4270. else if (p->type==SVG_STROKEDASHARRAY_ARRAY) {
  4271. u32 i = 0;
  4272. char *attVal = gf_malloc(sizeof(char));
  4273. attVal[0] = 0;
  4274. for (i=0; i<p->array.count; i++) {
  4275. char *szT;
  4276. SVG_Length l;
  4277. l.type = p->array.units[i];
  4278. l.value = p->array.vals[i];
  4279. szT = svg_dump_number(&l);
  4280. attVal = gf_realloc(attVal, sizeof(char)*(strlen(szT)+strlen(attVal)+ (i ? 2 : 1) ));
  4281. if (i) strcat(attVal, " ");
  4282. strcat(attVal, szT);
  4283. }
  4284. return attVal;
  4285. }
  4286. }
  4287. break;
  4288. case SVG_FontFamily_datatype:
  4289. {
  4290. SVG_FontFamily *f = (SVG_FontFamily *)info->far_ptr;
  4291. return gf_strdup( (f->type==SVG_FONTFAMILY_INHERIT) ? "inherit" : (const char *) f->value);
  4292. }
  4293. case SVG_PreserveAspectRatio_datatype:
  4294. {
  4295. SVG_PreserveAspectRatio *par = (SVG_PreserveAspectRatio *)info->far_ptr;
  4296. tmp[0] = 0;
  4297. if (par->defer) strcat(tmp, "defer ");
  4298. if (par->align == SVG_PRESERVEASPECTRATIO_NONE) strcat(tmp, "none");
  4299. else if (par->align == SVG_PRESERVEASPECTRATIO_XMINYMIN) strcat(tmp, "xMinYMin");
  4300. else if (par->align == SVG_PRESERVEASPECTRATIO_XMIDYMIN) strcat(tmp, "xMidYMin");
  4301. else if (par->align == SVG_PRESERVEASPECTRATIO_XMAXYMIN) strcat(tmp, "xMaxYMin");
  4302. else if (par->align == SVG_PRESERVEASPECTRATIO_XMINYMID) strcat(tmp, "xMinYMid");
  4303. else if (par->align == SVG_PRESERVEASPECTRATIO_XMIDYMID) strcat(tmp, "xMidYMid");
  4304. else if (par->align == SVG_PRESERVEASPECTRATIO_XMAXYMID) strcat(tmp, "xMaxYMid");
  4305. else if (par->align == SVG_PRESERVEASPECTRATIO_XMINYMAX) strcat(tmp, "xMinYMax");
  4306. else if (par->align == SVG_PRESERVEASPECTRATIO_XMIDYMAX) strcat(tmp, "xMidYMax");
  4307. else if (par->align == SVG_PRESERVEASPECTRATIO_XMAXYMAX) strcat(tmp, "xMaxYMax");
  4308. if (par->meetOrSlice== SVG_MEETORSLICE_SLICE) strcat(tmp, " slice");
  4309. return gf_strdup(tmp);
  4310. }
  4311. case SVG_Clock_datatype:
  4312. sprintf(tmp, "%g", * (SVG_Clock *)info->far_ptr );
  4313. return gf_strdup(tmp);
  4314. case SVG_ID_datatype:
  4315. case SVG_LanguageID_datatype:
  4316. case SVG_GradientOffset_datatype:
  4317. case DOM_String_datatype:
  4318. case SVG_ContentType_datatype:
  4319. if (*(SVG_String *)info->far_ptr)
  4320. return gf_strdup( *(SVG_String *)info->far_ptr );
  4321. break;
  4322. case SVG_Focus_datatype:
  4323. {
  4324. SVG_Focus *foc = (SVG_Focus *)info->far_ptr;
  4325. if (foc->type==SVG_FOCUS_SELF) return gf_strdup("self");
  4326. else if (foc->type==SVG_FOCUS_AUTO) return gf_strdup("auto");
  4327. else {
  4328. sprintf(tmp, "#%s", foc->target.string);
  4329. return gf_strdup(tmp);
  4330. }
  4331. }
  4332. break;
  4333. case SVG_Focusable_datatype:
  4334. {
  4335. SVG_Focusable *f = (SVG_Focusable *)info->far_ptr;
  4336. if (*f == SVG_FOCUSABLE_TRUE) return gf_strdup("true");
  4337. else if (*f == SVG_FOCUSABLE_FALSE) return gf_strdup("false");
  4338. else return gf_strdup("auto");
  4339. }
  4340. case DOM_StringList_datatype:
  4341. {
  4342. GF_List *l1 = *(GF_List **) info->far_ptr;
  4343. u32 i = 0;
  4344. u32 count = gf_list_count(l1);
  4345. char *attVal = gf_malloc(sizeof(char));
  4346. attVal[0] = 0;
  4347. for (i=0; i<count; i++) {
  4348. char *p1 = (char *)gf_list_get(l1, i);
  4349. attVal = gf_realloc(attVal, sizeof(char)*(strlen(p1)+strlen(attVal)+ (i ? 2 : 1) ));
  4350. if (i) strcat(attVal, " ");
  4351. strcat(attVal, p1);
  4352. }
  4353. return attVal;
  4354. }
  4355. case SVG_Numbers_datatype:
  4356. {
  4357. #if DUMP_COORDINATES
  4358. GF_List *l1 = *(GF_List **) info->far_ptr;
  4359. u32 i = 0;
  4360. u32 count = gf_list_count(l1);
  4361. char *attVal = gf_malloc(sizeof(char));
  4362. attVal[0]=0;
  4363. for (i=0; i<count; i++) {
  4364. char *szT;
  4365. SVG_Number *p = (SVG_Number *)gf_list_get(l1, i);
  4366. szT = svg_dump_number(p);
  4367. attVal = gf_realloc(attVal, sizeof(char)*(strlen(szT)+strlen(attVal)+ (i ? 2 : 1) ));
  4368. if (i) strcat(attVal, " ");
  4369. strcat(attVal, szT);
  4370. gf_free(szT);
  4371. }
  4372. return attVal;
  4373. #endif
  4374. }
  4375. break;
  4376. case SVG_Motion_datatype:
  4377. {
  4378. #if DUMP_COORDINATES
  4379. GF_Matrix2D *m = (GF_Matrix2D *)info->far_ptr;
  4380. sprintf(tmp, "%g %g", FIX2FLT(m->m[2]), FIX2FLT(m->m[5]));
  4381. return gf_strdup(tmp);
  4382. #endif
  4383. }
  4384. break;
  4385. case SVG_Transform_datatype:
  4386. {
  4387. SVG_Transform *t= (SVG_Transform *)info->far_ptr;
  4388. if (t->is_ref) {
  4389. sprintf(tmp, "ref(svg,%g,%g)", FIX2FLT(t->mat.m[2]), FIX2FLT(t->mat.m[5]) );
  4390. return gf_strdup(tmp);
  4391. } else {
  4392. return gf_svg_dump_matrix(&t->mat);
  4393. }
  4394. }
  4395. break;
  4396. case SVG_Transform_Translate_datatype:
  4397. {
  4398. SVG_Point *pt = (SVG_Point *)info->far_ptr;
  4399. #if DUMP_COORDINATES
  4400. sprintf(tmp, "%g %g", FIX2FLT(pt->x), FIX2FLT(pt->y) );
  4401. return gf_strdup(tmp);
  4402. #endif
  4403. }
  4404. break;
  4405. case SVG_Transform_Scale_datatype:
  4406. {
  4407. SVG_Point *pt = (SVG_Point *)info->far_ptr;
  4408. #if DUMP_COORDINATES
  4409. if (pt->x == pt->y) {
  4410. sprintf(tmp, "%g", FIX2FLT(pt->x));
  4411. } else {
  4412. sprintf(tmp, "%g %g", FIX2FLT(pt->x), FIX2FLT(pt->y) );
  4413. }
  4414. return gf_strdup(tmp);
  4415. #endif
  4416. }
  4417. break;
  4418. case SVG_Transform_SkewX_datatype:
  4419. case SVG_Transform_SkewY_datatype:
  4420. {
  4421. Fixed *f = (Fixed *)info->far_ptr;
  4422. #if DUMP_COORDINATES
  4423. sprintf(tmp, "%g", FIX2FLT( 180 * gf_divfix(*f, GF_PI) ));
  4424. return gf_strdup(tmp);
  4425. #endif
  4426. }
  4427. break;
  4428. case SVG_Transform_Rotate_datatype:
  4429. {
  4430. SVG_Point_Angle *pt = (SVG_Point_Angle *)info->far_ptr;
  4431. #if DUMP_COORDINATES
  4432. if (pt->x || pt->y) {
  4433. sprintf(tmp, "%g %g %g", FIX2FLT( 180 * gf_divfix(pt->angle, GF_PI) ), FIX2FLT(pt->x), FIX2FLT(pt->y) );
  4434. } else {
  4435. sprintf(tmp, "%g", FIX2FLT(gf_divfix(180 * pt->angle, GF_PI) ));
  4436. }
  4437. return gf_strdup(tmp);
  4438. #endif
  4439. }
  4440. break;
  4441. case SMIL_AttributeName_datatype:
  4442. {
  4443. SMIL_AttributeName *att_name = (SMIL_AttributeName *) info->far_ptr;
  4444. if (att_name->name)
  4445. return gf_strdup(att_name->name);
  4446. if (att_name->tag)
  4447. return gf_strdup( gf_svg_get_attribute_name(elt, att_name->tag) );
  4448. }
  4449. break;
  4450. case SMIL_Times_datatype:
  4451. {
  4452. u32 i, count;
  4453. GF_Node *par = gf_node_get_parent((GF_Node *)elt, 0);
  4454. GF_List *l = *(GF_List **) info->far_ptr;
  4455. char *attVal = gf_malloc(sizeof(char));
  4456. attVal[0] = 0;
  4457. count = gf_list_count(l);
  4458. for (i=0; i<count; i++) {
  4459. char szBuf[1000];
  4460. SMIL_Time *t = (SMIL_Time *)gf_list_get(l, i);
  4461. szBuf[0] = 0;
  4462. if (t->type == GF_SMIL_TIME_CLOCK) {
  4463. sprintf(szBuf, "%gs", t->clock);
  4464. } else if (t->type==GF_SMIL_TIME_INDEFINITE) {
  4465. strcpy(szBuf, "indefinite");
  4466. } else if (t->type==GF_SMIL_TIME_WALLCLOCK) {
  4467. u32 h, m, s;
  4468. /*TODO - day month and year*/
  4469. h = (u32) t->clock * 3600;
  4470. m = (u32) (t->clock * 60 - 60*h);
  4471. s = (u32) (t->clock - 3600*h - 60*m);
  4472. sprintf(szBuf, "wallclock(%d:%d:%d)", h, m, s);
  4473. }
  4474. else if (t->type==GF_SMIL_TIME_EVENT) {
  4475. if (t->event.type == GF_EVENT_KEYDOWN) {
  4476. svg_dump_access_key(&t->event, szBuf);
  4477. } else {
  4478. if (t->element_id) {
  4479. strcpy(szBuf, t->element_id);
  4480. strcat(szBuf, ".");
  4481. } else if (t->element && (t->element!=par) && gf_node_get_id(t->element) ) {
  4482. const char *name = gf_node_get_name(t->element);
  4483. if (name) {
  4484. strcpy(szBuf, name);
  4485. } else {
  4486. sprintf(szBuf, "N%d", gf_node_get_id(t->element)-1 );
  4487. }
  4488. strcat(szBuf, ".");
  4489. }
  4490. strcat(szBuf, gf_dom_event_get_name(t->event.type));
  4491. }
  4492. if (t->clock) {
  4493. char szCk[40];
  4494. sprintf(szCk, "+%gs", t->clock);
  4495. strcat(szBuf, szCk);
  4496. }
  4497. }
  4498. if (szBuf[0]) {
  4499. attVal = gf_realloc(attVal, sizeof(char)*(strlen(attVal)+strlen(szBuf)+ (i ? 2 : 1) ));
  4500. if ( strlen(attVal) ) strcat(attVal, ";");
  4501. strcat(attVal, szBuf);
  4502. }
  4503. }
  4504. return attVal;
  4505. }
  4506. break;
  4507. case SMIL_Duration_datatype:
  4508. {
  4509. SMIL_Duration *dur = (SMIL_Duration *)info->far_ptr;
  4510. if (dur->type == SMIL_DURATION_INDEFINITE) return gf_strdup("indefinite");
  4511. else if (dur->type == SMIL_DURATION_MEDIA) return gf_strdup("media");
  4512. else if (dur->type == SMIL_DURATION_DEFINED) {
  4513. sprintf(tmp, "%gs", dur->clock_value);
  4514. return gf_strdup(tmp);
  4515. } else {
  4516. GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Dumping] smil duration not assigned\n"));
  4517. }
  4518. }
  4519. break;
  4520. case SMIL_RepeatCount_datatype:
  4521. {
  4522. SMIL_RepeatCount *rep = (SMIL_RepeatCount *)info->far_ptr;
  4523. if (rep->type == SMIL_REPEATCOUNT_INDEFINITE) return gf_strdup("indefinite");
  4524. else if (rep->type == SMIL_REPEATCOUNT_DEFINED) {
  4525. sprintf(tmp, "%g", FIX2FLT(rep->count) );
  4526. return gf_strdup(tmp);
  4527. }
  4528. else {
  4529. GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Dumping] smil repeat count not assigned\n"));
  4530. }
  4531. }
  4532. break;
  4533. case SVG_TransformType_datatype:
  4534. {
  4535. SVG_TransformType tr = *(SVG_TransformType *)info->far_ptr;
  4536. if (tr == SVG_TRANSFORM_MATRIX) return gf_strdup("matrix");
  4537. else if (tr == SVG_TRANSFORM_SCALE) return gf_strdup("scale");
  4538. else if (tr == SVG_TRANSFORM_ROTATE) return gf_strdup("rotate");
  4539. else if (tr == SVG_TRANSFORM_TRANSLATE) return gf_strdup("translate");
  4540. else if (tr == SVG_TRANSFORM_SKEWX) return gf_strdup("skewX");
  4541. else if (tr == SVG_TRANSFORM_SKEWY) return gf_strdup("skewY");
  4542. }
  4543. break;
  4544. case SMIL_AnimateValue_datatype:
  4545. {
  4546. GF_FieldInfo a_fi;
  4547. SMIL_AnimateValue*av = (SMIL_AnimateValue*)info->far_ptr;
  4548. a_fi.fieldIndex = 0;
  4549. a_fi.fieldType = av->type;
  4550. a_fi.name = info->name;
  4551. a_fi.far_ptr = av->value;
  4552. return gf_svg_dump_attribute(elt, &a_fi);
  4553. }
  4554. break;
  4555. case SMIL_AnimateValues_datatype:
  4556. {
  4557. GF_FieldInfo a_fi;
  4558. u32 i, count;
  4559. SMIL_AnimateValues *av = (SMIL_AnimateValues*)info->far_ptr;
  4560. char *attVal = gf_malloc(sizeof(char));
  4561. attVal[0] = 0;
  4562. if (av->type) {
  4563. count = gf_list_count(av->values);
  4564. a_fi.fieldIndex = 0;
  4565. a_fi.fieldType = av->type;
  4566. a_fi.name = info->name;
  4567. for (i=0; i<count; i++) {
  4568. char *szBuf;
  4569. a_fi.far_ptr = gf_list_get(av->values, i);
  4570. szBuf = gf_svg_dump_attribute(elt, &a_fi);
  4571. attVal = gf_realloc(attVal, sizeof(char)*(strlen(attVal)+strlen(szBuf)+ (i ? 2 : 1) ));
  4572. if (i) strcat(attVal, ";");
  4573. strcat(attVal, szBuf);
  4574. gf_free(szBuf);
  4575. }
  4576. }
  4577. return attVal;
  4578. }
  4579. case XMLEV_Event_datatype:
  4580. {
  4581. XMLEV_Event *d = (XMLEV_Event *)info->far_ptr;
  4582. if (d->parameter) {
  4583. svg_dump_access_key(d, tmp);
  4584. } else {
  4585. strcpy(tmp, gf_dom_event_get_name(d->type));
  4586. }
  4587. return gf_strdup(tmp);
  4588. }
  4589. default:
  4590. GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Dumping] field %s of type %s not supported\n", info->name, gf_svg_attribute_type_to_string(info->fieldType)));
  4591. break;
  4592. }
  4593. return gf_strdup("");
  4594. }
  4595. char *gf_svg_dump_attribute_indexed(GF_Node *elt, GF_FieldInfo *info)
  4596. {
  4597. char tmp[1024];
  4598. switch (info->fieldType) {
  4599. case SVG_PointerEvents_datatype:
  4600. break;
  4601. case XMLRI_List_datatype:
  4602. return gf_strdup( (char *) info->far_ptr);
  4603. case SVG_Points_datatype:
  4604. {
  4605. #if DUMP_COORDINATES
  4606. SVG_Point *p = (SVG_Point *)info->far_ptr;
  4607. sprintf(tmp, "%g %g", FIX2FLT(p->x), FIX2FLT(p->y));
  4608. return gf_strdup(tmp);
  4609. #endif
  4610. }
  4611. break;
  4612. case SMIL_KeyPoints_datatype:
  4613. case SMIL_KeyTimes_datatype:
  4614. case SMIL_KeySplines_datatype:
  4615. {
  4616. Fixed *p = (Fixed *)info->far_ptr;
  4617. sprintf(tmp, "%g", FIX2FLT(*p));
  4618. return gf_strdup(tmp);
  4619. }
  4620. break;
  4621. case SVG_Coordinates_datatype:
  4622. #if DUMP_COORDINATES
  4623. return svg_dump_number((SVG_Length *) (SVG_Coordinate *)info->far_ptr);
  4624. #endif
  4625. break;
  4626. case SVG_ViewBox_datatype:
  4627. {
  4628. Fixed *v = (Fixed *)info->far_ptr;
  4629. sprintf(tmp, "%g", FIX2FLT(*v));
  4630. return gf_strdup(tmp);
  4631. }
  4632. break;
  4633. case SVG_StrokeDashArray_datatype:
  4634. {
  4635. /*TODO: fix this: should be an SVG_Length*/
  4636. Fixed *p = (Fixed *)info->far_ptr;
  4637. sprintf(tmp, "%g", FIX2FLT(*p));
  4638. return gf_strdup(tmp);
  4639. }
  4640. break;
  4641. case SMIL_Times_datatype:
  4642. {
  4643. SMIL_Time *t = (SMIL_Time *)info->far_ptr;
  4644. if (t->type == GF_SMIL_TIME_CLOCK) {
  4645. sprintf(tmp, "%gs", t->clock);
  4646. } else if (t->type==GF_SMIL_TIME_INDEFINITE) {
  4647. strcpy(tmp, "indefinite");
  4648. } else if (t->type==GF_SMIL_TIME_WALLCLOCK) {
  4649. u32 h, m, s;
  4650. /*TODO - day month and year*/
  4651. h = (u32) t->clock * 3600;
  4652. m = (u32) (t->clock * 60 - 60*h);
  4653. s = (u32) (t->clock - 3600*h - 60*m);
  4654. sprintf(tmp, "wallclock(%d:%d:%d)", h, m, s);
  4655. }
  4656. else if (t->type==GF_SMIL_TIME_EVENT) {
  4657. GF_Node *par = gf_node_get_parent((GF_Node *)elt, 0);
  4658. if (t->event.type == GF_EVENT_KEYDOWN) {
  4659. svg_dump_access_key(&t->event, tmp);
  4660. } else {
  4661. strcpy(tmp, "");
  4662. if (t->element_id) {
  4663. strcat(tmp, t->element_id);
  4664. strcat(tmp, ".");
  4665. } else if (t->element && (t->element!=par) && gf_node_get_id(t->element) ) {
  4666. const char *name = gf_node_get_name(t->element);
  4667. if (name) {
  4668. strcat(tmp, name);
  4669. } else {
  4670. sprintf(tmp, "N%d", gf_node_get_id(t->element)-1 );
  4671. }
  4672. strcat(tmp, ".");
  4673. }
  4674. strcat(tmp, gf_dom_event_get_name(t->event.type));
  4675. }
  4676. if (t->clock) {
  4677. char szBuf[100];
  4678. sprintf(szBuf, "+%gs", t->clock);
  4679. strcat(tmp, szBuf);
  4680. }
  4681. }
  4682. return gf_strdup(tmp);
  4683. }
  4684. default:
  4685. GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Dumping] indexed field %s of type %s not supported\n", info->name, gf_svg_attribute_type_to_string(info->fieldType)));
  4686. break;
  4687. }
  4688. return gf_strdup("");
  4689. }
  4690. static Bool svg_viewbox_equal(SVG_ViewBox *v1, SVG_ViewBox *v2)
  4691. {
  4692. if (v1->is_set != v2->is_set) return 0;
  4693. if (!v1->is_set)
  4694. return 1;
  4695. else {
  4696. if ( (v1->x == v2->x) && (v1->y == v2->y) && (v1->width == v2->width) && (v1->height == v2->height) )
  4697. return 1;
  4698. else
  4699. return 0;
  4700. }
  4701. }
  4702. static Bool svg_colors_equal(SVG_Color *c1, SVG_Color *c2)
  4703. {
  4704. if (c1->type != c2->type) return 0;
  4705. if (c1->red != c2->red) return 0;
  4706. if (c1->green != c2->green) return 0;
  4707. if (c1->blue != c2->blue) return 0;
  4708. return 1;
  4709. }
  4710. static Bool svg_numbers_equal(SVG_Length *l1, SVG_Length *l2)
  4711. {
  4712. if (l1->type!=l2->type) return 0;
  4713. if (l1->type >= SVG_NUMBER_INHERIT) return 1;
  4714. return (l1->value==l2->value) ? 1 : 0;
  4715. }
  4716. static Bool svg_iris_equal(XMLRI*iri1, XMLRI*iri2)
  4717. {
  4718. u32 type1, type2;
  4719. type1 = iri1->type;
  4720. type2 = iri2->type;
  4721. /*ignore undef hrefs, these are internall ones*/
  4722. if ((iri1->type == XMLRI_ELEMENTID) && iri1->target) {
  4723. if (!gf_node_get_id((GF_Node *)iri1->target)) type1 = 0;
  4724. }
  4725. if ((iri2->type == XMLRI_ELEMENTID) && iri2->target) {
  4726. if (!gf_node_get_id((GF_Node *)iri2->target)) type2 = 0;
  4727. }
  4728. if (type1 != type2) return 0;
  4729. if ((type1 == XMLRI_ELEMENTID) && (iri1->target == iri2->target) ) return 1;
  4730. if (iri1->string && iri2->string && !strcmp(iri1->string, iri2->string)) return 1;
  4731. if (!iri1->string && !iri2->string) return 1;
  4732. return 0;
  4733. }
  4734. static Bool svg_matrices_equal(GF_Matrix2D *m1, GF_Matrix2D *m2)
  4735. {
  4736. if (m1->m[0] != m2->m[0]) return 0;
  4737. if (m1->m[1] != m2->m[1]) return 0;
  4738. if (m1->m[2] != m2->m[2]) return 0;
  4739. if (m1->m[3] != m2->m[3]) return 0;
  4740. if (m1->m[4] != m2->m[4]) return 0;
  4741. if (m1->m[5] != m2->m[5]) return 0;
  4742. return 1;
  4743. }
  4744. Bool gf_svg_attributes_equal(GF_FieldInfo *f1, GF_FieldInfo *f2)
  4745. {
  4746. u32 v1, v2;
  4747. if (f1->fieldType!=f2->fieldType) return 0;
  4748. if (f1->far_ptr && !f2->far_ptr) return 0;
  4749. if (f2->far_ptr && !f1->far_ptr) return 0;
  4750. if (!f1->far_ptr) return 1;
  4751. v1 = *(u8 *)f1->far_ptr;
  4752. v2 = *(u8 *)f2->far_ptr;
  4753. switch (f1->fieldType) {
  4754. case SVG_Boolean_datatype:
  4755. case SVG_FillRule_datatype:
  4756. case SVG_StrokeLineJoin_datatype:
  4757. case SVG_StrokeLineCap_datatype:
  4758. case SVG_FontStyle_datatype:
  4759. case SVG_FontWeight_datatype:
  4760. case SVG_FontVariant_datatype:
  4761. case SVG_TextAnchor_datatype:
  4762. case SVG_Display_datatype:
  4763. case SVG_Visibility_datatype:
  4764. case SVG_GradientUnit_datatype:
  4765. case SVG_PreserveAspectRatio_datatype:
  4766. case XML_Space_datatype:
  4767. case XMLEV_Propagate_datatype:
  4768. case XMLEV_DefaultAction_datatype:
  4769. case XMLEV_Phase_datatype:
  4770. case SMIL_SyncBehavior_datatype:
  4771. case SMIL_AttributeType_datatype:
  4772. case SMIL_CalcMode_datatype:
  4773. case SMIL_Additive_datatype:
  4774. case SMIL_Accumulate_datatype:
  4775. case SMIL_Restart_datatype:
  4776. case SMIL_Fill_datatype:
  4777. case SVG_Overflow_datatype:
  4778. case SVG_ZoomAndPan_datatype:
  4779. case SVG_DisplayAlign_datatype:
  4780. case SVG_TextAlign_datatype:
  4781. case SVG_PointerEvents_datatype:
  4782. case SVG_RenderingHint_datatype:
  4783. case SVG_VectorEffect_datatype:
  4784. case SVG_PlaybackOrder_datatype:
  4785. case SVG_TimelineBegin_datatype:
  4786. case SVG_FocusHighlight_datatype:
  4787. case SVG_TransformType_datatype:
  4788. case SVG_Overlay_datatype:
  4789. case SVG_TransformBehavior_datatype:
  4790. case SVG_SpreadMethod_datatype:
  4791. case SVG_InitialVisibility_datatype:
  4792. case LASeR_Choice_datatype:
  4793. return (v1==v2) ? 1 : 0;
  4794. case SVG_Color_datatype:
  4795. return svg_colors_equal((SVG_Color *)f1->far_ptr, (SVG_Color *)f2->far_ptr);
  4796. case SMIL_SyncTolerance_datatype:
  4797. {
  4798. SMIL_SyncTolerance *st1 = (SMIL_SyncTolerance*)f1->far_ptr;
  4799. SMIL_SyncTolerance *st2 = (SMIL_SyncTolerance*)f2->far_ptr;
  4800. if (st1->type!=st2->type) return 0;
  4801. if ((st1->type==SMIL_SYNCTOLERANCE_VALUE) && (st1->value!=st2->value)) return 0;
  4802. return 1;
  4803. }
  4804. case SVG_Paint_datatype:
  4805. {
  4806. SVG_Paint *p1 = (SVG_Paint *)f1->far_ptr;
  4807. SVG_Paint *p2 = (SVG_Paint *)f2->far_ptr;
  4808. if (p1->type != p2->type) return 0;
  4809. if (p1->type==SVG_PAINT_COLOR) return svg_colors_equal(&p1->color, &p2->color);
  4810. else if (p1->type==SVG_PAINT_URI) return svg_iris_equal(&p1->iri, &p2->iri);
  4811. return 1;
  4812. }
  4813. break;
  4814. case SVG_FontSize_datatype:
  4815. case SVG_Length_datatype:
  4816. case SVG_Coordinate_datatype:
  4817. case SVG_Rotate_datatype:
  4818. case SVG_Number_datatype:
  4819. return svg_numbers_equal((SVG_Number *)f1->far_ptr, (SVG_Number *)f2->far_ptr);
  4820. case XMLRI_datatype:
  4821. return svg_iris_equal((XMLRI*)f1->far_ptr, (XMLRI*)f2->far_ptr);
  4822. case XMLRI_List_datatype:
  4823. {
  4824. GF_List *l1 = *(GF_List **)f1->far_ptr;
  4825. GF_List *l2 = *(GF_List **)f2->far_ptr;
  4826. u32 i, count = gf_list_count(l1);
  4827. if (gf_list_count(l2)!=count) return 0;
  4828. for (i=0; i<count; i++) {
  4829. if (!svg_iris_equal((XMLRI*)gf_list_get(l1, i), (XMLRI*)gf_list_get(l2, i) )) return 0;
  4830. }
  4831. return 1;
  4832. }
  4833. case SVG_PathData_datatype:
  4834. {
  4835. SVG_PathData *d1 = (SVG_PathData *)f1->far_ptr;
  4836. SVG_PathData *d2 = (SVG_PathData *)f2->far_ptr;
  4837. u32 i;
  4838. /*FIXME - be less lazy..*/
  4839. #if USE_GF_PATH
  4840. if (d1->n_points != d2->n_points) return 0;
  4841. if (d1->n_contours != d2->n_contours) return 0;
  4842. for (i=0; i<d1->n_points; i++) {
  4843. if (d1->points[i].x != d2->points[i].x) return 0;
  4844. if (d1->points[i].y != d2->points[i].y) return 0;
  4845. }
  4846. for (i=0; i<d1->n_points; i++) {
  4847. if (d1->tags[i] != d2->tags[i]) return 0;
  4848. }
  4849. for (i=0; i<d1->n_contours; i++) {
  4850. if (d1->contours[i] != d2->contours[i]) return 0;
  4851. }
  4852. return 1;
  4853. #else
  4854. if (!gf_list_count(d1->commands) && !gf_list_count(d2->commands)) return 1;
  4855. #endif
  4856. return 0;
  4857. }
  4858. case SVG_Points_datatype:
  4859. {
  4860. GF_List *l1 = *(GF_List **) f1->far_ptr;
  4861. GF_List *l2 = *(GF_List **) f2->far_ptr;
  4862. u32 i = 0;
  4863. u32 count = gf_list_count(l1);
  4864. if (gf_list_count(l2)!=count) return 0;
  4865. for (i=0; i<count; i++) {
  4866. SVG_Point *p1 = (SVG_Point *)gf_list_get(l1, i);
  4867. SVG_Point *p2 = (SVG_Point *)gf_list_get(l2, i);
  4868. if (p1->x != p2->x) return 0;
  4869. if (p1->y != p2->y) return 0;
  4870. }
  4871. return 1;
  4872. }
  4873. case SMIL_KeyTimes_datatype:
  4874. case SMIL_KeyPoints_datatype:
  4875. case SMIL_KeySplines_datatype:
  4876. {
  4877. GF_List *l1 = *(GF_List **) f1->far_ptr;
  4878. GF_List *l2 = *(GF_List **) f2->far_ptr;
  4879. u32 i = 0;
  4880. u32 count = gf_list_count(l1);
  4881. if (gf_list_count(l2)!=count) return 0;
  4882. for (i=0; i<count; i++) {
  4883. Fixed *p1 = (Fixed *)gf_list_get(l1, i);
  4884. Fixed *p2 = (Fixed *)gf_list_get(l2, i);
  4885. if (*p1 != *p2) return 0;
  4886. }
  4887. return 1;
  4888. }
  4889. case SVG_Coordinates_datatype:
  4890. {
  4891. GF_List *l1 = *(GF_List **) f1->far_ptr;
  4892. GF_List *l2 = *(GF_List **) f2->far_ptr;
  4893. u32 i = 0;
  4894. u32 count = gf_list_count(l1);
  4895. if (gf_list_count(l2) != count) return 0;
  4896. for (i=0; i<count; i++) {
  4897. SVG_Coordinate *p1 = (SVG_Coordinate *)gf_list_get(l1, i);
  4898. SVG_Coordinate *p2 = (SVG_Coordinate *)gf_list_get(l2, i);
  4899. if (!svg_numbers_equal(p1, p2)) return 0;
  4900. }
  4901. return 1;
  4902. }
  4903. case SVG_ViewBox_datatype:
  4904. {
  4905. SVG_ViewBox *v1 = (SVG_ViewBox *)f1->far_ptr;
  4906. SVG_ViewBox *v2 = (SVG_ViewBox *)f2->far_ptr;
  4907. return svg_viewbox_equal(v1, v2);
  4908. }
  4909. case SVG_StrokeDashArray_datatype:
  4910. {
  4911. SVG_StrokeDashArray *p1 = (SVG_StrokeDashArray *)f1->far_ptr;
  4912. SVG_StrokeDashArray *p2 = (SVG_StrokeDashArray *)f2->far_ptr;
  4913. if (p1->type!=p2->type) return 0;
  4914. if (p1->type==SVG_STROKEDASHARRAY_ARRAY) {
  4915. u32 i = 0;
  4916. if (p1->array.count != p2->array.count) return 0;
  4917. for (i=0; i<p1->array.count; i++) {
  4918. if (p1->array.units[i] != p2->array.units[i]) return 0;
  4919. if (p1->array.vals[i] != p2->array.vals[i]) return 0;
  4920. }
  4921. }
  4922. return 1;
  4923. }
  4924. case SVG_FontFamily_datatype:
  4925. {
  4926. SVG_FontFamily *ff1 = (SVG_FontFamily *)f1->far_ptr;
  4927. SVG_FontFamily *ff2 = (SVG_FontFamily *)f2->far_ptr;
  4928. if (ff1->type!=ff2->type) return 0;
  4929. if (ff1->type==SVG_FONTFAMILY_INHERIT) return 1;
  4930. return (ff1->value && ff2->value && !strcmp(ff1->value, ff2->value)) ? 1 : 0;
  4931. }
  4932. case SVG_Clock_datatype:
  4933. return (* (SVG_Clock *)f1->far_ptr == * (SVG_Clock *)f2->far_ptr) ? 1 : 0;
  4934. /* required for animateMotion */
  4935. case SVG_Motion_datatype:
  4936. return svg_matrices_equal((GF_Matrix2D*)f1->far_ptr, (GF_Matrix2D*)f2->far_ptr);
  4937. case SVG_Transform_datatype:
  4938. {
  4939. SVG_Transform *t1 = (SVG_Transform *)f1->far_ptr;
  4940. SVG_Transform *t2 = (SVG_Transform *)f2->far_ptr;
  4941. if (t1->is_ref == t2->is_ref)
  4942. return svg_matrices_equal(&t1->mat, &t2->mat);
  4943. else
  4944. return 0;
  4945. }
  4946. case SVG_Transform_Translate_datatype:
  4947. case SVG_Transform_Scale_datatype:
  4948. {
  4949. SVG_Point *p1 = (SVG_Point *)f1->far_ptr;
  4950. SVG_Point *p2 = (SVG_Point *)f2->far_ptr;
  4951. if (p1->x != p2->x) return 0;
  4952. if (p1->y != p2->y) return 0;
  4953. return 1;
  4954. }
  4955. case SVG_Transform_SkewX_datatype:
  4956. case SVG_Transform_SkewY_datatype:
  4957. {
  4958. Fixed *p1 = (Fixed *)f1->far_ptr;
  4959. Fixed *p2 = (Fixed *)f2->far_ptr;
  4960. return (*p1 == *p2);
  4961. }
  4962. case SVG_Transform_Rotate_datatype:
  4963. {
  4964. SVG_Point_Angle *p1 = (SVG_Point_Angle *)f1->far_ptr;
  4965. SVG_Point_Angle *p2 = (SVG_Point_Angle *)f2->far_ptr;
  4966. if (p1->x != p2->x) return 0;
  4967. if (p1->y != p2->y) return 0;
  4968. if (p1->angle != p2->angle) return 0;
  4969. return 1;
  4970. }
  4971. case SVG_ID_datatype:
  4972. case SVG_LanguageID_datatype:
  4973. case SVG_GradientOffset_datatype:
  4974. case DOM_String_datatype:
  4975. case SVG_ContentType_datatype:
  4976. {
  4977. char *str1 = *(SVG_String *)f1->far_ptr;
  4978. char *str2 = *(SVG_String *)f2->far_ptr;
  4979. if (!str1 && !str2) return 1;
  4980. return (str1 && str2 && !strcmp(str1, str2)) ? 1 : 0;
  4981. }
  4982. case SVG_Focus_datatype:
  4983. {
  4984. SVG_Focus *foc1 = (SVG_Focus *) f1->far_ptr;
  4985. SVG_Focus *foc2 = (SVG_Focus *)f2->far_ptr;
  4986. if (foc1->type!=foc2->type) return 0;
  4987. if (foc1->type != SVG_FOCUS_IRI) return 1;
  4988. return (foc1->target.string && foc2->target.string && !strcmp(foc1->target.string, foc2->target.string)) ? 1 : 0;
  4989. }
  4990. break;
  4991. case DOM_StringList_datatype:
  4992. {
  4993. GF_List *l1 = *(GF_List **) f1->far_ptr;
  4994. GF_List *l2 = *(GF_List **) f2->far_ptr;
  4995. u32 i = 0;
  4996. u32 count = gf_list_count(l1);
  4997. if (gf_list_count(l2) != count) return 0;
  4998. for (i=0; i<count; i++) {
  4999. char *p1 = (char *)gf_list_get(l1, i);
  5000. char *p2 = (char *)gf_list_get(l2, i);
  5001. if (strcmp(p1, p2)) return 0;
  5002. }
  5003. return 1;
  5004. }
  5005. case SVG_Numbers_datatype:
  5006. {
  5007. GF_List *l1 = *(GF_List **) f1->far_ptr;
  5008. GF_List *l2 = *(GF_List **) f2->far_ptr;
  5009. u32 i = 0;
  5010. u32 count = gf_list_count(l1);
  5011. if (gf_list_count(l2) != count) return 0;
  5012. for (i=0; i<count; i++) {
  5013. SVG_Number *p1 = (SVG_Number *)gf_list_get(l1, i);
  5014. SVG_Number *p2 = (SVG_Number *)gf_list_get(l2, i);
  5015. if (!svg_numbers_equal(p1, p2)) return 0;
  5016. }
  5017. return 1;
  5018. }
  5019. case SMIL_Times_datatype:
  5020. {
  5021. GF_List *l1 = *(GF_List **) f1->far_ptr;
  5022. GF_List *l2 = *(GF_List **) f2->far_ptr;
  5023. u32 i = 0;
  5024. u32 count = gf_list_count(l1);
  5025. if (gf_list_count(l2) != count) return 0;
  5026. for (i=0; i<count; i++) {
  5027. SMIL_Time *p1 = (SMIL_Time *)gf_list_get(l1, i);
  5028. SMIL_Time *p2 = (SMIL_Time *)gf_list_get(l2, i);
  5029. if (p1->type != p2->type) return 0;
  5030. if (p1->clock != p2->clock) return 0;
  5031. if (p1->type==GF_SMIL_TIME_EVENT) {
  5032. if (p1->event.type != p2->event.type) return 0;
  5033. if (p1->event.parameter != p2->event.parameter) return 0;
  5034. }
  5035. }
  5036. return 1;
  5037. }
  5038. case SMIL_Duration_datatype:
  5039. {
  5040. SMIL_Duration *d1 = (SMIL_Duration *)f1->far_ptr;
  5041. SMIL_Duration *d2 = (SMIL_Duration *)f2->far_ptr;
  5042. if (d1->type != d2->type) return 0;
  5043. if (d1->clock_value != d2->clock_value) return 0;
  5044. return 1;
  5045. }
  5046. case SMIL_RepeatCount_datatype:
  5047. {
  5048. SMIL_RepeatCount *d1 = (SMIL_RepeatCount *)f1->far_ptr;
  5049. SMIL_RepeatCount *d2 = (SMIL_RepeatCount *)f2->far_ptr;
  5050. if (d1->type != d2->type) return 0;
  5051. if (d1->count != d2->count) return 0;
  5052. return 1;
  5053. }
  5054. case SMIL_AttributeName_datatype:
  5055. {
  5056. SMIL_AttributeName *att1 = (SMIL_AttributeName *) f1->far_ptr;
  5057. SMIL_AttributeName *att2 = (SMIL_AttributeName *) f2->far_ptr;
  5058. /*TODO check me...*/
  5059. if (att2->field_ptr == att1->field_ptr) return 1;
  5060. return 0;
  5061. }
  5062. case SMIL_AnimateValue_datatype:
  5063. {
  5064. SMIL_AnimateValue *av1 = (SMIL_AnimateValue*)f1->far_ptr;
  5065. SMIL_AnimateValue *av2 = (SMIL_AnimateValue*)f2->far_ptr;
  5066. if (av1->value != av2->value) return 0;
  5067. return 1;
  5068. }
  5069. break;
  5070. case SMIL_AnimateValues_datatype:
  5071. {
  5072. u32 count;
  5073. SMIL_AnimateValues *av1 = (SMIL_AnimateValues*)f1->far_ptr;
  5074. SMIL_AnimateValues *av2 = (SMIL_AnimateValues*)f2->far_ptr;
  5075. if (av1->type != av2->type) return 0;
  5076. if ( (count = gf_list_count(av1->values) ) != gf_list_count(av1->values)) return 0;
  5077. return count ? 0 : 1;
  5078. }
  5079. case XMLEV_Event_datatype:
  5080. {
  5081. XMLEV_Event *d1 = (XMLEV_Event *)f1->far_ptr;
  5082. XMLEV_Event *d2 = (XMLEV_Event *)f2->far_ptr;
  5083. if (d1->type != d2->type) return 0;
  5084. if (d1->parameter != d2->parameter) return 0;
  5085. return 1;
  5086. }
  5087. case LASeR_Size_datatype:
  5088. {
  5089. LASeR_Size *sz1 = (LASeR_Size *)f1->far_ptr;
  5090. LASeR_Size *sz2 = (LASeR_Size *)f2->far_ptr;
  5091. if (sz1->width != sz2->width) return 0;
  5092. if (sz1->height != sz2->height) return 0;
  5093. return 1;
  5094. }
  5095. default:
  5096. GF_LOG(GF_LOG_WARNING, GF_LOG_INTERACT, ("[SVG Attributes] comparaison for field %s of type %s not supported\n", f1->name, gf_svg_attribute_type_to_string(f1->fieldType)));
  5097. return 0;
  5098. }
  5099. }
  5100. static void svg_color_clamp(SVG_Color *a)
  5101. {
  5102. a->red = MAX(0, MIN(FIX_ONE, a->red));
  5103. a->green = MAX(0, MIN(FIX_ONE, a->green));
  5104. a->blue = MAX(0, MIN(FIX_ONE, a->blue));
  5105. }
  5106. static GF_Err svg_color_muladd(Fixed alpha, SVG_Color *a, Fixed beta, SVG_Color *b, SVG_Color *c, Bool clamp)
  5107. {
  5108. if (a->type != SVG_COLOR_RGBCOLOR || b->type != SVG_COLOR_RGBCOLOR) {
  5109. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] only RGB colors are additive\n"));
  5110. return GF_BAD_PARAM;
  5111. }
  5112. c->type = SVG_COLOR_RGBCOLOR;
  5113. c->red = gf_mulfix(alpha, a->red) + gf_mulfix(beta, b->red);
  5114. c->green = gf_mulfix(alpha, a->green) + gf_mulfix(beta, b->green);
  5115. c->blue = gf_mulfix(alpha, a->blue) + gf_mulfix(beta, b->blue);
  5116. if (clamp) svg_color_clamp(c);
  5117. return GF_OK;
  5118. }
  5119. static GF_Err svg_number_muladd(Fixed alpha, SVG_Number *a, Fixed beta, SVG_Number *b, SVG_Number *c)
  5120. {
  5121. if (a->type != b->type) {
  5122. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] cannot add lengths of mismatching types\n"));
  5123. return GF_BAD_PARAM;
  5124. }
  5125. if (a->type == SVG_NUMBER_INHERIT || a->type == SVG_NUMBER_AUTO) {
  5126. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] cannot add lengths\n"));
  5127. return GF_BAD_PARAM;
  5128. }
  5129. c->value = gf_mulfix(alpha, a->value) + gf_mulfix(beta, b->value);
  5130. return GF_OK;
  5131. }
  5132. static GF_Err svg_viewbox_muladd(Fixed alpha, SVG_ViewBox *a, Fixed beta, SVG_ViewBox *b, SVG_ViewBox *c)
  5133. {
  5134. c->is_set = 1;
  5135. c->x = gf_mulfix(alpha, a->x) + gf_mulfix(beta, b->x);
  5136. c->y = gf_mulfix(alpha, a->y) + gf_mulfix(beta, b->y);
  5137. c->width = gf_mulfix(alpha, a->width) + gf_mulfix(beta, b->width);
  5138. c->height= gf_mulfix(alpha, a->height) + gf_mulfix(beta, b->height);
  5139. return GF_OK;
  5140. }
  5141. static GF_Err svg_point_muladd(Fixed alpha, SVG_Point *pta, Fixed beta, SVG_Point *ptb, SVG_Point *ptc)
  5142. {
  5143. ptc->x = gf_mulfix(alpha, pta->x) + gf_mulfix(beta, ptb->x);
  5144. ptc->y = gf_mulfix(alpha, pta->y) + gf_mulfix(beta, ptb->y);
  5145. return GF_OK;
  5146. }
  5147. static GF_Err svg_point_angle_muladd(Fixed alpha, SVG_Point_Angle *pta, Fixed beta, SVG_Point_Angle *ptb, SVG_Point_Angle *ptc)
  5148. {
  5149. ptc->x = gf_mulfix(alpha, pta->x) + gf_mulfix(beta, ptb->x);
  5150. ptc->y = gf_mulfix(alpha, pta->y) + gf_mulfix(beta, ptb->y);
  5151. ptc->angle = gf_mulfix(alpha, pta->angle) + gf_mulfix(beta, ptb->angle);
  5152. return GF_OK;
  5153. }
  5154. static GF_Err svg_points_muladd(Fixed alpha, SVG_Points *a, Fixed beta, SVG_Points *b, SVG_Points *c)
  5155. {
  5156. u32 a_count = gf_list_count(*a);
  5157. u32 i;
  5158. if (a_count != gf_list_count(*b)) return GF_BAD_PARAM;
  5159. while (gf_list_count(*c)) {
  5160. SVG_Point *ptc = (SVG_Point *)gf_list_get(*c, 0);
  5161. gf_list_rem(*c, 0);
  5162. gf_free(ptc);
  5163. }
  5164. for (i = 0; i < a_count; i ++) {
  5165. SVG_Point *ptc;
  5166. SVG_Point *pta = (SVG_Point *)gf_list_get(*a, i);
  5167. SVG_Point *ptb = (SVG_Point *)gf_list_get(*b, i);
  5168. GF_SAFEALLOC(ptc, SVG_Point)
  5169. svg_point_muladd(alpha, pta, beta, ptb, ptc);
  5170. gf_list_add(*c, ptc);
  5171. }
  5172. return GF_OK;
  5173. }
  5174. static GF_Err svg_points_copy(SVG_Points *a, SVG_Points *b)
  5175. {
  5176. u32 i, count;
  5177. count = gf_list_count(*a);
  5178. for (i = 0; i < count; i++) {
  5179. SVG_Point *pt = (SVG_Point *)gf_list_get(*a, i);
  5180. gf_free(pt);
  5181. }
  5182. gf_list_reset(*a);
  5183. count = gf_list_count(*b);
  5184. for (i = 0; i < count; i ++) {
  5185. SVG_Point *ptb = (SVG_Point *)gf_list_get(*b, i);
  5186. SVG_Point *pta;
  5187. GF_SAFEALLOC(pta, SVG_Point)
  5188. *pta = *ptb;
  5189. gf_list_add(*a, pta);
  5190. }
  5191. return GF_OK;
  5192. }
  5193. static GF_Err svg_numbers_muladd(Fixed alpha, SVG_Numbers *a, Fixed beta, SVG_Numbers *b, SVG_Numbers *c)
  5194. {
  5195. u32 a_count = gf_list_count(*a);
  5196. u32 i;
  5197. if (a_count != gf_list_count(*b)) return GF_BAD_PARAM;
  5198. gf_list_reset(*c);
  5199. for (i = 0; i < a_count; i ++) {
  5200. SVG_Number *nc;
  5201. SVG_Number *na = (SVG_Number *)gf_list_get(*a, i);
  5202. SVG_Number *nb = (SVG_Number *)gf_list_get(*b, i);
  5203. GF_SAFEALLOC(nc, SVG_Number)
  5204. svg_number_muladd(alpha, na, beta, nb, nc);
  5205. gf_list_add(*c, nc);
  5206. }
  5207. return GF_OK;
  5208. }
  5209. static GF_Err svg_numbers_copy(SVG_Numbers *a, SVG_Numbers *b)
  5210. {
  5211. u32 i, count;
  5212. count = gf_list_count(*a);
  5213. for (i = 0; i < count; i++) {
  5214. SVG_Coordinate *c = (SVG_Coordinate *)gf_list_get(*a, i);
  5215. gf_free(c);
  5216. }
  5217. gf_list_reset(*a);
  5218. count = gf_list_count(*b);
  5219. for (i = 0; i < count; i ++) {
  5220. SVG_Number *na;
  5221. GF_SAFEALLOC(na, SVG_Number)
  5222. *na = *(SVG_Number *)gf_list_get(*b, i);
  5223. gf_list_add(*a, na);
  5224. }
  5225. return GF_OK;
  5226. }
  5227. #if USE_GF_PATH
  5228. static GF_Err svg_path_copy(SVG_PathData *a, SVG_PathData *b)
  5229. {
  5230. if (a->contours) gf_free(a->contours);
  5231. if (a->points) gf_free(a->points);
  5232. if (a->tags) gf_free(a->tags);
  5233. a->contours = (u32 *)gf_malloc(sizeof(u32)*b->n_contours);
  5234. a->points = (GF_Point2D *) gf_malloc(sizeof(GF_Point2D)*b->n_points);
  5235. a->tags = (u8 *) gf_malloc(sizeof(u8)*b->n_points);
  5236. memcpy(a->contours, b->contours, sizeof(u32)*b->n_contours);
  5237. a->n_contours = b->n_contours;
  5238. memcpy(a->points, b->points, sizeof(GF_Point2D)*b->n_points);
  5239. memcpy(a->tags, b->tags, sizeof(u8)*b->n_points);
  5240. a->n_alloc_points = a->n_points = b->n_points;
  5241. a->flags = b->flags;
  5242. a->bbox = b->bbox;
  5243. a->fineness = b->fineness;
  5244. return GF_OK;
  5245. }
  5246. #else
  5247. static GF_Err svg_path_copy(SVG_PathData *a, SVG_PathData *b)
  5248. {
  5249. u32 i, count;
  5250. count = gf_list_count(a->commands);
  5251. for (i = 0; i < count; i++) {
  5252. u8 *command = (u8 *)gf_list_get(a->commands, i);
  5253. gf_free(command);
  5254. }
  5255. gf_list_reset(a->commands);
  5256. count = gf_list_count(a->points);
  5257. for (i = 0; i < count; i++) {
  5258. SVG_Point *pt = (SVG_Point *)gf_list_get(a->points, i);
  5259. gf_free(pt);
  5260. }
  5261. gf_list_reset(a->points);
  5262. count = gf_list_count(b->commands);
  5263. for (i = 0; i < count; i ++) {
  5264. u8 *nc = (u8 *)gf_malloc(sizeof(u8));
  5265. *nc = *(u8*)gf_list_get(b->commands, i);
  5266. gf_list_add(a->commands, nc);
  5267. }
  5268. count = gf_list_count(b->points);
  5269. for (i = 0; i < count; i ++) {
  5270. SVG_Point *pta;
  5271. GF_SAFEALLOC(pta, SVG_Point)
  5272. *pta = *(SVG_Point *)gf_list_get(b->points, i);
  5273. gf_list_add(a->points, pta);
  5274. }
  5275. return GF_OK;
  5276. }
  5277. #endif
  5278. #if USE_GF_PATH
  5279. static GF_Err svg_path_muladd(Fixed alpha, SVG_PathData *a, Fixed beta, SVG_PathData *b, SVG_PathData *c)
  5280. {
  5281. u32 i;
  5282. if (a->n_points != b->n_points) return GF_BAD_PARAM;
  5283. gf_path_reset(c);
  5284. svg_path_copy(c, a);
  5285. for (i=0; i<a->n_points; i++) {
  5286. svg_point_muladd(alpha, (SVG_Point *) &a->points[i], beta, (SVG_Point *) &b->points[i], (SVG_Point *) &c->points[i]);
  5287. }
  5288. c->flags |= GF_PATH_BBOX_DIRTY;
  5289. c->flags &= ~GF_PATH_FLATTENED;
  5290. return GF_OK;
  5291. }
  5292. #else
  5293. static GF_Err svg_path_muladd(Fixed alpha, SVG_PathData *a, Fixed beta, SVG_PathData *b, SVG_PathData *c)
  5294. {
  5295. u32 i, ccount, pcount;
  5296. ccount = gf_list_count(a->commands);
  5297. pcount = gf_list_count(a->points);
  5298. if (pcount != gf_list_count(b->points)) return GF_BAD_PARAM;
  5299. #if 0
  5300. if (ccount != gf_list_count(b->commands)) return GF_BAD_PARAM;
  5301. for (i = 0; i < ccount; i++) {
  5302. u8 *ac = gf_list_get(a->commands, i);
  5303. u8 *bc = gf_list_get(b->commands, i);
  5304. if (*ac != *bc) return GF_BAD_PARAM;
  5305. }
  5306. #endif
  5307. while (gf_list_count(c->commands)) {
  5308. u8 *command = (u8 *)gf_list_last(c->commands);
  5309. gf_free(command);
  5310. gf_list_rem_last(c->commands);
  5311. }
  5312. while (gf_list_count(c->points)) {
  5313. SVG_Point *pt = (SVG_Point *)gf_list_last(c->points);
  5314. gf_free(pt);
  5315. gf_list_rem_last(c->points);
  5316. }
  5317. for (i = 0; i < ccount; i++) {
  5318. u8 *nc = (u8 *)gf_malloc(sizeof(u8));
  5319. *nc = *(u8*)gf_list_get(a->commands, i);
  5320. gf_list_add(c->commands, nc);
  5321. }
  5322. for (i = 0; i < pcount; i++) {
  5323. SVG_Point *pta = (SVG_Point *)gf_list_get(a->points, i);
  5324. SVG_Point *ptb = (SVG_Point *)gf_list_get(b->points, i);
  5325. SVG_Point *ptc;
  5326. GF_SAFEALLOC(ptc, SVG_Point)
  5327. svg_point_muladd(alpha, pta, beta, ptb, ptc);
  5328. gf_list_add(c->points, ptc);
  5329. }
  5330. return GF_OK;
  5331. }
  5332. #endif
  5333. static GF_Err svg_dasharray_muladd(Fixed alpha, SVG_StrokeDashArray *a, Fixed beta, SVG_StrokeDashArray *b, SVG_StrokeDashArray *c)
  5334. {
  5335. u32 i;
  5336. if (a->type != b->type) return GF_BAD_PARAM;
  5337. if (a->array.count != b->array.count) return GF_BAD_PARAM;
  5338. c->type = a->type;
  5339. c->array.count = a->array.count;
  5340. c->array.vals = (Fixed *) gf_malloc(sizeof(Fixed)*c->array.count);
  5341. for (i = 0; i < c->array.count; i++) {
  5342. /* TODO: convert units if needed */
  5343. c->array.units[i] = a->array.units[i];
  5344. c->array.vals[i] = gf_mulfix(alpha, a->array.vals[i]) + gf_mulfix(beta, b->array.vals[i]);
  5345. }
  5346. return GF_OK;
  5347. }
  5348. static GF_Err svg_dasharray_copy(SVG_StrokeDashArray *a, SVG_StrokeDashArray *b)
  5349. {
  5350. a->type = b->type;
  5351. a->array.count = b->array.count;
  5352. a->array.units = (u8*)gf_malloc(sizeof(u8)*a->array.count);
  5353. memcpy(a->array.units, b->array.units, sizeof(u8)*a->array.count);
  5354. a->array.vals = (Fixed*)gf_malloc(sizeof(Fixed)*a->array.count);
  5355. memcpy(a->array.vals, b->array.vals, sizeof(Fixed)*a->array.count);
  5356. return GF_OK;
  5357. }
  5358. static GF_Err svg_matrix_muladd(Fixed alpha, GF_Matrix2D *a, Fixed beta, GF_Matrix2D *b, GF_Matrix2D *c)
  5359. {
  5360. /*
  5361. if ((alpha == beta) && (alpha == FIX_ONE) ) {
  5362. GF_Matrix2D tmp;
  5363. gf_mx2d_copy(tmp, *b);
  5364. gf_mx2d_add_matrix(&tmp, a);
  5365. gf_mx2d_copy(*c, tmp);
  5366. } else */
  5367. if (alpha <= FIX_ONE) {
  5368. /* This case should happen only when using animateMotion and accumulation
  5369. see animate-elem-202-t.svg
  5370. we only add and multiply the translation component; */
  5371. /*
  5372. c->m[0] = gf_mulfix(alpha, a->m[0]) + gf_mulfix(beta, b->m[0]);
  5373. c->m[1] = gf_mulfix(alpha, a->m[1]) + gf_mulfix(beta, b->m[1]);
  5374. c->m[2] = gf_mulfix(alpha, a->m[2]) + gf_mulfix(beta, b->m[2]);
  5375. c->m[3] = gf_mulfix(alpha, a->m[3]) + gf_mulfix(beta, b->m[3]);
  5376. */
  5377. c->m[0] = a->m[0];
  5378. c->m[1] = a->m[1];
  5379. c->m[2] = gf_mulfix(alpha, a->m[2]) + gf_mulfix(beta, b->m[2]);
  5380. c->m[3] = a->m[3];
  5381. c->m[4] = a->m[4];
  5382. c->m[5] = gf_mulfix(alpha, a->m[5]) + gf_mulfix(beta, b->m[5]);
  5383. } else {
  5384. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] matrix operations not supported\n"));
  5385. return GF_BAD_PARAM;
  5386. }
  5387. return GF_OK;
  5388. }
  5389. static GF_Err laser_size_muladd(Fixed alpha, LASeR_Size *sza, Fixed beta, LASeR_Size *szb, LASeR_Size *szc)
  5390. {
  5391. szc->width = gf_mulfix(alpha, sza->width) + gf_mulfix(beta, szb->width);
  5392. szc->height = gf_mulfix(alpha, sza->height) + gf_mulfix(beta, szb->height);
  5393. return GF_OK;
  5394. }
  5395. /* c = alpha * a + beta * b */
  5396. GF_Err gf_svg_attributes_muladd(Fixed alpha, GF_FieldInfo *a,
  5397. Fixed beta, GF_FieldInfo *b,
  5398. GF_FieldInfo *c,
  5399. Bool clamp)
  5400. {
  5401. if (!a->far_ptr || !b->far_ptr || !c->far_ptr) return GF_BAD_PARAM;
  5402. if (a->fieldType != b->fieldType) {
  5403. if (a->fieldType != SVG_Transform_datatype &&
  5404. a->fieldType != SVG_Transform_Scale_datatype &&
  5405. a->fieldType != SVG_Transform_Translate_datatype &&
  5406. a->fieldType != SVG_Transform_Rotate_datatype &&
  5407. a->fieldType != SVG_Transform_SkewX_datatype &&
  5408. a->fieldType != SVG_Transform_SkewY_datatype &&
  5409. a->fieldType != SVG_Motion_datatype)
  5410. return GF_BAD_PARAM;
  5411. }
  5412. /* by default a and c are of the same type, except for matrix related types */
  5413. c->fieldType = a->fieldType;
  5414. switch (a->fieldType) {
  5415. /* Numeric types */
  5416. case SVG_Color_datatype:
  5417. return svg_color_muladd(alpha, (SVG_Color*)a->far_ptr, beta, (SVG_Color*)b->far_ptr, (SVG_Color*)c->far_ptr, clamp);
  5418. case SVG_Paint_datatype:
  5419. {
  5420. SVG_Paint *pa = (SVG_Paint *)a->far_ptr;
  5421. SVG_Paint *pb = (SVG_Paint *)b->far_ptr;
  5422. SVG_Paint *pc = (SVG_Paint *)c->far_ptr;
  5423. if (pa->type != pb->type || pa->type != SVG_PAINT_COLOR || pb->type != SVG_PAINT_COLOR) {
  5424. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] only color paints are additive\n"));
  5425. return GF_BAD_PARAM;
  5426. }
  5427. pc->type = SVG_PAINT_COLOR;
  5428. return svg_color_muladd(alpha, &pa->color, beta, &pb->color, &pc->color, clamp);
  5429. }
  5430. case SVG_Number_datatype:
  5431. case SVG_Length_datatype:
  5432. case SVG_Coordinate_datatype:
  5433. case SVG_FontSize_datatype:
  5434. return svg_number_muladd(alpha, (SVG_Number*)a->far_ptr, beta, (SVG_Number*)b->far_ptr, (SVG_Number*)c->far_ptr);
  5435. case SVG_ViewBox_datatype:
  5436. return svg_viewbox_muladd(alpha, (SVG_ViewBox*)a->far_ptr, beta, (SVG_ViewBox*)b->far_ptr, (SVG_ViewBox*)c->far_ptr);
  5437. case SVG_Points_datatype:
  5438. return svg_points_muladd(alpha, (GF_List **)a->far_ptr, beta, (GF_List **)b->far_ptr, (GF_List **)c->far_ptr);
  5439. case SVG_Numbers_datatype:
  5440. case SVG_Coordinates_datatype:
  5441. return svg_numbers_muladd(alpha, (GF_List **)a->far_ptr, beta, (GF_List **)b->far_ptr, (GF_List **)c->far_ptr);
  5442. case SVG_PathData_datatype:
  5443. return svg_path_muladd(alpha, (SVG_PathData*)a->far_ptr, beta, (SVG_PathData*)b->far_ptr, (SVG_PathData*)c->far_ptr);
  5444. case SVG_StrokeDashArray_datatype:
  5445. return svg_dasharray_muladd(alpha, (SVG_StrokeDashArray*)a->far_ptr, beta, (SVG_StrokeDashArray*)b->far_ptr, (SVG_StrokeDashArray*)c->far_ptr);
  5446. case SVG_Motion_datatype:
  5447. return svg_matrix_muladd(alpha, (GF_Matrix2D*)a->far_ptr, beta, (GF_Matrix2D*)b->far_ptr, (GF_Matrix2D*)c->far_ptr);
  5448. case SVG_Transform_datatype:
  5449. if (b->fieldType == SVG_Transform_datatype) {
  5450. SVG_Transform *ta = (SVG_Transform *)a->far_ptr;
  5451. SVG_Transform *tb = (SVG_Transform *)b->far_ptr;
  5452. SVG_Transform *tc = (SVG_Transform *)c->far_ptr;
  5453. if (ta->is_ref == tb->is_ref) {
  5454. return svg_matrix_muladd(alpha, &ta->mat, beta, &tb->mat, &tc->mat);
  5455. } else {
  5456. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] matrix operations not supported\n"));
  5457. return GF_NOT_SUPPORTED;
  5458. }
  5459. } else {
  5460. /* a and c are matrices but b is not */
  5461. GF_Matrix2D tmp;
  5462. /*TOCHECK what is this test*/
  5463. /*
  5464. if (alpha != FIX_ONE) {
  5465. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] matrix operations not supported\n"));
  5466. return GF_NOT_SUPPORTED;
  5467. }
  5468. */
  5469. gf_mx2d_init(tmp);
  5470. switch (b->fieldType) {
  5471. case SVG_Transform_Translate_datatype:
  5472. gf_mx2d_add_translation(&tmp, gf_mulfix(((SVG_Point *)b->far_ptr)->x, beta), gf_mulfix(((SVG_Point *)b->far_ptr)->y, beta));
  5473. break;
  5474. case SVG_Transform_Scale_datatype:
  5475. gf_mx2d_add_scale(&tmp, gf_mulfix(((SVG_Point *)b->far_ptr)->x, beta), gf_mulfix(((SVG_Point *)b->far_ptr)->y, beta));
  5476. break;
  5477. case SVG_Transform_Rotate_datatype:
  5478. gf_mx2d_add_rotation(&tmp, gf_mulfix(((SVG_Point_Angle *)b->far_ptr)->x, beta), gf_mulfix(((SVG_Point_Angle *)b->far_ptr)->y, beta), gf_mulfix(((SVG_Point_Angle *)b->far_ptr)->angle, beta));
  5479. break;
  5480. case SVG_Transform_SkewX_datatype:
  5481. gf_mx2d_add_skew_x(&tmp, gf_mulfix(*(Fixed*)b->far_ptr, beta));
  5482. break;
  5483. case SVG_Transform_SkewY_datatype:
  5484. gf_mx2d_add_skew_y(&tmp, gf_mulfix(*(Fixed*)b->far_ptr, beta));
  5485. break;
  5486. default:
  5487. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] copy of attributes %s not supported\n", a->name));
  5488. return GF_NOT_SUPPORTED;
  5489. }
  5490. gf_mx2d_add_matrix(&tmp, &((SVG_Transform*)a->far_ptr)->mat);
  5491. gf_mx2d_copy(((SVG_Transform*)c->far_ptr)->mat, tmp);
  5492. return GF_OK;
  5493. }
  5494. case SVG_Transform_Translate_datatype:
  5495. if (b->fieldType == SVG_Transform_Translate_datatype) {
  5496. return svg_point_muladd(alpha, (SVG_Point*)a->far_ptr, beta, (SVG_Point*)b->far_ptr, (SVG_Point*)c->far_ptr);
  5497. } else {
  5498. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] matrix operations not supported\n"));
  5499. return GF_NOT_SUPPORTED;
  5500. }
  5501. case SVG_Transform_Scale_datatype:
  5502. if (b->fieldType == SVG_Transform_Scale_datatype) {
  5503. if (alpha == FIX_ONE && beta == FIX_ONE) {
  5504. /* addition of matrices which represent scales is equivalent
  5505. to multiplication of scale coefficients, we assume this only happens if
  5506. alpha and beta are set to one */
  5507. ((SVG_Point*)c->far_ptr)->x = gf_mulfix(((SVG_Point*)a->far_ptr)->x,((SVG_Point*)b->far_ptr)->x);
  5508. ((SVG_Point*)c->far_ptr)->y = gf_mulfix(((SVG_Point*)a->far_ptr)->y,((SVG_Point*)b->far_ptr)->y);
  5509. return GF_OK;
  5510. } else {
  5511. return svg_point_muladd(alpha, (SVG_Point*)a->far_ptr, beta, (SVG_Point*)b->far_ptr, (SVG_Point*)c->far_ptr);
  5512. }
  5513. } else {
  5514. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] matrix operations not supported\n"));
  5515. return GF_NOT_SUPPORTED;
  5516. }
  5517. case SVG_Transform_Rotate_datatype:
  5518. if (b->fieldType == SVG_Transform_Rotate_datatype) {
  5519. return svg_point_angle_muladd(alpha, (SVG_Point_Angle*)a->far_ptr, beta, (SVG_Point_Angle*)b->far_ptr, (SVG_Point_Angle*)c->far_ptr);
  5520. } else {
  5521. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] matrix operations not supported\n"));
  5522. return GF_NOT_SUPPORTED;
  5523. }
  5524. case SVG_Transform_SkewX_datatype:
  5525. if (b->fieldType == SVG_Transform_SkewX_datatype) {
  5526. *(Fixed*)c->far_ptr = gf_mulfix(alpha, *(Fixed*)a->far_ptr) + gf_mulfix(beta, *(Fixed*)b->far_ptr);
  5527. return GF_OK;
  5528. } else {
  5529. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] matrix operations not supported\n"));
  5530. return GF_NOT_SUPPORTED;
  5531. }
  5532. case SVG_Transform_SkewY_datatype:
  5533. if (b->fieldType == SVG_Transform_SkewY_datatype) {
  5534. *(Fixed*)c->far_ptr = gf_mulfix(alpha, *(Fixed*)a->far_ptr) + gf_mulfix(beta, *(Fixed*)b->far_ptr);
  5535. return GF_OK;
  5536. } else {
  5537. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] matrix operations not supported\n"));
  5538. return GF_NOT_SUPPORTED;
  5539. }
  5540. case DOM_String_datatype:
  5541. {
  5542. u32 len;
  5543. char *res;
  5544. SVG_String *s_a = (SVG_String *)a->far_ptr;
  5545. SVG_String *s_b = (SVG_String *)b->far_ptr;
  5546. u32 len_a = (u32) strlen(*s_a);
  5547. u32 len_b = (u32) strlen(*s_b);
  5548. len_a = FIX2INT(alpha * len_a);
  5549. len_b = FIX2INT(beta * len_b);
  5550. len = len_a + len_b + 1;
  5551. res = (char*)gf_malloc(sizeof(char) * len);
  5552. memcpy(res, *s_a, len_a);
  5553. memcpy(res+len_a, *s_b, len_b);
  5554. res[len-1] = 0;
  5555. s_a = (SVG_String*)c->far_ptr;
  5556. if (*s_a) gf_free(*s_a);
  5557. *s_a = res;
  5558. }
  5559. break;
  5560. case LASeR_Size_datatype:
  5561. laser_size_muladd(alpha, (LASeR_Size*)a->far_ptr, beta, (LASeR_Size*)b->far_ptr, (LASeR_Size*)c->far_ptr);
  5562. break;
  5563. /* Keyword types */
  5564. case SVG_Boolean_datatype:
  5565. case SVG_FillRule_datatype:
  5566. case SVG_StrokeLineJoin_datatype:
  5567. case SVG_StrokeLineCap_datatype:
  5568. case SVG_FontStyle_datatype:
  5569. case SVG_FontWeight_datatype:
  5570. case SVG_FontVariant_datatype:
  5571. case SVG_TextAnchor_datatype:
  5572. case SVG_Display_datatype:
  5573. case SVG_Visibility_datatype:
  5574. case SVG_GradientUnit_datatype:
  5575. case SVG_PreserveAspectRatio_datatype:
  5576. case XML_Space_datatype:
  5577. case XMLEV_Propagate_datatype:
  5578. case XMLEV_DefaultAction_datatype:
  5579. case XMLEV_Phase_datatype:
  5580. case SMIL_SyncBehavior_datatype:
  5581. case SMIL_SyncTolerance_datatype:
  5582. case SMIL_AttributeType_datatype:
  5583. case SMIL_CalcMode_datatype:
  5584. case SMIL_Additive_datatype:
  5585. case SMIL_Accumulate_datatype:
  5586. case SMIL_Restart_datatype:
  5587. case SMIL_Fill_datatype:
  5588. case SVG_Overflow_datatype:
  5589. case SVG_ZoomAndPan_datatype:
  5590. case SVG_DisplayAlign_datatype:
  5591. case SVG_TextAlign_datatype:
  5592. case SVG_PointerEvents_datatype:
  5593. case SVG_RenderingHint_datatype:
  5594. case SVG_VectorEffect_datatype:
  5595. case SVG_PlaybackOrder_datatype:
  5596. case SVG_TimelineBegin_datatype:
  5597. case SVG_SpreadMethod_datatype:
  5598. case SVG_TransformType_datatype:
  5599. /* Unsupported types */
  5600. case SVG_ContentType_datatype:
  5601. case SVG_LanguageID_datatype:
  5602. case SVG_FontFamily_datatype:
  5603. case XMLRI_datatype:
  5604. case XMLRI_List_datatype:
  5605. case DOM_StringList_datatype:
  5606. case SVG_Clock_datatype:
  5607. case SVG_Focus_datatype:
  5608. case SVG_ID_datatype:
  5609. case SVG_GradientOffset_datatype:
  5610. case SMIL_KeyTimes_datatype:
  5611. case SMIL_KeyPoints_datatype:
  5612. case SMIL_KeySplines_datatype:
  5613. case SMIL_AnimateValue_datatype:
  5614. case SMIL_AnimateValues_datatype:
  5615. case SMIL_AttributeName_datatype:
  5616. case SMIL_Times_datatype:
  5617. case SMIL_Duration_datatype:
  5618. case SMIL_RepeatCount_datatype:
  5619. default:
  5620. GF_LOG(GF_LOG_WARNING, GF_LOG_INTERACT, ("[SVG Attributes] addition for attributes %s of type %s not supported\n", a->name, gf_svg_attribute_type_to_string(a->fieldType)));
  5621. return GF_NOT_SUPPORTED;
  5622. }
  5623. return GF_OK;
  5624. }
  5625. /* *a = *b, copy by value */
  5626. GF_EXPORT
  5627. GF_Err gf_svg_attributes_copy(GF_FieldInfo *a, GF_FieldInfo *b, Bool clamp)
  5628. {
  5629. if (!a->far_ptr || !b->far_ptr) return GF_BAD_PARAM;
  5630. switch (a->fieldType) {
  5631. /* Numeric types */
  5632. case SVG_Color_datatype:
  5633. *((SVG_Color *)a->far_ptr) = *((SVG_Color *)b->far_ptr);
  5634. if (clamp) svg_color_clamp((SVG_Color *)a->far_ptr);
  5635. break;
  5636. case SVG_Paint_datatype:
  5637. {
  5638. SVG_Paint *pa = (SVG_Paint *)a->far_ptr;
  5639. SVG_Paint *pb = (SVG_Paint *)b->far_ptr;
  5640. pa->type = pb->type;
  5641. if (pb->type == SVG_PAINT_URI) {
  5642. GF_FieldInfo tmp_a, tmp_b;
  5643. tmp_a.fieldType = tmp_b.fieldType = XMLRI_datatype;
  5644. tmp_a.far_ptr = &pa->iri;
  5645. tmp_b.far_ptr = &pb->iri;
  5646. gf_svg_attributes_copy(&tmp_a, &tmp_b, 0);
  5647. } else {
  5648. pa->color = pb->color;
  5649. }
  5650. return GF_OK;
  5651. }
  5652. break;
  5653. case SVG_Number_datatype:
  5654. case SVG_Length_datatype:
  5655. case SVG_Coordinate_datatype:
  5656. case SVG_FontSize_datatype:
  5657. *((SVG_Number *)a->far_ptr) = *((SVG_Number *)b->far_ptr);
  5658. break;
  5659. case SVG_ViewBox_datatype:
  5660. *((SVG_ViewBox *)a->far_ptr) = *((SVG_ViewBox *)b->far_ptr);
  5661. break;
  5662. case SVG_Points_datatype:
  5663. return svg_points_copy((GF_List**)a->far_ptr, (GF_List**)b->far_ptr);
  5664. case SVG_Numbers_datatype:
  5665. case SVG_Coordinates_datatype:
  5666. return svg_numbers_copy((GF_List**)a->far_ptr, (GF_List**)b->far_ptr);
  5667. case SVG_PathData_datatype:
  5668. return svg_path_copy((SVG_PathData*)a->far_ptr, (SVG_PathData*)b->far_ptr);
  5669. case SVG_StrokeDashArray_datatype:
  5670. return svg_dasharray_copy((SVG_StrokeDashArray*)a->far_ptr, (SVG_StrokeDashArray*)b->far_ptr);
  5671. case SVG_Motion_datatype:
  5672. gf_mx2d_copy(*(GF_Matrix2D *)a->far_ptr, *(GF_Matrix2D *)b->far_ptr);
  5673. return GF_OK;
  5674. case SVG_Transform_datatype:
  5675. switch (b->fieldType) {
  5676. case SVG_Transform_Translate_datatype:
  5677. gf_mx2d_init(((SVG_Transform *)a->far_ptr)->mat);
  5678. gf_mx2d_add_translation(&((SVG_Transform *)a->far_ptr)->mat, ((SVG_Point*)b->far_ptr)->x, ((SVG_Point*)b->far_ptr)->y);
  5679. break;
  5680. case SVG_Transform_Scale_datatype:
  5681. gf_mx2d_init(((SVG_Transform *)a->far_ptr)->mat);
  5682. gf_mx2d_add_scale(&((SVG_Transform *)a->far_ptr)->mat, ((SVG_Point*)b->far_ptr)->x, ((SVG_Point*)b->far_ptr)->y);
  5683. break;
  5684. case SVG_Transform_Rotate_datatype:
  5685. gf_mx2d_init(((SVG_Transform *)a->far_ptr)->mat);
  5686. gf_mx2d_add_rotation(&((SVG_Transform *)a->far_ptr)->mat, ((SVG_Point_Angle*)b->far_ptr)->x, ((SVG_Point_Angle*)b->far_ptr)->y, ((SVG_Point_Angle*)b->far_ptr)->angle);
  5687. break;
  5688. case SVG_Transform_SkewX_datatype:
  5689. gf_mx2d_init(((SVG_Transform *)a->far_ptr)->mat);
  5690. gf_mx2d_add_skew_x(&((SVG_Transform *)a->far_ptr)->mat, *(Fixed *)b->far_ptr);
  5691. break;
  5692. case SVG_Transform_SkewY_datatype:
  5693. gf_mx2d_init(((SVG_Transform *)a->far_ptr)->mat);
  5694. gf_mx2d_add_skew_y(&((SVG_Transform *)a->far_ptr)->mat, *(Fixed *)b->far_ptr);
  5695. break;
  5696. case SVG_Transform_datatype:
  5697. gf_mx2d_copy(((SVG_Transform *)a->far_ptr)->mat, ((SVG_Transform *)b->far_ptr)->mat);
  5698. break;
  5699. default:
  5700. GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[SVG Attributes] forbidden type of transform\n"));
  5701. return GF_NOT_SUPPORTED;
  5702. }
  5703. return GF_OK;
  5704. /* Keyword types */
  5705. case SVG_Boolean_datatype:
  5706. case SVG_FillRule_datatype:
  5707. case SVG_StrokeLineJoin_datatype:
  5708. case SVG_StrokeLineCap_datatype:
  5709. case SVG_FontStyle_datatype:
  5710. case SVG_FontWeight_datatype:
  5711. case SVG_FontVariant_datatype:
  5712. case SVG_TextAnchor_datatype:
  5713. case SVG_Display_datatype:
  5714. case SVG_Visibility_datatype:
  5715. case SVG_GradientUnit_datatype:
  5716. case SVG_PreserveAspectRatio_datatype:
  5717. case XML_Space_datatype:
  5718. case XMLEV_Propagate_datatype:
  5719. case XMLEV_DefaultAction_datatype:
  5720. case XMLEV_Phase_datatype:
  5721. case SMIL_SyncBehavior_datatype:
  5722. case SMIL_AttributeType_datatype:
  5723. case SMIL_CalcMode_datatype:
  5724. case SMIL_Additive_datatype:
  5725. case SMIL_Accumulate_datatype:
  5726. case SMIL_Restart_datatype:
  5727. case SMIL_Fill_datatype:
  5728. case SVG_Overflow_datatype:
  5729. case SVG_ZoomAndPan_datatype:
  5730. case SVG_DisplayAlign_datatype:
  5731. case SVG_TextAlign_datatype:
  5732. case SVG_PointerEvents_datatype:
  5733. case SVG_RenderingHint_datatype:
  5734. case SVG_VectorEffect_datatype:
  5735. case SVG_PlaybackOrder_datatype:
  5736. case SVG_TimelineBegin_datatype:
  5737. case SVG_TransformType_datatype:
  5738. case SVG_Focusable_datatype:
  5739. case SVG_FocusHighlight_datatype:
  5740. *(u8 *)a->far_ptr = *(u8 *)b->far_ptr;
  5741. return GF_OK;
  5742. case SMIL_SyncTolerance_datatype:
  5743. *(SMIL_SyncTolerance*)a->far_ptr = *(SMIL_SyncTolerance*)b->far_ptr;
  5744. return GF_OK;
  5745. /* Other types */
  5746. case SVG_ID_datatype:
  5747. case SVG_LanguageID_datatype:
  5748. case SVG_ContentType_datatype:
  5749. case DOM_String_datatype:
  5750. if (* (SVG_String *)a->far_ptr) gf_free(* (SVG_String *)a->far_ptr);
  5751. * (SVG_String *)a->far_ptr = *(SVG_String *)b->far_ptr ? gf_strdup(*(SVG_String *)b->far_ptr) : NULL;
  5752. return GF_OK;
  5753. case SVG_FontFamily_datatype:
  5754. ((SVG_FontFamily *)a->far_ptr)->type = ((SVG_FontFamily *)b->far_ptr)->type;
  5755. if ( ((SVG_FontFamily *)a->far_ptr)->value) gf_free( ((SVG_FontFamily *)a->far_ptr)->value );
  5756. ((SVG_FontFamily *)a->far_ptr)->value = (((SVG_FontFamily *)b->far_ptr)->value ? gf_strdup(((SVG_FontFamily *)b->far_ptr)->value) : NULL );
  5757. return GF_OK;
  5758. case XMLRI_datatype:
  5759. case XML_IDREF_datatype:
  5760. ((XMLRI *)a->far_ptr)->type = ((XMLRI *)b->far_ptr)->type;
  5761. if (((XMLRI *)a->far_ptr)->string) gf_free(((XMLRI *)a->far_ptr)->string);
  5762. if (((XMLRI *)b->far_ptr)->string) {
  5763. ((XMLRI *)a->far_ptr)->string = gf_strdup(((XMLRI *)b->far_ptr)->string);
  5764. } else {
  5765. ((XMLRI *)a->far_ptr)->string = gf_strdup("");
  5766. }
  5767. ((XMLRI *)a->far_ptr)->target = ((XMLRI *)b->far_ptr)->target;
  5768. if (((XMLRI *)a->far_ptr)->type == XMLRI_ELEMENTID) {
  5769. GF_Node *n = (GF_Node *) ((XMLRI *)b->far_ptr)->target;
  5770. /*TODO Check if assigning IRI from # scenegraph can happen*/
  5771. if (n) gf_node_register_iri(gf_node_get_graph(n), (XMLRI*)a->far_ptr);
  5772. }
  5773. return GF_OK;
  5774. case SVG_Focus_datatype:
  5775. {
  5776. ((SVG_Focus *)a->far_ptr)->type = ((SVG_Focus *)b->far_ptr)->type;
  5777. if ( ((SVG_Focus *)b->far_ptr)->target.string)
  5778. ((SVG_Focus *)a->far_ptr)->target.string = gf_strdup( ((SVG_Focus *)b->far_ptr)->target.string);
  5779. }
  5780. return GF_OK;
  5781. case SMIL_Times_datatype:
  5782. {
  5783. u32 i, count;
  5784. GF_List *dst = *(GF_List **)a->far_ptr;
  5785. GF_List *src = *(GF_List **)b->far_ptr;
  5786. while (gf_list_count(dst)) {
  5787. SMIL_Time *t = gf_list_get(dst, 0);
  5788. gf_list_rem(dst, 0);
  5789. gf_free(t);
  5790. }
  5791. count = gf_list_count(src);
  5792. for (i=0;i<count;i++) {
  5793. SMIL_Time *t2;
  5794. SMIL_Time *t = gf_list_get(src, i);
  5795. t2 = (SMIL_Time*)gf_malloc(sizeof(SMIL_Time));
  5796. memcpy(t2, t, sizeof(SMIL_Time));
  5797. gf_list_add(dst, t2);
  5798. }
  5799. }
  5800. return GF_OK;
  5801. case SMIL_AttributeName_datatype:
  5802. {
  5803. SMIL_AttributeName *saa = (SMIL_AttributeName *)a->far_ptr;
  5804. SMIL_AttributeName *sab = (SMIL_AttributeName *)b->far_ptr;
  5805. saa->tag = sab->tag;
  5806. saa->type = sab->type;
  5807. saa->name = sab->name ? gf_strdup(sab->name) : NULL;
  5808. }
  5809. break;
  5810. case SMIL_Duration_datatype:
  5811. {
  5812. SMIL_Duration *da = (SMIL_Duration*)a->far_ptr;
  5813. SMIL_Duration *db = (SMIL_Duration*)b->far_ptr;
  5814. da->type = db->type;
  5815. da->clock_value = db->clock_value;
  5816. }
  5817. break;
  5818. case SMIL_AnimateValue_datatype:
  5819. {
  5820. SMIL_AnimateValue *sa = (SMIL_AnimateValue*)a->far_ptr;
  5821. SMIL_AnimateValue *sb = (SMIL_AnimateValue*)b->far_ptr;
  5822. sa->type = sb->type;
  5823. if (sb->value) {
  5824. GF_FieldInfo ava, avb;
  5825. sa->value = gf_svg_create_attribute_value(sa->type);
  5826. ava.fieldIndex = avb.fieldIndex = 0;
  5827. ava.fieldType = avb.fieldType = sb->type;
  5828. ava.far_ptr = sa->value;
  5829. avb.far_ptr = sb->value;
  5830. gf_svg_attributes_copy(&ava, &avb, 0);
  5831. }
  5832. }
  5833. break;
  5834. /* Unsupported types */
  5835. case XMLRI_List_datatype:
  5836. case DOM_StringList_datatype:
  5837. case SVG_GradientOffset_datatype:
  5838. case SVG_Clock_datatype:
  5839. case SMIL_KeyTimes_datatype:
  5840. case SMIL_KeyPoints_datatype:
  5841. case SMIL_KeySplines_datatype:
  5842. case SMIL_AnimateValues_datatype:
  5843. case SMIL_RepeatCount_datatype:
  5844. default:
  5845. GF_LOG(GF_LOG_WARNING, GF_LOG_INTERACT, ("[SVG Attributes] copy of attributes %s of type %s not supported\n", a->name, gf_svg_attribute_type_to_string(a->fieldType)));
  5846. return GF_OK;
  5847. }
  5848. return GF_OK;
  5849. }
  5850. /* c = a + b */
  5851. GF_Err gf_svg_attributes_add(GF_FieldInfo *a, GF_FieldInfo *b, GF_FieldInfo *c, Bool clamp)
  5852. {
  5853. return gf_svg_attributes_muladd(FIX_ONE, a, FIX_ONE, b, c, clamp);
  5854. }
  5855. Bool gf_svg_attribute_is_interpolatable(u32 type)
  5856. {
  5857. switch (type) {
  5858. /* additive types which can really be interpolated */
  5859. case SVG_Color_datatype:
  5860. case SVG_Paint_datatype:
  5861. case SVG_Number_datatype:
  5862. case SVG_Length_datatype:
  5863. case SVG_Coordinate_datatype:
  5864. case SVG_FontSize_datatype:
  5865. case SVG_ViewBox_datatype:
  5866. case SVG_Points_datatype:
  5867. case SVG_Numbers_datatype:
  5868. case SVG_Coordinates_datatype:
  5869. case SVG_PathData_datatype:
  5870. case SVG_Motion_datatype:
  5871. case SVG_Transform_datatype:
  5872. case SVG_Transform_Translate_datatype:
  5873. case SVG_Transform_Scale_datatype:
  5874. case SVG_Transform_Rotate_datatype:
  5875. case SVG_Transform_SkewX_datatype:
  5876. case SVG_Transform_SkewY_datatype:
  5877. case LASeR_Size_datatype:
  5878. return 1;
  5879. }
  5880. return 0;
  5881. }
  5882. GF_Err gf_svg_attributes_interpolate(GF_FieldInfo *a, GF_FieldInfo *b, GF_FieldInfo *c, Fixed coef, Bool clamp)
  5883. {
  5884. if (!a->far_ptr || !b->far_ptr || !c->far_ptr) return GF_BAD_PARAM;
  5885. c->fieldType = a->fieldType;
  5886. switch (a->fieldType) {
  5887. /* additive types which can really be interpolated */
  5888. case SVG_Color_datatype:
  5889. case SVG_Paint_datatype:
  5890. case SVG_Number_datatype:
  5891. case SVG_Length_datatype:
  5892. case SVG_Coordinate_datatype:
  5893. case SVG_FontSize_datatype:
  5894. case SVG_ViewBox_datatype:
  5895. case SVG_Points_datatype:
  5896. case SVG_Numbers_datatype:
  5897. case SVG_Coordinates_datatype:
  5898. case SVG_PathData_datatype:
  5899. case SVG_Motion_datatype:
  5900. case SVG_Transform_datatype:
  5901. case SVG_Transform_Translate_datatype:
  5902. case SVG_Transform_Scale_datatype:
  5903. case SVG_Transform_Rotate_datatype:
  5904. case SVG_Transform_SkewX_datatype:
  5905. case SVG_Transform_SkewY_datatype:
  5906. case LASeR_Size_datatype:
  5907. return gf_svg_attributes_muladd(FIX_ONE-coef, a, coef, b, c, clamp);
  5908. /* discrete types: interpolation is the selection of one of the 2 values
  5909. using the coeff and a the 0.5 threshold */
  5910. /* Keyword types */
  5911. case SVG_Boolean_datatype:
  5912. case SVG_FillRule_datatype:
  5913. case SVG_StrokeLineJoin_datatype:
  5914. case SVG_StrokeLineCap_datatype:
  5915. case SVG_FontStyle_datatype:
  5916. case SVG_FontWeight_datatype:
  5917. case SVG_FontVariant_datatype:
  5918. case SVG_TextAnchor_datatype:
  5919. case SVG_Display_datatype:
  5920. case SVG_Visibility_datatype:
  5921. case SVG_GradientUnit_datatype:
  5922. case SVG_PreserveAspectRatio_datatype:
  5923. case SVG_TransformType_datatype:
  5924. case XML_Space_datatype:
  5925. case XMLEV_Propagate_datatype:
  5926. case XMLEV_DefaultAction_datatype:
  5927. case XMLEV_Phase_datatype:
  5928. case SMIL_SyncBehavior_datatype:
  5929. case SMIL_SyncTolerance_datatype:
  5930. case SMIL_AttributeType_datatype:
  5931. case SMIL_CalcMode_datatype:
  5932. case SMIL_Additive_datatype:
  5933. case SMIL_Accumulate_datatype:
  5934. case SMIL_Restart_datatype:
  5935. case SMIL_Fill_datatype:
  5936. case SVG_Overflow_datatype:
  5937. case SVG_ZoomAndPan_datatype:
  5938. case SVG_DisplayAlign_datatype:
  5939. case SVG_TextAlign_datatype:
  5940. case SVG_PointerEvents_datatype:
  5941. case SVG_RenderingHint_datatype:
  5942. case SVG_VectorEffect_datatype:
  5943. case SVG_PlaybackOrder_datatype:
  5944. case SVG_TimelineBegin_datatype:
  5945. /* Other non keyword types but which can still be discretely interpolated */
  5946. case DOM_String_datatype:
  5947. case SVG_ContentType_datatype:
  5948. case SVG_LanguageID_datatype:
  5949. case SVG_FontFamily_datatype:
  5950. case XMLRI_datatype:
  5951. case XMLRI_List_datatype:
  5952. case DOM_StringList_datatype:
  5953. case SVG_Clock_datatype:
  5954. case SVG_ID_datatype:
  5955. case SVG_GradientOffset_datatype:
  5956. case LASeR_Choice_datatype:
  5957. if (coef < FIX_ONE/2) {
  5958. gf_svg_attributes_copy(c, a, clamp);
  5959. } else {
  5960. gf_svg_attributes_copy(c, b, clamp);
  5961. }
  5962. return GF_OK;
  5963. /* Unsupported types */
  5964. case SMIL_KeyTimes_datatype:
  5965. case SMIL_KeyPoints_datatype:
  5966. case SMIL_KeySplines_datatype:
  5967. case SMIL_AnimateValue_datatype:
  5968. case SMIL_AnimateValues_datatype:
  5969. case SMIL_AttributeName_datatype:
  5970. case SMIL_Times_datatype:
  5971. case SMIL_Duration_datatype:
  5972. case SMIL_RepeatCount_datatype:
  5973. default:
  5974. GF_LOG(GF_LOG_WARNING, GF_LOG_INTERACT, ("[SVG Attributes] interpolation for attributes %s of type %s not supported\n", a->name, gf_svg_attribute_type_to_string(a->fieldType)));
  5975. return GF_OK;
  5976. }
  5977. return GF_OK;
  5978. }
  5979. Bool gf_svg_is_current_color(GF_FieldInfo *a)
  5980. {
  5981. switch (a->fieldType) {
  5982. case SVG_Color_datatype:
  5983. return (((SVG_Color *)a->far_ptr)->type == SVG_COLOR_CURRENTCOLOR);
  5984. break;
  5985. case SVG_Paint_datatype:
  5986. if ( ((SVG_Paint *)a->far_ptr)->type == SVG_PAINT_COLOR) {
  5987. return (((SVG_Paint *)a->far_ptr)->color.type == SVG_COLOR_CURRENTCOLOR);
  5988. } else {
  5989. return 0;
  5990. }
  5991. break;
  5992. }
  5993. return 0;
  5994. }
  5995. char *gf_svg_attribute_type_to_string(u32 att_type)
  5996. {
  5997. switch (att_type) {
  5998. case SVG_FillRule_datatype: return "FillRule";
  5999. case SVG_StrokeLineJoin_datatype: return "StrokeLineJoin";
  6000. case SVG_StrokeLineCap_datatype: return "StrokeLineCap";
  6001. case SVG_FontStyle_datatype: return "FontStyle";
  6002. case SVG_FontWeight_datatype: return "FontWeight";
  6003. case SVG_FontVariant_datatype: return "FontVariant";
  6004. case SVG_TextAnchor_datatype: return "TextAnchor";
  6005. case SVG_TransformType_datatype: return "TransformType";
  6006. case SVG_Display_datatype: return "Display";
  6007. case SVG_Visibility_datatype: return "Visibility";
  6008. case SVG_Overflow_datatype: return "Overflow";
  6009. case SVG_ZoomAndPan_datatype: return "ZoomAndPan";
  6010. case SVG_DisplayAlign_datatype: return "DisplayAlign";
  6011. case SVG_PointerEvents_datatype: return "PointerEvents";
  6012. case SVG_RenderingHint_datatype: return "RenderingHint";
  6013. case SVG_VectorEffect_datatype: return "VectorEffect";
  6014. case SVG_PlaybackOrder_datatype: return "PlaybackOrder";
  6015. case SVG_TimelineBegin_datatype: return "TimelineBegin";
  6016. case XML_Space_datatype: return "XML_Space";
  6017. case XMLEV_Propagate_datatype: return "XMLEV_Propagate";
  6018. case XMLEV_DefaultAction_datatype: return "XMLEV_DefaultAction";
  6019. case XMLEV_Phase_datatype: return "XMLEV_Phase";
  6020. case SMIL_SyncBehavior_datatype: return "SMIL_SyncBehavior";
  6021. case SMIL_SyncTolerance_datatype: return "SMIL_SyncTolerance";
  6022. case SMIL_AttributeType_datatype: return "SMIL_AttributeType";
  6023. case SMIL_CalcMode_datatype: return "SMIL_CalcMode";
  6024. case SMIL_Additive_datatype: return "SMIL_Additive";
  6025. case SMIL_Accumulate_datatype: return "SMIL_Accumulate";
  6026. case SMIL_Restart_datatype: return "SMIL_Restart";
  6027. case SMIL_Fill_datatype: return "SMIL_Fill";
  6028. case SVG_GradientUnit_datatype: return "GradientUnit";
  6029. case SVG_InitialVisibility_datatype:return "InitialVisibility";
  6030. case SVG_FocusHighlight_datatype: return "FocusHighlight";
  6031. case SVG_Overlay_datatype: return "Overlay";
  6032. case SVG_TransformBehavior_datatype:return "TransformBehavior";
  6033. case SVG_SpreadMethod_datatype: return "SpreadMethod";
  6034. case SVG_TextAlign_datatype: return "TextAlign";
  6035. case SVG_Number_datatype: return "Number";
  6036. case SVG_FontSize_datatype: return "FontSize";
  6037. case SVG_Length_datatype: return "Length";
  6038. case SVG_Coordinate_datatype: return "Coordinate";
  6039. case SVG_Rotate_datatype: return "Rotate";
  6040. case SVG_Numbers_datatype: return "Numbers";
  6041. case SVG_Points_datatype: return "Points";
  6042. case SVG_Coordinates_datatype: return "Coordinates";
  6043. case DOM_StringList_datatype: return "StringList";
  6044. case XMLRI_List_datatype: return "ListOfIRI";
  6045. case SMIL_KeyTimes_datatype: return "SMIL_KeyTimes";
  6046. case SMIL_KeySplines_datatype: return "SMIL_KeySplines";
  6047. case SMIL_KeyPoints_datatype: return "SMIL_KeyPoints";
  6048. case SMIL_Times_datatype: return "SMIL_Times";
  6049. case SMIL_AnimateValue_datatype: return "SMIL_AnimateValue";
  6050. case SMIL_AnimateValues_datatype: return "SMIL_AnimateValues";
  6051. case SMIL_Duration_datatype: return "SMIL_Duration";
  6052. case SMIL_RepeatCount_datatype: return "SMIL_RepeatCount";
  6053. case SMIL_AttributeName_datatype: return "SMIL_AttributeName";
  6054. case SVG_Boolean_datatype: return "Boolean";
  6055. case SVG_Color_datatype: return "Color";
  6056. case SVG_Paint_datatype: return "Paint";
  6057. case SVG_PathData_datatype: return "PathData";
  6058. case SVG_FontFamily_datatype: return "FontFamily";
  6059. case SVG_ID_datatype: return "ID";
  6060. case XMLRI_datatype: return "IRI";
  6061. case XML_IDREF_datatype: return "IDREF";
  6062. case SVG_StrokeDashArray_datatype: return "StrokeDashArray";
  6063. case SVG_PreserveAspectRatio_datatype:return "PreserveAspectRatio";
  6064. case SVG_ViewBox_datatype: return "ViewBox";
  6065. case SVG_GradientOffset_datatype: return "GradientOffset";
  6066. case SVG_Focus_datatype : return "Focus";
  6067. case SVG_Clock_datatype : return "Clock";
  6068. case DOM_String_datatype : return "String";
  6069. case SVG_ContentType_datatype: return "ContentType";
  6070. case SVG_LanguageID_datatype: return "LanguageID";
  6071. case XMLEV_Event_datatype: return "XMLEV_Event";
  6072. case SVG_Motion_datatype: return "Motion";
  6073. case SVG_Transform_datatype: return "Transform";
  6074. case SVG_Transform_Translate_datatype:return "Translate";
  6075. case SVG_Transform_Scale_datatype: return "Scale";
  6076. case SVG_Transform_SkewX_datatype: return "SkewX";
  6077. case SVG_Transform_SkewY_datatype: return "SkewY";
  6078. case SVG_Transform_Rotate_datatype: return "Rotate";
  6079. case LASeR_Choice_datatype: return "LASeR_Choice";
  6080. case LASeR_Size_datatype: return "LASeR_Size";
  6081. default: return "UnknownType";
  6082. }
  6083. }
  6084. #endif /*GPAC_DISABLE_SVG*/