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