Coverage Report

Created: 2025-12-14 06:51

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