LCOV - code coverage report
Current view: top level - scenegraph - svg_attributes.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1955 3132 62.4 %
Date: 2021-04-29 23:48:07 Functions: 93 114 81.6 %

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

Generated by: LCOV version 1.13