| /* | |
| * GPAC Multimedia Framework | |
| * | |
| * Authors: Cyril Concolato, Jean Le Feuvre | |
| * Copyright (c) Telecom ParisTech 2004-2026 | |
| * All rights reserved | |
| * | |
| * This file is part of GPAC / SVG Loader module | |
| * | |
| * GPAC is free software; you can redistribute it and/or modify | |
| * it under the terms of the GNU Lesser General Public License as published by | |
| * the Free Software Foundation; either version 2, or (at your option) | |
| * any later version. | |
| * | |
| * GPAC is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; see the file COPYING. If not, write to | |
| * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
| * | |
| */ | |
| #include <gpac/base_coding.h> | |
| #include <gpac/color.h> | |
| #include <gpac/events.h> | |
| #include <gpac/nodes_svg.h> | |
| #ifndef GPAC_DISABLE_SVG | |
| #include <gpac/internal/scenegraph_dev.h> | |
| #define DUMP_COORDINATES 1 | |
| static const struct dom_event_def { | |
| GF_EventType event; | |
| const char *name; | |
| GF_DOMEventCategory category; | |
| } defined_dom_events [] = | |
| { | |
| { GF_EVENT_ABORT, "abort", GF_DOM_EVENT_DOM }, | |
| { GF_EVENT_ERROR, "error", GF_DOM_EVENT_DOM }, | |
| { GF_EVENT_LOAD, "load", GF_DOM_EVENT_DOM }, | |
| { GF_EVENT_UNLOAD, "unload", GF_DOM_EVENT_DOM }, | |
| /*focus - we differentiate from UI/key events to avoid browing focus if no listener is on place*/ | |
| { GF_EVENT_FOCUSIN, "DOMFocusIn", GF_DOM_EVENT_FOCUS }, | |
| { GF_EVENT_FOCUSIN, "focusin", GF_DOM_EVENT_FOCUS }, | |
| { GF_EVENT_FOCUSOUT, "DOMFocusOut", GF_DOM_EVENT_FOCUS }, | |
| { GF_EVENT_FOCUSOUT, "focusout", GF_DOM_EVENT_FOCUS }, | |
| { GF_EVENT_CHANGE, "change", GF_DOM_EVENT_FOCUS }, | |
| { GF_EVENT_FOCUS, "focus", GF_DOM_EVENT_FOCUS }, | |
| { GF_EVENT_BLUR, "blur", GF_DOM_EVENT_FOCUS }, | |
| /*key events*/ | |
| { GF_EVENT_KEYDOWN, "keydown", GF_DOM_EVENT_KEY }, | |
| { GF_EVENT_KEYDOWN, "accesskey", GF_DOM_EVENT_KEY }, | |
| { GF_EVENT_KEYDOWN, "keypress", GF_DOM_EVENT_KEY }, | |
| { GF_EVENT_KEYUP, "keyup", GF_DOM_EVENT_KEY }, | |
| { GF_EVENT_LONGKEYPRESS, "longaccesskey", GF_DOM_EVENT_KEY }, | |
| { GF_EVENT_CLICK, "click", GF_DOM_EVENT_MOUSE }, | |
| { GF_EVENT_DBLCLICK, "dblclick", GF_DOM_EVENT_MOUSE }, | |
| { GF_EVENT_MOUSEDOWN, "mousedown", GF_DOM_EVENT_MOUSE }, | |
| { GF_EVENT_MOUSEMOVE, "mousemove", GF_DOM_EVENT_MOUSE }, | |
| { GF_EVENT_MOUSEOUT, "mouseout", GF_DOM_EVENT_MOUSE }, | |
| { GF_EVENT_MOUSEOVER, "mouseover", GF_DOM_EVENT_MOUSE }, | |
| { GF_EVENT_MOUSEUP, "mouseup", GF_DOM_EVENT_MOUSE }, | |
| { GF_EVENT_MOUSEWHEEL, "wheel", GF_DOM_EVENT_MOUSE }, | |
| { GF_EVENT_MOUSEWHEEL, "SVGMousewheel", GF_DOM_EVENT_MOUSE }, | |
| /*activate is not a basic DOM but a MOUSE and KEY event*/ | |
| { GF_EVENT_ACTIVATE, "activate", GF_DOM_EVENT_MOUSE | GF_DOM_EVENT_KEY }, | |
| { GF_EVENT_ACTIVATE, "DOMActivate", GF_DOM_EVENT_MOUSE | GF_DOM_EVENT_KEY }, | |
| /*text events*/ | |
| { GF_EVENT_TEXTINPUT, "textInput", GF_DOM_EVENT_TEXT }, | |
| { GF_EVENT_TEXTSELECT, "select", GF_DOM_EVENT_TEXT }, | |
| /*SMIL events*/ | |
| { GF_EVENT_BEGIN, "begin", GF_DOM_EVENT_FAKE }, | |
| { GF_EVENT_BEGIN_EVENT, "beginEvent", GF_DOM_EVENT_SMIL }, | |
| { GF_EVENT_END, "end", GF_DOM_EVENT_FAKE }, | |
| { GF_EVENT_END_EVENT, "endEvent", GF_DOM_EVENT_SMIL }, | |
| { GF_EVENT_REPEAT, "repeat", GF_DOM_EVENT_FAKE }, | |
| { GF_EVENT_REPEAT_EVENT, "repeatEvent", GF_DOM_EVENT_SMIL }, | |
| /*all SVG/HTML/... UI events*/ | |
| { GF_EVENT_RESIZE, "resize", GF_DOM_EVENT_UI }, | |
| { GF_EVENT_SCROLL, "scroll", GF_DOM_EVENT_UI }, | |
| { GF_EVENT_ZOOM, "zoom", GF_DOM_EVENT_UI }, | |
| { GF_EVENT_LOAD, "SVGLoad", GF_DOM_EVENT_DOM }, | |
| { GF_EVENT_RESIZE, "SVGResize", GF_DOM_EVENT_UI }, | |
| { GF_EVENT_SCROLL, "SVGScroll", GF_DOM_EVENT_UI }, | |
| { GF_EVENT_ZOOM, "SVGZoom", GF_DOM_EVENT_UI }, | |
| /*mutation events and DCCI*/ | |
| { GF_EVENT_TREE_MODIFIED, "DOMSubtreeModified", GF_DOM_EVENT_MUTATION }, | |
| { GF_EVENT_NODE_INSERTED, "DOMNodeInserted", GF_DOM_EVENT_MUTATION }, | |
| { GF_EVENT_NODE_REMOVED, "DOMNodeRemoved", GF_DOM_EVENT_MUTATION }, | |
| { GF_EVENT_NODE_REMOVED_DOC, "DOMNodeRemovedFromDocument", GF_DOM_EVENT_MUTATION }, | |
| { GF_EVENT_NODE_INSERTED_DOC, "DOMNodeInsertedIntoDocument", GF_DOM_EVENT_MUTATION }, | |
| { GF_EVENT_ATTR_MODIFIED, "DOMAttrModified", GF_DOM_EVENT_MUTATION }, | |
| { GF_EVENT_CHAR_DATA_MODIFIED, "DOMCharacterDataModified", GF_DOM_EVENT_MUTATION }, | |
| { GF_EVENT_NODE_NAME_CHANGED, "DOMElementNameChanged", GF_DOM_EVENT_MUTATION }, | |
| { GF_EVENT_ATTR_NAME_CHANGED, "DOMAttributeNameChanged", GF_DOM_EVENT_MUTATION }, | |
| { GF_EVENT_DCCI_PROP_CHANGE, "DCCI-prop-change", GF_DOM_EVENT_MUTATION }, | |
| /*LASeR events - some events are attached to other categorues*/ | |
| { GF_EVENT_ACTIVATED, "activatedEvent", GF_DOM_EVENT_LASER }, | |
| { GF_EVENT_DEACTIVATED, "deactivatedEvent", GF_DOM_EVENT_LASER }, | |
| { GF_EVENT_EXECUTION_TIME, "executionTime", GF_DOM_EVENT_FAKE }, | |
| { GF_EVENT_PAUSE, "pause", GF_DOM_EVENT_SMIL }, | |
| { GF_EVENT_PAUSED_EVENT, "pausedEvent", GF_DOM_EVENT_SMIL }, | |
| { GF_EVENT_PLAY, "play", GF_DOM_EVENT_SMIL }, | |
| { GF_EVENT_RESUME_EVENT, "resumedEvent", GF_DOM_EVENT_SMIL }, | |
| { GF_EVENT_REPEAT_KEY, "repeatKey", GF_DOM_EVENT_KEY }, | |
| { GF_EVENT_SHORT_ACCESSKEY, "shortAccessKey", GF_DOM_EVENT_KEY }, | |
| /*LASeR unofficial events*/ | |
| { GF_EVENT_BATTERY, "battery", GF_DOM_EVENT_LASER }, | |
| { GF_EVENT_CPU, "cpu", GF_DOM_EVENT_LASER }, | |
| { GF_EVENT_MEDIA_SETUP_BEGIN, "setupbegin", GF_DOM_EVENT_MEDIA}, | |
| { GF_EVENT_MEDIA_SETUP_DONE, "setupdone", GF_DOM_EVENT_MEDIA}, | |
| { GF_EVENT_MEDIA_LOAD_START, "loadstart", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_LOAD_DONE, "loaddone", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_PROGRESS, "progress", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_SUSPEND, "suspend", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_ABORT, "abort", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_ERROR, "error", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_EMPTIED, "emptied", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_STALLED, "stalled", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_LOADED_METADATA, "loadedmetadata", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_LODADED_DATA, "loadeddata", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_CANPLAY, "canplay", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_CANPLAYTHROUGH, "canplaythrough", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_PLAYING, "playing", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_WAITING, "waiting", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_SEEKING, "seeking", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_SEEKED, "seeked", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_ENDED, "ended", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_DURATION_CHANGED, "durationchanged", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_TIME_UPDATE, "timeupdate", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_PLAY, "play", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_PAUSE, "pause", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_RATECHANGE, "ratechange", GF_DOM_EVENT_MEDIA }, | |
| { GF_EVENT_MEDIA_VOLUME_CHANGED, "volumechange", GF_DOM_EVENT_MEDIA }, | |
| #if 0 | |
| /* Media Source Events */ | |
| { GF_EVENT_HTML_MSE_SOURCE_OPEN, "sourceopen", GF_DOM_EVENT_MEDIASOURCE }, | |
| { GF_EVENT_HTML_MSE_SOURCE_ENDED, "sourceended", GF_DOM_EVENT_MEDIASOURCE }, | |
| { GF_EVENT_HTML_MSE_SOURCE_CLOSE, "sourceclose", GF_DOM_EVENT_MEDIASOURCE }, | |
| { GF_EVENT_HTML_MSE_UPDATE_START, "updatestart", GF_DOM_EVENT_MEDIASOURCE }, | |
| { GF_EVENT_HTML_MSE_UPDATE, "update", GF_DOM_EVENT_MEDIASOURCE }, | |
| { GF_EVENT_HTML_MSE_UPDATE_END, "updateend", GF_DOM_EVENT_MEDIASOURCE }, | |
| { GF_EVENT_HTML_MSE_UPDATE_ERROR, "error", GF_DOM_EVENT_MEDIASOURCE }, | |
| { GF_EVENT_HTML_MSE_UPDATE_ABORT, "abort", GF_DOM_EVENT_MEDIASOURCE }, | |
| { GF_EVENT_HTML_MSE_ADD_SOURCE_BUFFER, "addsourcebuffer", GF_DOM_EVENT_MEDIASOURCE }, | |
| { GF_EVENT_HTML_MSE_REMOVE_SOURCE_BUFFER, "removesourcebuffer", GF_DOM_EVENT_MEDIASOURCE }, | |
| #endif | |
| /*GPAC internals*/ | |
| { GF_EVENT_SCENE_ATTACHED, "gpac_scene_attached", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_SCENE_SIZE, "gpac_scene_size", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_VP_RESIZE, "gpac_vp_changed", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_ADDON_DETECTED, "gpac_addon_found", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_MAIN_ADDON_STATE, "gpac_main_addon_state", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_STREAMLIST, "gpac_streamlist_changed", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_TIMESHIFT_DEPTH, "gpac_timeshift_depth_changed", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_CODEC_SLOW, "gpac_codec_slow", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_CODEC_OK, "gpac_codec_ok", GF_DOM_EVENT_GPAC}, | |
| #if 0 | |
| { GF_EVENT_DBLCLICK, "gpac_dbl_click", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_SIZE, "gpac_size_changed", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_SHOWHIDE, "gpac_show_hide", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_SET_CURSOR, "gpac_set_cursor", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_SET_CAPTION, "gpac_set_caption", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_MOVE, "gpac_move", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_REFRESH, "gpac_refresh", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_QUIT, "gpac_quit", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_PASTE_TEXT, "gpac_paste", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_COPY_TEXT, "gpac_copy", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_CONNECT, "gpac_on_connect", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_DURATION, "gpac_on_duration", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_EOS, "gpac_eos", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_AUTHORIZATION, "gpac_authorization", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_NAVIGATE, "gpac_navigate", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_NAVIGATE_INFO, "gpac_navigate_info", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_MESSAGE, "gpac_on_message", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_PROGRESS, "gpac_on_progress", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_VIEWPOINTS, "gpac_viewpoints_changed", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_METADATA, "gpac_metadata_changed", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_MIGRATE, "gpac_session_migrate", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_DISCONNECT, "gpac_request_disconnect", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_RESOLUTION, "gpac_resolution_changed", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_DROPFILE, "gpac_dropfile", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_TEXT_EDITING_START, "gpac_textedit_start", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_TEXT_EDITING_END, "gpac_textedit_end", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_QUALITY_SWITCHED, "gpac_quality_switch", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_TIMESHIFT_OVERFLOW, "gpac_timeshift_overflow", GF_DOM_EVENT_GPAC}, | |
| { GF_EVENT_TIMESHIFT_UPDATE, "gpac_timeshift_update", GF_DOM_EVENT_GPAC} | |
| { GF_EVENT_TIMESHIFT_UNDERRUN, "gpac_timeshift_underrun", GF_DOM_EVENT_GPAC} | |
| #endif | |
| }; | |
| #ifdef WIN32 | |
| /** In order to have the same representation of laser/svg media on unix and windows | |
| * we have to force windows to use the same rounding method as the glibc. | |
| * See: http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html | |
| * "The low-order digit shall be rounded in an implementation-defined manner." | |
| * glibc uses the IEEE-754 recommended half-to-even method while windows rounds half up. | |
| * When windows finally implements HTE rounding we'll be able to remove the convoluted functions below | |
| **/ | |
| int is_even(double d) { | |
| double int_part; | |
| modf(d / 2.0, &int_part); | |
| return 2.0 * int_part == d; | |
| } | |
| double round_ieee_754(double d) { | |
| double i = floor(d); | |
| d -= i; | |
| if (d < 0.5) | |
| return i; | |
| if (d > 0.5) | |
| return i + 1.0; | |
| if (is_even(i)) | |
| return i; | |
| return i + 1.0; | |
| } | |
| double round_float_hte(double value, int digits) | |
| { | |
| if (value) { | |
| int missing_digits = digits - (int)log10(fabs(value)) - (fabs(value) > 1.f); | |
| double exp = pow(10.f, missing_digits > 0 ? missing_digits : 0); | |
| value *= exp; | |
| value = round_ieee_754(value); | |
| value /= exp; | |
| } | |
| return value; | |
| }; | |
| #define _FIX2FLT(x) (round_float_hte(FIX2FLT(x),6)) | |
| #else | |
| #define _FIX2FLT(x) FIX2FLT(x) | |
| #endif | |
| GF_EXPORT | |
| GF_EventType gf_dom_event_type_by_name(const char *name) | |
| { | |
| u32 i, count; | |
| count = sizeof(defined_dom_events) / sizeof(struct dom_event_def); | |
| if (!name) return GF_EVENT_UNKNOWN; | |
| if ((name[0]=='o') && (name[1]=='n')) name += 2; | |
| for (i=0; i<count; i++) { | |
| if (!strcmp(name, defined_dom_events[i].name)) | |
| return defined_dom_events[i].event; | |
| } | |
| return GF_EVENT_UNKNOWN; | |
| } | |
| GF_EXPORT | |
| const char *gf_dom_event_get_name(GF_EventType type) | |
| { | |
| u32 i, count; | |
| count = sizeof(defined_dom_events) / sizeof(struct dom_event_def); | |
| for (i=0; i<count; i++) { | |
| if (defined_dom_events[i].event == type) | |
| return defined_dom_events[i].name; | |
| } | |
| return "unknown"; | |
| } | |
| GF_DOMEventCategory gf_dom_event_get_category(GF_EventType type) | |
| { | |
| u32 i, count; | |
| count = sizeof(defined_dom_events) / sizeof(struct dom_event_def); | |
| for (i=0; i<count; i++) { | |
| if (defined_dom_events[i].event == type) | |
| return defined_dom_events[i].category; | |
| } | |
| return GF_DOM_EVENT_UNKNOWN_CATEGORY; | |
| } | |
| static const struct predef_keyid { | |
| GF_KeyCode key_code; | |
| const char *name; | |
| const char *friendly_name; | |
| } predefined_key_identifiers[] = | |
| { | |
| { GF_KEY_ACCEPT, "Accept" }, | |
| { GF_KEY_AGAIN, "Again" }, | |
| { GF_KEY_ALLCANDIDATES, "AllCandidates" }, | |
| { GF_KEY_ALPHANUM, "Alphanumeric" }, | |
| { GF_KEY_ALT, "Alt" }, | |
| { GF_KEY_ALTGRAPH, "AltGraph" }, | |
| { GF_KEY_APPS, "Apps" }, | |
| { GF_KEY_ATTN, "Attn" }, | |
| { GF_KEY_BROWSERBACK, "BrowserBack" }, | |
| { GF_KEY_BROWSERFAVORITES, "BrowserFavorites" }, | |
| { GF_KEY_BROWSERFORWARD, "BrowserForward" }, | |
| { GF_KEY_BROWSERHOME, "BrowserHome" }, | |
| { GF_KEY_BROWSERREFRESH, "BrowserRefresh" }, | |
| { GF_KEY_BROWSERSEARCH, "BrowserSearch" }, | |
| { GF_KEY_BROWSERSTOP, "BrowserStop" }, | |
| { GF_KEY_CAPSLOCK, "CapsLock" }, | |
| { GF_KEY_CLEAR, "Clear" }, | |
| { GF_KEY_CODEINPUT, "CodeInput" }, | |
| { GF_KEY_COMPOSE, "Compose" }, | |
| { GF_KEY_CONTROL, "Control" }, | |
| { GF_KEY_CRSEL, "Crsel" }, | |
| { GF_KEY_CONVERT, "Convert" }, | |
| { GF_KEY_COPY, "Copy" }, | |
| { GF_KEY_CUT, "Cut" }, | |
| { GF_KEY_DOWN, "Down" }, | |
| { GF_KEY_END, "End" }, | |
| { GF_KEY_ENTER, "Enter" }, | |
| { GF_KEY_ERASEEOF, "EraseEof" }, | |
| { GF_KEY_EXECUTE, "Execute" }, | |
| { GF_KEY_EXSEL, "Exsel" }, | |
| { GF_KEY_F1, "F1" }, | |
| { GF_KEY_F2, "F2" }, | |
| { GF_KEY_F3, "F3" }, | |
| { GF_KEY_F4, "F4" }, | |
| { GF_KEY_F5, "F5" }, | |
| { GF_KEY_F6, "F6" }, | |
| { GF_KEY_F7, "F7" }, | |
| { GF_KEY_F8, "F8" }, | |
| { GF_KEY_F9, "F9" }, | |
| { GF_KEY_F10, "F10" }, | |
| { GF_KEY_F11, "F11" }, | |
| { GF_KEY_F12, "F12" }, | |
| { GF_KEY_F13, "F13" }, | |
| { GF_KEY_F14, "F14" }, | |
| { GF_KEY_F15, "F15" }, | |
| { GF_KEY_F16, "F16" }, | |
| { GF_KEY_F17, "F17" }, | |
| { GF_KEY_F18, "F18" }, | |
| { GF_KEY_F19, "F19" }, | |
| { GF_KEY_F20, "F20" }, | |
| { GF_KEY_F21, "F21" }, | |
| { GF_KEY_F22, "F22" }, | |
| { GF_KEY_F23, "F23" }, | |
| { GF_KEY_F24, "F24" }, | |
| { GF_KEY_FINALMODE, "FinalMode" }, | |
| { GF_KEY_FIND, "Find" }, | |
| { GF_KEY_FULLWIDTH, "FullWidth" }, | |
| { GF_KEY_HALFWIDTH, "HalfWidth" }, | |
| { GF_KEY_HANGULMODE, "HangulMode" }, | |
| { GF_KEY_HANJAMODE, "HanjaMode" }, | |
| { GF_KEY_HELP, "Help" }, | |
| { GF_KEY_HIRAGANA, "Hiragana" }, | |
| { GF_KEY_HOME, "Home" }, | |
| { GF_KEY_INSERT, "Insert" }, | |
| { GF_KEY_JAPANESEHIRAGANA, "JapaneseHiragana" }, | |
| { GF_KEY_JAPANESEKATAKANA, "JapaneseKatakana" }, | |
| { GF_KEY_JAPANESEROMAJI, "JapaneseRomaji" }, | |
| { GF_KEY_JUNJAMODE, "JunjaMode" }, | |
| { GF_KEY_KANAMODE, "KanaMode" }, | |
| { GF_KEY_KANJIMODE, "KanjiMode" }, | |
| { GF_KEY_KATAKANA, "Katakana" }, | |
| { GF_KEY_LAUNCHAPPLICATION1, "LaunchApplication1" }, | |
| { GF_KEY_LAUNCHAPPLICATION2, "LaunchApplication2" }, | |
| { GF_KEY_LAUNCHMAIL, "LaunchMail" }, | |
| { GF_KEY_LEFT, "Left" }, | |
| { GF_KEY_META, "Meta" }, | |
| { GF_KEY_MEDIANEXTTRACK, "MediaNextTrack" }, | |
| { GF_KEY_MEDIAPLAYPAUSE, "MediaPlayPause" }, | |
| { GF_KEY_MEDIAPREVIOUSTRACK, "MediaPreviousTrack" }, | |
| { GF_KEY_MEDIASTOP, "MediaStop" }, | |
| { GF_KEY_MODECHANGE, "ModeChange" }, | |
| { GF_KEY_NONCONVERT, "Nonconvert" }, | |
| { GF_KEY_NUMLOCK, "NumLock" }, | |
| { GF_KEY_PAGEDOWN, "PageDown" }, | |
| { GF_KEY_PAGEUP, "PageUp" }, | |
| { GF_KEY_PASTE, "Paste" }, | |
| { GF_KEY_PAUSE, "Pause" }, | |
| { GF_KEY_PLAY, "Play" }, | |
| { GF_KEY_PREVIOUSCANDIDATE, "PreviousCandidate" }, | |
| { GF_KEY_PRINTSCREEN, "PrintScreen" }, | |
| { GF_KEY_PROCESS, "Process" }, | |
| { GF_KEY_PROPS, "Props" }, | |
| { GF_KEY_RIGHT, "Right" }, | |
| { GF_KEY_ROMANCHARACTERS, "RomanCharacters" }, | |
| { GF_KEY_SCROLL, "Scroll" }, | |
| { GF_KEY_SELECT, "Select" }, | |
| { GF_KEY_SELECTMEDIA, "SelectMedia" }, | |
| { GF_KEY_SHIFT, "Shift" }, | |
| { GF_KEY_STOP, "Stop" }, | |
| { GF_KEY_UP, "Up" }, | |
| { GF_KEY_UNDO, "Undo" }, | |
| { GF_KEY_VOLUMEDOWN, "VolumeDown" }, | |
| { GF_KEY_VOLUMEMUTE, "VolumeMute" }, | |
| { GF_KEY_VOLUMEUP, "VolumeUp" }, | |
| { GF_KEY_WIN, "Win" }, | |
| { GF_KEY_ZOOM, "Zoom" }, | |
| { GF_KEY_BACKSPACE, "U+0008", "backspace" }, | |
| { GF_KEY_TAB, "U+0009", "tab" }, | |
| { GF_KEY_CANCEL, "U+0018", "cancel" }, | |
| { GF_KEY_ESCAPE, "U+001B", "esc" }, | |
| { GF_KEY_SPACE, "U+0020", "space" }, | |
| { GF_KEY_EXCLAMATION, "U+0021", "!" }, | |
| { GF_KEY_QUOTATION, "U+0022", "\"" }, | |
| { GF_KEY_NUMBER, "U+0023", "#" }, | |
| { GF_KEY_DOLLAR, "U+0024", "$" }, | |
| { GF_KEY_AMPERSAND, "U+0026", "&" }, | |
| { GF_KEY_APOSTROPHE, "U+0027", "'" }, | |
| { GF_KEY_LEFTPARENTHESIS, "U+0028", "(" }, | |
| { GF_KEY_RIGHTPARENTHESIS, "U+0029", ")" }, | |
| { GF_KEY_STAR, "U+002A", "*" }, | |
| { GF_KEY_PLUS, "U+002B", "+" }, | |
| { GF_KEY_COMMA, "U+002C", "," }, | |
| { GF_KEY_HYPHEN, "U+002D", "-" }, | |
| { GF_KEY_FULLSTOP, "U+002E", "." }, | |
| { GF_KEY_SLASH, "U+002F", "/" }, | |
| { GF_KEY_0, "U+0030", "0" }, | |
| { GF_KEY_1, "U+0031", "1" }, | |
| { GF_KEY_2, "U+0032", "2" }, | |
| { GF_KEY_3, "U+0033", "3" }, | |
| { GF_KEY_4, "U+0034", "4" }, | |
| { GF_KEY_5, "U+0035", "5" }, | |
| { GF_KEY_6, "U+0036", "6" }, | |
| { GF_KEY_7, "U+0037", "7" }, | |
| { GF_KEY_8, "U+0038", "8" }, | |
| { GF_KEY_9, "U+0039", "9" }, | |
| { GF_KEY_COLON, "U+003A", ":" }, | |
| { GF_KEY_SEMICOLON, "U+003B", ";" }, | |
| { GF_KEY_LESSTHAN, "U+003C", "<" }, | |
| { GF_KEY_EQUALS, "U+003D", "=" }, | |
| { GF_KEY_GREATERTHAN, "U+003E", ">" }, | |
| { GF_KEY_QUESTION, "U+003F", "?" }, | |
| { GF_KEY_AT, "U+0040", "@" }, | |
| { GF_KEY_A, "U+0041", "A" }, | |
| { GF_KEY_B, "U+0042", "B" }, | |
| { GF_KEY_C, "U+0043", "C" }, | |
| { GF_KEY_D, "U+0044", "D" }, | |
| { GF_KEY_E, "U+0045", "E" }, | |
| { GF_KEY_F, "U+0046", "F" }, | |
| { GF_KEY_G, "U+0047", "G" }, | |
| { GF_KEY_H, "U+0048", "H" }, | |
| { GF_KEY_I, "U+0049", "I" }, | |
| { GF_KEY_J, "U+004A", "J" }, | |
| { GF_KEY_K, "U+004B", "K" }, | |
| { GF_KEY_L, "U+004C", "L" }, | |
| { GF_KEY_M, "U+004D", "M" }, | |
| { GF_KEY_N, "U+004E", "N" }, | |
| { GF_KEY_O, "U+004F", "O" }, | |
| { GF_KEY_P, "U+0050", "P" }, | |
| { GF_KEY_Q, "U+0051", "Q" }, | |
| { GF_KEY_R, "U+0052", "R" }, | |
| { GF_KEY_S, "U+0053", "S" }, | |
| { GF_KEY_T, "U+0054", "T" }, | |
| { GF_KEY_U, "U+0055", "U" }, | |
| { GF_KEY_V, "U+0056", "V" }, | |
| { GF_KEY_W, "U+0057", "W" }, | |
| { GF_KEY_X, "U+0058", "X" }, | |
| { GF_KEY_Y, "U+0059", "Y" }, | |
| { GF_KEY_Z, "U+005A", "Z" }, | |
| { GF_KEY_LEFTSQUAREBRACKET, "U+005B", "[" }, | |
| { GF_KEY_BACKSLASH, "U+005C", "\\" }, | |
| { GF_KEY_RIGHTSQUAREBRACKET, "U+005D", "]" }, | |
| { GF_KEY_CIRCUM, "U+005E", "^" }, | |
| { GF_KEY_UNDERSCORE, "U+005F", "_" }, | |
| { GF_KEY_GRAVEACCENT, "U+0060", "`" }, | |
| { GF_KEY_LEFTCURLYBRACKET, "U+007B", "{" }, | |
| { GF_KEY_PIPE, "U+007C", "|" }, | |
| { GF_KEY_RIGHTCURLYBRACKET, "U+007D", "}" }, | |
| { GF_KEY_DEL, "U+007F", "del" }, | |
| { GF_KEY_INVERTEXCLAMATION, "U+00A1" }, | |
| { GF_KEY_DEADGRAVE, "U+0300" }, | |
| { GF_KEY_DEADEACUTE, "U+0301" }, | |
| { GF_KEY_DEADCIRCUM, "U+0302" }, | |
| { GF_KEY_DEADTILDE, "U+0303" }, | |
| { GF_KEY_DEADMACRON, "U+0304" }, | |
| { GF_KEY_DEADBREVE, "U+0306" }, | |
| { GF_KEY_DEADABOVEDOT, "U+0307" }, | |
| { GF_KEY_DEADDIARESIS, "U+0308" }, | |
| { GF_KEY_DEADRINGABOVE, "U+030A" }, | |
| { GF_KEY_DEADDOUBLEACUTE, "U+030B" }, | |
| { GF_KEY_DEADCARON, "U+030C" }, | |
| { GF_KEY_DEADCEDILLA, "U+0327" }, | |
| { GF_KEY_DEADOGONEK, "U+0328" }, | |
| { GF_KEY_DEADIOTA, "U+0345" }, | |
| { GF_KEY_EURO, "U+20AC"}, | |
| { GF_KEY_DEADVOICESOUND, "U+3099" }, | |
| { GF_KEY_DEADSEMIVOICESOUND, "U+309A" }, | |
| { GF_KEY_CHANNELUP, "ChannelUp" }, | |
| { GF_KEY_CHANNELDOWN, "ChannelDown" }, | |
| { GF_KEY_TEXT, "Text" }, | |
| { GF_KEY_INFO, "Info" }, | |
| { GF_KEY_EPG, "EPG" }, | |
| { GF_KEY_RECORD, "Record" }, | |
| { GF_KEY_BEGINPAGE, "BeginPage" }, | |
| { GF_KEY_CELL_SOFT1, "CELLSOFT1" }, | |
| { GF_KEY_CELL_SOFT2, "CELLSOFT2" }, | |
| }; | |
| GF_EXPORT | |
| const char *gf_dom_get_key_name(GF_KeyCode key_identifier) | |
| { | |
| u32 count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid); | |
| if (!key_identifier || count<= (u32) key_identifier) return "Unknown"; | |
| return predefined_key_identifiers[key_identifier-1].name; | |
| } | |
| GF_EXPORT | |
| const char *gf_dom_get_friendly_name(GF_KeyCode key_identifier) | |
| { | |
| u32 count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid); | |
| if (!key_identifier || count<= (u32) key_identifier) return "Unknown"; | |
| if (predefined_key_identifiers[key_identifier-1].friendly_name) | |
| return predefined_key_identifiers[key_identifier-1].friendly_name; | |
| return predefined_key_identifiers[key_identifier-1].name; | |
| } | |
| GF_EXPORT | |
| GF_KeyCode gf_dom_get_key_type(char *key_name) | |
| { | |
| if (strlen(key_name) == 1) { | |
| char c[2]; | |
| c[0] = key_name[0]; | |
| c[1] = 0; | |
| strupr(c); | |
| if (c[0] >= 'A' && c[0] <= 'Z') | |
| return (GF_KEY_A + (c[0] - 'A') ); | |
| if (c[0] >= '0' && c[0] <= '9') | |
| return ( GF_KEY_0 + (c[0] - '0') ); | |
| switch ((u8) c[0]) { | |
| case '@': | |
| return GF_KEY_AT; | |
| case '*': | |
| return GF_KEY_STAR; | |
| case '#': | |
| return GF_KEY_NUMBER; | |
| case ' ': | |
| return GF_KEY_SPACE; | |
| case '!': | |
| return GF_KEY_EXCLAMATION; | |
| case '"': | |
| return GF_KEY_QUOTATION; | |
| case '$': | |
| return GF_KEY_DOLLAR; | |
| case '&': | |
| return GF_KEY_AMPERSAND; | |
| case '\'': | |
| return GF_KEY_APOSTROPHE; | |
| case '(': | |
| return GF_KEY_LEFTPARENTHESIS; | |
| case ')': | |
| return GF_KEY_RIGHTPARENTHESIS; | |
| case '+': | |
| return GF_KEY_PLUS; | |
| case ',': | |
| return GF_KEY_COMMA; | |
| case '-': | |
| return GF_KEY_HYPHEN; | |
| case '.': | |
| return GF_KEY_FULLSTOP; | |
| case '/': | |
| return GF_KEY_SLASH; | |
| case ':': | |
| return GF_KEY_COLON; | |
| case ';': | |
| return GF_KEY_SEMICOLON; | |
| case '<': | |
| return GF_KEY_LESSTHAN; | |
| case '=': | |
| return GF_KEY_EQUALS; | |
| case '>': | |
| return GF_KEY_GREATERTHAN; | |
| case '?': | |
| return GF_KEY_QUESTION; | |
| case '[': | |
| return GF_KEY_LEFTSQUAREBRACKET; | |
| case '\\': | |
| return GF_KEY_BACKSLASH; | |
| case ']': | |
| return GF_KEY_RIGHTSQUAREBRACKET; | |
| case '^': | |
| return GF_KEY_CIRCUM; | |
| case '_': | |
| return GF_KEY_UNDERSCORE; | |
| case '`': | |
| return GF_KEY_GRAVEACCENT; | |
| case '{': | |
| return GF_KEY_LEFTCURLYBRACKET; | |
| case '|': | |
| return GF_KEY_PIPE; | |
| case '}': | |
| return GF_KEY_RIGHTCURLYBRACKET; | |
| case 0xA1: | |
| return GF_KEY_INVERTEXCLAMATION; | |
| default: | |
| return GF_KEY_UNIDENTIFIED; | |
| } | |
| } else { | |
| u32 i, count; | |
| count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid); | |
| for (i=0; i<count; i++) { | |
| if (!stricmp(key_name, predefined_key_identifiers[i].name)) { | |
| return predefined_key_identifiers[i].key_code; | |
| } | |
| } | |
| return GF_KEY_UNIDENTIFIED; | |
| } | |
| } | |
| /* Basic SVG datatype parsing functions */ | |
| /* Basic SVG datatype parsing functions */ | |
| static const struct sys_col { | |
| const char *name; | |
| u8 type; | |
| } system_colors[] = | |
| { | |
| {"ActiveBorder", SVG_COLOR_ACTIVE_BORDER}, | |
| {"ActiveCaption", SVG_COLOR_ACTIVE_CAPTION}, | |
| {"AppWorkspace", SVG_COLOR_APP_WORKSPACE}, | |
| {"Background", SVG_COLOR_BACKGROUND}, | |
| {"ButtonFace", SVG_COLOR_BUTTON_FACE}, | |
| {"ButtonHighlight", SVG_COLOR_BUTTON_HIGHLIGHT}, | |
| {"ButtonShadow", SVG_COLOR_BUTTON_SHADOW}, | |
| {"ButtonText", SVG_COLOR_BUTTON_TEXT}, | |
| {"CaptionText", SVG_COLOR_CAPTION_TEXT}, | |
| {"GrayText", SVG_COLOR_GRAY_TEXT}, | |
| {"Highlight", SVG_COLOR_HIGHLIGHT}, | |
| {"HighlightText", SVG_COLOR_HIGHLIGHT_TEXT}, | |
| {"InactiveBorder", SVG_COLOR_INACTIVE_BORDER}, | |
| {"InactiveCaption", SVG_COLOR_INACTIVE_CAPTION}, | |
| {"InactiveCaptionText", SVG_COLOR_INACTIVE_CAPTION_TEXT}, | |
| {"InfoBackground", SVG_COLOR_INFO_BACKGROUND}, | |
| {"InfoText", SVG_COLOR_INFO_TEXT}, | |
| {"Menu", SVG_COLOR_MENU}, | |
| {"MenuText", SVG_COLOR_MENU_TEXT}, | |
| {"Scrollbar", SVG_COLOR_SCROLLBAR}, | |
| {"ThreeDDarkShadow", SVG_COLOR_3D_DARK_SHADOW}, | |
| {"ThreeDFace", SVG_COLOR_3D_FACE}, | |
| {"ThreeDHighlight", SVG_COLOR_3D_HIGHLIGHT}, | |
| {"ThreeDLightShadow", SVG_COLOR_3D_LIGHT_SHADOW}, | |
| {"ThreeDShadow", SVG_COLOR_3D_SHADOW}, | |
| {"Window", SVG_COLOR_WINDOW}, | |
| {"WindowFrame", SVG_COLOR_WINDOW_FRAME}, | |
| {"WindowText", SVG_COLOR_WINDOW_TEXT}, | |
| }; | |
| /* parses an color from a named color HTML or CSS 2 */ | |
| static void svg_parse_named_color(SVG_Color *col, char *attribute_content) | |
| { | |
| u32 i, count, val; | |
| val = gf_color_parse(attribute_content); | |
| if (val) { | |
| col->red = INT2FIX((val>>16) & 0xFF) / 255; | |
| col->green = INT2FIX((val>>8) & 0xFF) / 255; | |
| col->blue = INT2FIX(val & 0xFF) / 255; | |
| col->type = SVG_COLOR_RGBCOLOR; | |
| return; | |
| } | |
| count = sizeof(system_colors) / sizeof(struct sys_col); | |
| for (i=0; i<count; i++) { | |
| if (!strcmp(attribute_content, system_colors[i].name)) { | |
| col->type = system_colors[i].type; | |
| return; | |
| } | |
| } | |
| } | |
| const char *gf_svg_get_system_paint_server_name(u32 paint_type) | |
| { | |
| u32 i, count; | |
| count = sizeof(system_colors) / sizeof(struct sys_col); | |
| for (i=0; i<count; i++) { | |
| if (paint_type == system_colors[i].type) return system_colors[i].name; | |
| } | |
| return "undefined"; | |
| } | |
| u32 gf_svg_get_system_paint_server_type(const char *name) | |
| { | |
| u32 i, count; | |
| count = sizeof(system_colors) / sizeof(struct sys_col); | |
| for (i=0; i<count; i++) { | |
| if (!strcmp(name, system_colors[i].name)) return system_colors[i].type; | |
| } | |
| return 0; | |
| } | |
| /* Reads an SVG Color | |
| either #RRGGBB, #RGB, rgb(r,g,b) in [0,255] , colorname, or 'r g b' in [0,1] | |
| ignores any space, comma, semi-column before and any space after | |
| TODO: | |
| transform the char into char and duplicate the input, instead of modifying it | |
| be more robust to errors in color description ex rgb(0 0 0) | |
| */ | |
| static void svg_parse_color(SVG_Color *col, char *attribute_content, GF_Err *out_e) | |
| { | |
| char *str = attribute_content; | |
| if (!str) return; | |
| u32 len = (u32) strlen(attribute_content); | |
| while (len && (str[strlen(attribute_content)-1] == ' ')) { | |
| str[len-1] = 0; | |
| len--; | |
| } | |
| while (*str != 0 && (*str == ' ' || *str == ',' || *str == ';')) str++; | |
| if (!strcmp(str, "currentColor")) { | |
| col->type = SVG_COLOR_CURRENTCOLOR; | |
| return; | |
| } else if (!strcmp(str, "inherit")) { | |
| col->type = SVG_COLOR_INHERIT; | |
| return; | |
| } else if (str[0]=='#') { | |
| u32 val; | |
| if (sscanf(str+1, "%x", &val) != 1) { | |
| col->type = SVG_COLOR_INHERIT; | |
| return; | |
| } | |
| if (strlen(str) == 7) { | |
| col->red = INT2FIX((val>>16) & 0xFF) / 255; | |
| col->green = INT2FIX((val>>8) & 0xFF) / 255; | |
| col->blue = INT2FIX(val & 0xFF) / 255; | |
| } else { | |
| col->red = INT2FIX((val>>8) & 0xF) / 15; | |
| col->green = INT2FIX((val>>4) & 0xF) / 15; | |
| col->blue = INT2FIX(val & 0xF) / 15; | |
| } | |
| col->type = SVG_COLOR_RGBCOLOR; | |
| } else if (strstr(str, "rgb(") || strstr(str, "RGB(")) { | |
| Float _val; | |
| u8 is_percentage= 0; | |
| if (strstr(str, "%")) is_percentage = 1; | |
| str = strstr(str, "("); | |
| str++; | |
| if (sscanf(str, "%f", &_val) != 1) { | |
| col->red = col->green = col->blue = 0; | |
| return; | |
| } | |
| col->red = FLT2FIX(_val); | |
| str = strstr(str, ","); | |
| if (!str) { | |
| /* space separated colors/percentages are not allowed neither in SVG 1.1 nor in SVG T1.2 */ | |
| col->red = col->green = col->blue = 0; | |
| return; | |
| } | |
| str++; | |
| sscanf(str, "%f", &_val); | |
| col->green = FLT2FIX(_val); | |
| str = strstr(str, ","); | |
| if (!str) { | |
| /* space separated colors/percentages are not allowed neither in SVG 1.1 nor in SVG T1.2 */ | |
| col->red = col->green = col->blue = 0; | |
| return; | |
| } | |
| str++; | |
| sscanf(str, "%f", &_val); | |
| col->blue = FLT2FIX(_val); | |
| if (is_percentage) { | |
| col->red /= 100; | |
| col->green /= 100; | |
| col->blue /= 100; | |
| } else { | |
| col->red /= 255; | |
| col->green /= 255; | |
| col->blue /= 255; | |
| } | |
| col->type = SVG_COLOR_RGBCOLOR; | |
| } else if ((str[0] >= 'a' && str[0] <= 'z') | |
| || (str[0] >= 'A' && str[0] <= 'Z')) { | |
| svg_parse_named_color(col, str); | |
| } else { | |
| Float _r, _g, _b; | |
| if (sscanf(str, "%f %f %f", &_r, &_g, &_b)==3) { | |
| col->red = FLT2FIX(_r); | |
| col->green = FLT2FIX(_g); | |
| col->blue = FLT2FIX(_b); | |
| col->type = SVG_COLOR_RGBCOLOR; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| } | |
| /* | |
| Reads a number (i.e. without unit) according to the CSS syntax (same as SVG paths and transforms) | |
| trims any space, comma, semi-column before or after (TODO: fix this) | |
| reads an optional + or - | |
| then reads a digit between 0 and 9 | |
| optionally followed by an '.' and digits between 0 and 9 | |
| optionally followed by e or E and digits between 0 and 9 | |
| Returns the number of chars read in d | |
| */ | |
| static u32 svg_parse_number(char *d, Fixed *f, Bool is_angle, GF_Err *out_e) | |
| { | |
| u32 nb_digit_before = 0; | |
| u32 nb_digit_after = 0; | |
| Bool has_fractional = 0; | |
| Bool is_negative = 0; | |
| Float _val = 0; | |
| u32 i = 0; | |
| /* warning the comma and semicolumn should not be there when parsing a number in a path */ | |
| while ((d[i] != 0) && strchr(" ,;\r\n\t", d[i])) i++; | |
| if (!d[i]) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Parsing] Parsing number with empty string or only spaces: %s\n", d)); | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| return 0; | |
| } | |
| if (d[i] == '+') { | |
| i++; | |
| } else if (d[i] == '-') { | |
| is_negative = 1; | |
| i++; | |
| } | |
| /* Warning: this is not normal, should be detected somehow by checking the BNF */ | |
| /* if ((d[i]=='N') && (d[i+1]=='a') && (d[i+2]=='N')) { | |
| i+= 3; | |
| _val = 0; | |
| goto end; | |
| }*/ | |
| /* read the digit-sequence token of the BNF */ | |
| while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) { | |
| _val = _val*10 + (d[i]-'0'); | |
| nb_digit_before++; | |
| i++; | |
| } | |
| if (d[i] == '.') { | |
| has_fractional = 1; | |
| i++; | |
| while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) { | |
| _val = _val*10 + (d[i]-'0'); | |
| nb_digit_after++; | |
| i++; | |
| } | |
| if (nb_digit_after) { | |
| _val /= (Float)pow(10,nb_digit_after); | |
| } else if (nb_digit_before == 0) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing number (expecting digits before or after a '.': %s\n", d)); | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| return 0; | |
| } else { | |
| /* dangling '.' without digits after. This is allowed by the BNF */ | |
| } | |
| } | |
| if ((nb_digit_before == 0) && (has_fractional == 0)) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing number (expecting digits):%s\n", d)); | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| return 0; | |
| } | |
| /* reading the exponent */ | |
| if (d[i] == 'e' || d[i] == 'E') { | |
| Bool neg_exp = 0; | |
| u32 nb_exp_digits = 0; | |
| s32 exp = 0; | |
| i++; | |
| if (d[i] == '+') i++; | |
| else if (d[i] == '-') { | |
| i++; | |
| neg_exp=1; | |
| } | |
| while (d[i] >= '0' && d[i] <= '9' && d[i] != 0) { | |
| exp = exp*10 + (d[i]-'0'); | |
| nb_exp_digits++; | |
| i++; | |
| } | |
| if (nb_exp_digits) { | |
| _val *= (Float)pow(10, neg_exp ? -exp : exp); | |
| } else { | |
| 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)); | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| return 0; | |
| } | |
| } | |
| /* We can now produce the final number */ | |
| if (is_negative) _val *= -1; | |
| if (is_angle) { | |
| _val/=180; | |
| (*f) = gf_mulfix(FLT2FIX(_val), GF_PI); | |
| } else { | |
| (*f) = FLT2FIX(_val); | |
| } | |
| /* warning the comma and semicolumn should not be there when parsing a path number */ | |
| while (d[i] != 0 && (d[i] == ' ' || d[i] == ',' || d[i] == ';')) i++; | |
| return i; | |
| } | |
| /* | |
| Parse an Offset Value, i.e +/- Clock Value | |
| */ | |
| static GF_Err svg_parse_clock_value(char *d, Double *clock_value) | |
| { | |
| char *tmp; | |
| s32 sign = 1; | |
| if (!d) return GF_BAD_PARAM; | |
| if (!d[0]) return GF_BAD_PARAM; | |
| if (d[0] == '+') d++; | |
| else if (d[0] == '-') { | |
| sign = -1; | |
| d++; | |
| } | |
| if (!d[0]) return GF_BAD_PARAM; | |
| /* According to SVG, the following are invalid syntaxes (see animate-elem-225-t.svg) | |
| '+-2s' | |
| '1++s' even though sscanf returns the right values | |
| */ | |
| if (strpbrk(d, "+-")) return GF_BAD_PARAM; | |
| /* No embedded white space is allowed in clock values, | |
| although leading and trailing white space characters will be ignored.*/ | |
| while (*d == ' ') d++; | |
| if ((tmp = strchr(d, ':'))) { | |
| /* Full or Partial Clock value */ | |
| tmp++; | |
| if ((tmp = strchr(tmp, ':'))) { | |
| /* Full Clock value : hh:mm:ss(.frac) */ | |
| u32 hours; | |
| u32 minutes; | |
| Float seconds; | |
| if (sscanf(d, "%u:%u:%f", &hours, &minutes, &seconds) < 3) return GF_BAD_PARAM; | |
| *clock_value = hours*3600 + minutes*60 + seconds; | |
| } else { | |
| /* Partial Clock value : mm:ss(.frac) */ | |
| s32 minutes; | |
| Float seconds; | |
| if (sscanf(d, "%d:%f", &minutes, &seconds) < 2) return GF_BAD_PARAM; | |
| *clock_value = minutes*60 + seconds; | |
| } | |
| } else if ((tmp = strstr(d, "h"))) { | |
| Float f; | |
| if (sscanf(d, "%fh", &f) == 0) return GF_BAD_PARAM; | |
| *clock_value = 3600*f; | |
| } else if (strstr(d, "min")) { | |
| Float f; | |
| if (sscanf(d, "%fmin", &f) == 0) return GF_BAD_PARAM; | |
| *clock_value = 60*f; | |
| } else if ((tmp = strstr(d, "ms"))) { | |
| Float f; | |
| if (sscanf(d, "%fms", &f) == 0) return GF_BAD_PARAM; | |
| *clock_value = f/1000; | |
| } else if (strchr(d, 's')) { | |
| Float f; | |
| if (sscanf(d, "%fs", &f) == 0) return GF_BAD_PARAM; | |
| *clock_value = f; | |
| } else { | |
| Float f; | |
| if (sscanf(d, "%f", &f) == 0) return GF_BAD_PARAM; | |
| *clock_value = f; | |
| } | |
| *clock_value *= sign; | |
| return GF_OK; | |
| } | |
| /* Parses one SVG time value: | |
| indefinite, | |
| element_id.event_name | |
| wallclock, | |
| accessKey, | |
| events, | |
| clock value. | |
| */ | |
| static GF_Err smil_parse_time(GF_Node *elt, SMIL_Time *v, char *d) | |
| { | |
| GF_Err e = GF_OK; | |
| char *tmp; | |
| /* Offset Values */ | |
| if ((d[0] >= '0' && d[0] <= '9') || d[0] == '+' || d[0] == '-') { | |
| v->type = GF_SMIL_TIME_CLOCK; | |
| return svg_parse_clock_value(d, &(v->clock)); | |
| } | |
| /* Indefinite Values */ | |
| else if (!strcmp(d, "indefinite")) { | |
| v->type = GF_SMIL_TIME_INDEFINITE; | |
| return GF_OK; | |
| } | |
| /* Wallclock Values */ | |
| else if ((tmp = strstr(d, "wallclock("))) { | |
| u32 year, month, day; | |
| u32 hours, minutes; | |
| u32 nhours, nminutes; | |
| Float seconds; | |
| char *tmp1; | |
| v->type = GF_SMIL_TIME_WALLCLOCK; | |
| tmp += 10; | |
| if ((tmp1 = strchr(tmp, 'T')) ) { | |
| /* From tmp to wallStartTime, we parse a date */ | |
| sscanf(tmp, "%u-%u-%dT", &year, &month, &day); | |
| tmp1++; | |
| tmp = tmp1; | |
| } | |
| if ((tmp1 = strchr(tmp, ':')) ) { | |
| if (strchr(tmp1, ':')) { | |
| /* HHMMSS */ | |
| sscanf(tmp, "%u:%u:%f", &hours, &minutes, &seconds); | |
| } else { | |
| /* HHMM */ | |
| sscanf(tmp, "%u:%u", &hours, &minutes); | |
| } | |
| } | |
| if (strchr(tmp, 'Z')) { | |
| return GF_OK; | |
| } else { | |
| if ( (tmp1 = strchr(tmp, '+')) ) { | |
| sscanf(tmp1, "%u:%u", &nhours, &nminutes); | |
| } else if ( (tmp1 = strchr(tmp, '-')) ) { | |
| sscanf(tmp1, "%u:%u", &nhours, &nminutes); | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| /* AccessKey Values */ | |
| else if ((tmp = strstr(d, "accessKey("))) { | |
| char *sep; | |
| v->type = GF_SMIL_TIME_EVENT; | |
| v->event.type = GF_EVENT_KEYDOWN; | |
| v->element = elt->sgprivate->scenegraph->RootNode; | |
| tmp+=10; | |
| sep = strchr(d, ')'); | |
| if (!sep) return GF_BAD_PARAM; | |
| sep[0] = 0; | |
| v->event.parameter = gf_dom_get_key_type(tmp); | |
| sep++; | |
| if ((tmp = strchr(sep, '+')) || (tmp = strchr(sep, '-'))) { | |
| char c = *tmp; | |
| tmp++; | |
| e = svg_parse_clock_value(tmp, &(v->clock)); | |
| if (c == '-') v->clock *= -1; | |
| } | |
| return e; | |
| } | |
| else { | |
| Bool had_param = 0; | |
| char *tmp2; | |
| v->type = GF_SMIL_TIME_EVENT; | |
| if ((tmp = strchr(d, '.'))) { | |
| tmp[0] = 0; | |
| if (strlen(d) == 0) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] expecting an id before '.' in SMIL Time .%s\n", tmp+1)); | |
| return GF_BAD_PARAM; | |
| } | |
| v->element_id = gf_strdup(d); | |
| tmp[0] = '.'; | |
| tmp++; | |
| } else { | |
| tmp = d; | |
| } | |
| if ((tmp2 = strchr(tmp, '('))) { | |
| tmp2[0] = 0; | |
| v->event.type = gf_dom_event_type_by_name(tmp); | |
| tmp2[0] = '('; | |
| tmp2++; | |
| had_param = 1; | |
| v->event.parameter = atoi(tmp2); | |
| tmp = strchr(tmp2, ')'); | |
| if (!tmp) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] expecting ')' in SMIL Time %s\n", d)); | |
| return GF_BAD_PARAM; | |
| } | |
| tmp++; | |
| } | |
| if ((tmp2 = strchr(tmp, '+')) || (tmp2 = strchr(tmp, '-'))) { | |
| char c = *tmp2; | |
| char *tmp3 = tmp2; | |
| tmp2[0] = 0; | |
| tmp3--; | |
| while (*tmp3==' ') { | |
| *tmp3=0; | |
| tmp3--; | |
| } | |
| if (v->event.type == 0) v->event.type = gf_dom_event_type_by_name(tmp); | |
| if (!had_param && (v->event.type == GF_EVENT_REPEAT || v->event.type == GF_EVENT_REPEAT_EVENT)) | |
| v->event.parameter = 1; | |
| tmp2[0] = c; | |
| tmp2++; | |
| e = svg_parse_clock_value(tmp2, &(v->clock)); | |
| if (c == '-') v->clock *= -1; | |
| return e; | |
| } else { | |
| if (v->event.type == 0) v->event.type = gf_dom_event_type_by_name(tmp); | |
| if (!had_param && (v->event.type == GF_EVENT_REPEAT || v->event.type == GF_EVENT_REPEAT_EVENT)) | |
| v->event.parameter = 1; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| /* Parses a list of SVG transformations and collapses them in the given matrix */ | |
| Bool gf_svg_parse_transformlist(GF_Matrix2D *mat, char *attribute_content) | |
| { | |
| GF_Matrix2D tmp; | |
| GF_Err e; | |
| char *str; | |
| u32 read_chars; | |
| u32 i; | |
| gf_mx2d_init(*mat); | |
| str = attribute_content; | |
| i = 0; | |
| while (str[i] != 0) { | |
| while (str[i] == ' ') i++; | |
| if (str[i] == ',') i++; | |
| while (str[i] == ' ') i++; | |
| if (strstr(str+i, "scale")==str+i) { | |
| i += 5; | |
| while(str[i] == ' ') i++; | |
| if (str[i] == '(') { | |
| Fixed sx, sy; | |
| i++; | |
| read_chars = svg_parse_number(&(str[i]), &sx, 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading sx component in scale: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| if (str[i] == ')') { | |
| sy = sx; | |
| } else { | |
| read_chars = svg_parse_number(&(str[i]), &sy, 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading sy component in scale: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| } | |
| gf_mx2d_init(tmp); | |
| gf_mx2d_add_scale(&tmp, sx, sy); | |
| gf_mx2d_add_matrix(&tmp, mat); | |
| gf_mx2d_copy(*mat, tmp); | |
| while(str[i] == ' ') i++; | |
| if (str[i] == ')') i++; | |
| else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| } else if (strstr(str+i, "translate")==str+i) { | |
| i += 9; | |
| while(str[i] == ' ') i++; | |
| if (str[i] == '(') { | |
| Fixed tx, ty; | |
| i++; | |
| read_chars = svg_parse_number(&(str[i]), &tx, 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading tx component in translate: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| if (str[i] == ')') { | |
| ty = 0; | |
| } else { | |
| read_chars = svg_parse_number(&(str[i]), &ty, 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading ty component in translate: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| } | |
| gf_mx2d_init(tmp); | |
| gf_mx2d_add_translation(&tmp, tx, ty); | |
| gf_mx2d_add_matrix(&tmp, mat); | |
| gf_mx2d_copy(*mat, tmp); | |
| while(str[i] == ' ') i++; | |
| if (str[i] == ')') i++; | |
| else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| } else if (strstr(str+i, "rotate")==str+i) { | |
| i += 6; | |
| while(str[i] == ' ') i++; | |
| if (str[i] == '(') { | |
| Fixed angle, cx, cy; | |
| i++; | |
| read_chars = svg_parse_number(&(str[i]), &angle, 1, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading angle component in rotate: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| if (str[i] == ')') { | |
| cx = cy = 0; | |
| } else { | |
| read_chars = svg_parse_number(&(str[i]), &cx, 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading cx component in rotate: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(str[i]), &cy, 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading cy component in rotate: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| } | |
| gf_mx2d_init(tmp); | |
| gf_mx2d_add_rotation(&tmp, cx, cy, angle); | |
| gf_mx2d_add_matrix(&tmp, mat); | |
| gf_mx2d_copy(*mat, tmp); | |
| while(str[i] == ' ') i++; | |
| if (str[i] == ')') i++; | |
| else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| } else if (strstr(str+i, "skewX")==str+i) { | |
| i += 5; | |
| while(str[i] == ' ') i++; | |
| if (str[i] == '(') { | |
| Fixed angle; | |
| i++; | |
| read_chars = svg_parse_number(&(str[i]), &angle, 1, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading angle in skewX: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| gf_mx2d_init(tmp); | |
| gf_mx2d_add_skew_x(&tmp, angle); | |
| gf_mx2d_add_matrix(&tmp, mat); | |
| gf_mx2d_copy(*mat, tmp); | |
| while(str[i] == ' ') i++; | |
| if (str[i] == ')') i++; | |
| else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| } else if (strstr(str+i, "skewY")==str+i) { | |
| i += 5; | |
| while(str[i] == ' ') i++; | |
| if (str[i] == '(') { | |
| Fixed angle; | |
| i++; | |
| read_chars = svg_parse_number(&(str[i]), &angle, 1, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading angle component in skewY: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| gf_mx2d_init(tmp); | |
| gf_mx2d_add_skew_y(&tmp, angle); | |
| gf_mx2d_add_matrix(&tmp, mat); | |
| gf_mx2d_copy(*mat, tmp); | |
| while(str[i] == ' ') i++; | |
| if (str[i] == ')') i++; | |
| else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| } else if (strstr(str+i, "matrix")==str+i) { | |
| i+=6; | |
| while(str[i] == ' ') i++; | |
| if (str[i] == '(') { | |
| i++; | |
| read_chars = svg_parse_number(&(str[i]), &(tmp.m[0]), 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient a in matrix: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(str[i]), &(tmp.m[3]), 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient b in matrix: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(str[i]), &(tmp.m[1]), 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient c in matrix: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(str[i]), &(tmp.m[4]), 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient d in matrix: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(str[i]), &(tmp.m[2]), 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient e in matrix: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(str[i]), &(tmp.m[5]), 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient f in matrix: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| i += read_chars; | |
| gf_mx2d_add_matrix(&tmp, mat); | |
| gf_mx2d_copy(*mat, tmp); | |
| while(str[i] == ' ') i++; | |
| if (str[i] == ')') i++; | |
| else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in transform attribute: %s\n", attribute_content)); | |
| return 0; | |
| } | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Unrecognized transofrm type in attribute %s\n", attribute_content)); | |
| return 0; | |
| } | |
| /*for svgView parsing*/ | |
| if (str[i] == ')') i++; | |
| } | |
| return 1; | |
| } | |
| /* Parses an SVG transform attribute and collapses all in the given matrix */ | |
| static GF_Err svg_parse_transform(SVG_Transform *t, char *attribute_content) | |
| { | |
| char *str; | |
| u32 i; | |
| u32 read_chars; | |
| i = 0; | |
| GF_Err e; | |
| if ((str = strstr(attribute_content, "ref"))) { | |
| t->is_ref = 1; | |
| gf_mx2d_init(t->mat); | |
| str+=3; | |
| while (str[i] == ' ') i++; | |
| if (str[i] == '(') { | |
| i++; | |
| while (str[i] == ' ') i++; | |
| if (str[i] == 's' && str[i+1] == 'v' && str[i+2] == 'g') { | |
| i+=3; | |
| while (str[i] == ' ') i++; | |
| if (str[i] == ',') { | |
| i++; | |
| } else if (str[i] == ')') { | |
| //i++; | |
| return GF_OK; | |
| } | |
| read_chars = svg_parse_number(&(str[i]), &(t->mat.m[2]), 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient tx in ref transform: %s\n", attribute_content)); | |
| return e; | |
| } | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(str[i]), &(t->mat.m[5]), 0, &e); | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error reading coefficient ty in ref transform: %s\n", attribute_content)); | |
| return e; | |
| } | |
| i += read_chars; | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Unsupported syntax for ref transform attribute")); | |
| } | |
| while (str[i] == ' ') i++; | |
| if (str[i] == ')') { | |
| //i++; | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing closing parenthesis in transform attribute: %s\n", attribute_content)); | |
| } | |
| return GF_OK; | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Missing opening parenthesis in ref transform attribute: %s\n", attribute_content)); | |
| return GF_BAD_PARAM; | |
| } | |
| } else { | |
| Bool res = gf_svg_parse_transformlist(&t->mat, attribute_content); | |
| if (!res) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error parsing transform list: %s\n", attribute_content)); | |
| return GF_BAD_PARAM; | |
| } | |
| } | |
| return GF_OK; | |
| } | |
| #undef REMOVE_ALLOC | |
| #if USE_GF_PATH | |
| //#define PARSE_PATH_ONLY | |
| static void svg_parse_path(SVG_PathData *path, char *attribute_content, GF_Err *out_e) | |
| { | |
| char *d = attribute_content; | |
| /* used to detect end of BNF production: | |
| "The processing of the BNF must consume as much of a given BNF production as possible, | |
| stopping at the point when a character is encountered which no longer satisfies the production." */ | |
| u32 read_chars = 0; | |
| /* Point used to start a new subpath when the previous subpath is closed */ | |
| SVG_Point prev_m_pt; | |
| /* Point used to convert relative 'lower-case commands' into absolute */ | |
| SVG_Point rel_ref_pt; | |
| /* Points used to convert S, T commands into C, Q */ | |
| SVG_Point orig, ct_orig, ct_end, end; | |
| /* Used by elliptical arcs */ | |
| Fixed x_axis_rotation, large_arc_flag, sweep_flag; | |
| char c, prev_c; | |
| u32 i; | |
| if (*d == 0) return; | |
| i = 0; | |
| prev_c = 'M'; | |
| 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; | |
| while(1) { | |
| while ( (d[i]==' ') || (d[i] =='\t') || (d[i] =='\r') || (d[i] =='\n') ) i++; | |
| c = d[i]; | |
| if (! c) break; | |
| next_command: | |
| switch (c) { | |
| case 'm': | |
| case 'M': | |
| i++; | |
| read_chars = svg_parse_number(&(d[i]), &(orig.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(orig.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 'm') { | |
| orig.x += rel_ref_pt.x; | |
| orig.y += rel_ref_pt.y; | |
| } | |
| #ifndef PARSE_PATH_ONLY | |
| gf_path_add_move_to(path, orig.x, orig.y); | |
| #endif | |
| rel_ref_pt = orig; | |
| prev_m_pt = orig; | |
| /*provision for nextCurveTo when no curve is specified: | |
| "If there is no previous command or if the previous command was not an C, c, S or s, | |
| assume the first control point is coincident with the current point. | |
| */ | |
| ct_orig = orig; | |
| prev_c = c; | |
| break; | |
| case 'L': | |
| case 'l': | |
| i++; | |
| read_chars = svg_parse_number(&(d[i]), &(orig.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(orig.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 'l') { | |
| orig.x += rel_ref_pt.x; | |
| orig.y += rel_ref_pt.y; | |
| } | |
| #ifndef PARSE_PATH_ONLY | |
| gf_path_add_line_to(path, orig.x, orig.y); | |
| #endif | |
| rel_ref_pt = orig; | |
| orig = end; | |
| /*cf above*/ | |
| ct_orig = orig; | |
| prev_c = c; | |
| break; | |
| case 'H': | |
| case 'h': | |
| i++; | |
| read_chars = svg_parse_number(&(d[i]), &(orig.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 'h') { | |
| orig.x += rel_ref_pt.x; | |
| } | |
| orig.y = rel_ref_pt.y; | |
| #ifndef PARSE_PATH_ONLY | |
| gf_path_add_line_to(path, orig.x, orig.y); | |
| #endif | |
| rel_ref_pt.x = orig.x; | |
| orig = end; | |
| /*cf above*/ | |
| ct_orig = orig; | |
| prev_c = c; | |
| break; | |
| case 'V': | |
| case 'v': | |
| i++; | |
| read_chars = svg_parse_number(&(d[i]), &(orig.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 'v') { | |
| orig.y += rel_ref_pt.y; | |
| } | |
| orig.x = rel_ref_pt.x; | |
| #ifndef PARSE_PATH_ONLY | |
| gf_path_add_line_to(path, orig.x, orig.y); | |
| #endif | |
| rel_ref_pt.y = orig.y; | |
| orig = end; | |
| /*cf above*/ | |
| ct_orig = orig; | |
| prev_c = c; | |
| break; | |
| case 'C': | |
| case 'c': | |
| i++; | |
| read_chars = svg_parse_number(&(d[i]), &(ct_orig.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(ct_orig.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 'c') { | |
| ct_orig.x += rel_ref_pt.x; | |
| ct_orig.y += rel_ref_pt.y; | |
| } | |
| read_chars = svg_parse_number(&(d[i]), &(ct_end.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(ct_end.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 'c') { | |
| ct_end.x += rel_ref_pt.x; | |
| ct_end.y += rel_ref_pt.y; | |
| } | |
| read_chars = svg_parse_number(&(d[i]), &(end.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(end.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 'c') { | |
| end.x += rel_ref_pt.x; | |
| end.y += rel_ref_pt.y; | |
| } | |
| #ifndef PARSE_PATH_ONLY | |
| gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y); | |
| #endif | |
| rel_ref_pt = end; | |
| ct_orig = ct_end; | |
| orig = end; | |
| prev_c = c; | |
| break; | |
| case 'S': | |
| case 's': | |
| i++; | |
| ct_orig.x = 2*orig.x - ct_orig.x; | |
| ct_orig.y = 2*orig.y - ct_orig.y; | |
| read_chars = svg_parse_number(&(d[i]), &(ct_end.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(ct_end.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 's') { | |
| ct_end.x += rel_ref_pt.x; | |
| ct_end.y += rel_ref_pt.y; | |
| } | |
| read_chars = svg_parse_number(&(d[i]), &(end.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(end.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 's') { | |
| end.x += rel_ref_pt.x; | |
| end.y += rel_ref_pt.y; | |
| } | |
| #ifndef PARSE_PATH_ONLY | |
| switch (prev_c) { | |
| case 'c': | |
| case 'C': | |
| case 's': | |
| case 'S': | |
| gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y); | |
| break; | |
| default: | |
| gf_path_add_quadratic_to(path, ct_end.x, ct_end.y, end.x, end.y); | |
| break; | |
| } | |
| #endif | |
| rel_ref_pt = end; | |
| ct_orig = ct_end; | |
| orig = end; | |
| prev_c = c; | |
| break; | |
| case 'Q': | |
| case 'q': | |
| i++; | |
| read_chars = svg_parse_number(&(d[i]), &(ct_orig.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(ct_orig.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 'q') { | |
| ct_orig.x += rel_ref_pt.x; | |
| ct_orig.y += rel_ref_pt.y; | |
| } | |
| read_chars = svg_parse_number(&(d[i]), &(end.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(end.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 'q') { | |
| end.x += rel_ref_pt.x; | |
| end.y += rel_ref_pt.y; | |
| } | |
| #ifndef PARSE_PATH_ONLY | |
| gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y); | |
| #endif | |
| rel_ref_pt = end; | |
| orig = end; | |
| prev_c = c; | |
| break; | |
| case 'T': | |
| case 't': | |
| i++; | |
| ct_orig.x = 2*orig.x - ct_orig.x; | |
| ct_orig.y = 2*orig.y - ct_orig.y; | |
| read_chars = svg_parse_number(&(d[i]), &(end.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(end.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 't') { | |
| end.x += rel_ref_pt.x; | |
| end.y += rel_ref_pt.y; | |
| } | |
| #ifndef PARSE_PATH_ONLY | |
| gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y); | |
| #endif | |
| rel_ref_pt = end; | |
| orig = end; | |
| prev_c = c; | |
| break; | |
| case 'A': | |
| case 'a': | |
| i++; | |
| read_chars = svg_parse_number(&(d[i]), &(orig.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(orig.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(x_axis_rotation), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(large_arc_flag), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(sweep_flag), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(end.x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(d[i]), &(end.y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| if (c == 'a') { | |
| end.x += rel_ref_pt.x; | |
| end.y += rel_ref_pt.y; | |
| } | |
| #ifndef PARSE_PATH_ONLY | |
| 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)); | |
| #endif | |
| rel_ref_pt = end; | |
| ct_orig = end; | |
| prev_c = c; | |
| break; | |
| case 'Z': | |
| case 'z': | |
| i++; | |
| #ifndef PARSE_PATH_ONLY | |
| gf_path_close(path); | |
| #endif | |
| prev_c = c; | |
| rel_ref_pt = prev_m_pt; | |
| break; | |
| default: | |
| i--; | |
| switch (prev_c) { | |
| case 'M': | |
| c = 'L'; | |
| break; | |
| case 'm': | |
| c = 'l'; | |
| break; | |
| case 'Z': | |
| case 'z': | |
| /* closepath takes no parameters, so re-dispatching it here | |
| consumes nothing: the i-- above is undone by the i++ in | |
| the 'Z' case and the loop never advances. The path data | |
| is in error at this point, so stop parsing. */ | |
| return; | |
| default: | |
| c = prev_c; | |
| } | |
| goto next_command; | |
| } | |
| } | |
| } | |
| #else | |
| /* TODO: Change the function to handle elliptical arcs, requires changing data structure */ | |
| static void svg_parse_path(SVG_PathData *d_attribute, char *attribute_content, GF_Err *out_e) | |
| { | |
| GF_List *d_commands = d_attribute->commands; | |
| GF_List *d_points = d_attribute->points; | |
| char *d = attribute_content; | |
| if (strlen(d)) { | |
| SVG_Point *pt, cur_pt, prev_m_pt; | |
| u8 *command; | |
| u32 i, k; | |
| char c, prev_c = 'M'; | |
| #ifdef REMOVE_ALLOC | |
| GF_SAFEALLOC(pt, SVG_Point) | |
| if (!pt) return; | |
| #endif | |
| i = 0; | |
| cur_pt.x = cur_pt.y = 0; | |
| prev_m_pt.x = prev_m_pt.y = 0; | |
| while(1) { | |
| while ( (d[i]==' ') || (d[i] =='\t') ) i++; | |
| c = d[i]; | |
| if (! c) break; | |
| next_command: | |
| switch (c) { | |
| case 'm': | |
| case 'M': | |
| i++; | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(command, u8) | |
| if (!command) return; | |
| gf_list_add(d_commands, command); | |
| *command = SVG_PATHCOMMAND_M; | |
| GF_SAFEALLOC(pt, SVG_Point) | |
| if (!pt) return; | |
| gf_list_add(d_points, pt); | |
| #endif | |
| i += svg_parse_number(&(d[i]), &(pt->x), 0, out_e); | |
| i += svg_parse_number(&(d[i]), &(pt->y), 0, out_e); | |
| if (c == 'm') { | |
| pt->x += cur_pt.x; | |
| pt->y += cur_pt.y; | |
| } | |
| cur_pt.x = pt->x; | |
| cur_pt.y = pt->y; | |
| prev_m_pt = cur_pt; | |
| prev_c = c; | |
| break; | |
| case 'L': | |
| case 'l': | |
| i++; | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(command, u8) | |
| if (!command) return; | |
| gf_list_add(d_commands, command); | |
| *command = SVG_PATHCOMMAND_L; | |
| GF_SAFEALLOC(pt, SVG_Point) | |
| if (!pt) return; | |
| gf_list_add(d_points, pt); | |
| #endif | |
| i += svg_parse_number(&(d[i]), &(pt->x), 0, out_e); | |
| i += svg_parse_number(&(d[i]), &(pt->y), 0, out_e); | |
| if (c == 'l') { | |
| pt->x += cur_pt.x; | |
| pt->y += cur_pt.y; | |
| } | |
| cur_pt.x = pt->x; | |
| cur_pt.y = pt->y; | |
| prev_c = c; | |
| break; | |
| case 'H': | |
| case 'h': | |
| i++; | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(command, u8) | |
| if (!command) return; | |
| gf_list_add(d_commands, command); | |
| *command = SVG_PATHCOMMAND_L; | |
| GF_SAFEALLOC(pt, SVG_Point) | |
| if (!pt) return; | |
| gf_list_add(d_points, pt); | |
| #endif | |
| i += svg_parse_number(&(d[i]), &(pt->x), 0, out_e); | |
| if (c == 'h') { | |
| pt->x += cur_pt.x; | |
| } | |
| pt->y = cur_pt.y; | |
| cur_pt.x = pt->x; | |
| prev_c = c; | |
| break; | |
| case 'V': | |
| case 'v': | |
| i++; | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(command, u8) | |
| if (!command) return; | |
| gf_list_add(d_commands, command); | |
| *command = SVG_PATHCOMMAND_L; | |
| GF_SAFEALLOC(pt, SVG_Point) | |
| if (!pt) return; | |
| gf_list_add(d_points, pt); | |
| #endif | |
| i += svg_parse_number(&(d[i]), &(pt->y), 0, out_e); | |
| if (c == 'v') { | |
| pt->y += cur_pt.y; | |
| } | |
| pt->x = cur_pt.x; | |
| cur_pt.y = pt->y; | |
| prev_c = c; | |
| break; | |
| case 'C': | |
| case 'c': | |
| i++; | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(command, u8) | |
| if (!command) return; | |
| gf_list_add(d_commands, command); | |
| *command = SVG_PATHCOMMAND_C; | |
| #endif | |
| for (k=0; k<3; k++) { | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(pt, SVG_Point) | |
| if (!pt) return; | |
| gf_list_add(d_points, pt); | |
| #endif | |
| i += svg_parse_number(&(d[i]), &(pt->x), 0, out_e); | |
| i += svg_parse_number(&(d[i]), &(pt->y), 0, out_e); | |
| if (c == 'c') { | |
| pt->x += cur_pt.x; | |
| pt->y += cur_pt.y; | |
| } | |
| } | |
| cur_pt.x = pt->x; | |
| cur_pt.y = pt->y; | |
| prev_c = c; | |
| break; | |
| case 'S': | |
| case 's': | |
| i++; | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(command, u8) | |
| if (!command) return; | |
| gf_list_add(d_commands, command); | |
| *command = SVG_PATHCOMMAND_S; | |
| #endif | |
| for (k=0; k<2; k++) { | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(pt, SVG_Point) | |
| if (!pt) return; | |
| gf_list_add(d_points, pt); | |
| #endif | |
| i += svg_parse_number(&(d[i]), &(pt->x), 0, out_e); | |
| i += svg_parse_number(&(d[i]), &(pt->y), 0, out_e); | |
| if (c == 's') { | |
| pt->x += cur_pt.x; | |
| pt->y += cur_pt.y; | |
| } | |
| } | |
| cur_pt.x = pt->x; | |
| cur_pt.y = pt->y; | |
| prev_c = c; | |
| break; | |
| case 'Q': | |
| case 'q': | |
| i++; | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(command, u8) | |
| if (!command) return; | |
| gf_list_add(d_commands, command); | |
| *command = SVG_PATHCOMMAND_Q; | |
| #endif | |
| for (k=0; k<2; k++) { | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(pt, SVG_Point) | |
| if (!pt) return; | |
| gf_list_add(d_points, pt); | |
| #endif | |
| i += svg_parse_number(&(d[i]), &(pt->x), 0, out_e); | |
| i += svg_parse_number(&(d[i]), &(pt->y), 0, out_e); | |
| if (c == 'q') { | |
| pt->x += cur_pt.x; | |
| pt->y += cur_pt.y; | |
| } | |
| } | |
| cur_pt.x = pt->x; | |
| cur_pt.y = pt->y; | |
| prev_c = c; | |
| break; | |
| case 'T': | |
| case 't': | |
| i++; | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(command, u8) | |
| if (!command) return; | |
| gf_list_add(d_commands, command); | |
| *command = SVG_PATHCOMMAND_T; | |
| GF_SAFEALLOC(pt, SVG_Point) | |
| if (!pt) return; | |
| gf_list_add(d_points, pt); | |
| #endif | |
| i += svg_parse_number(&(d[i]), &(pt->x), 0, out_e); | |
| i += svg_parse_number(&(d[i]), &(pt->y), 0, out_e); | |
| if (c == 't') { | |
| pt->x += cur_pt.x; | |
| pt->y += cur_pt.y; | |
| } | |
| cur_pt.x = pt->x; | |
| cur_pt.y = pt->y; | |
| prev_c = c; | |
| break; | |
| case 'A': | |
| case 'a': | |
| { | |
| Fixed tmp; | |
| i++; | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(command, u8) | |
| if (!command) return; | |
| gf_list_add(d_commands, command); | |
| *command = SVG_PATHCOMMAND_A; | |
| pt = gf_malloc(sizeof(SVG_Point)); | |
| if (!pt) return; | |
| gf_list_add(d_points, pt); | |
| #endif | |
| i += svg_parse_number(&(d[i]), &(pt->x), 0, out_e); | |
| i += svg_parse_number(&(d[i]), &(pt->y), 0, out_e); | |
| i += svg_parse_number(&(d[i]), &(tmp), 0, out_e); | |
| i += svg_parse_number(&(d[i]), &(tmp), 0, out_e); | |
| i += svg_parse_number(&(d[i]), &(tmp), 0, out_e); | |
| #ifndef REMOVE_ALLOC | |
| pt = gf_malloc(sizeof(SVG_Point)); | |
| if (!pt) return; | |
| gf_list_add(d_points, pt); | |
| #endif | |
| i += svg_parse_number(&(d[i]), &(pt->x), 0, out_e); | |
| i += svg_parse_number(&(d[i]), &(pt->y), 0, out_e); | |
| if (c == 'a') { | |
| pt->x += cur_pt.x; | |
| pt->y += cur_pt.y; | |
| } | |
| cur_pt.x = pt->x; | |
| cur_pt.y = pt->y; | |
| } | |
| prev_c = c; | |
| break; | |
| case 'Z': | |
| case 'z': | |
| i++; | |
| #ifndef REMOVE_ALLOC | |
| GF_SAFEALLOC(command, u8) | |
| if (!command) return; | |
| gf_list_add(d_commands, command); | |
| *command = SVG_PATHCOMMAND_Z; | |
| #endif | |
| prev_c = c; | |
| cur_pt = prev_m_pt; | |
| break; | |
| default: | |
| i--; | |
| switch (prev_c) { | |
| case 'M': | |
| c = 'L'; | |
| break; | |
| case 'm': | |
| c = 'l'; | |
| break; | |
| default: | |
| c = prev_c; | |
| } | |
| goto next_command; | |
| } | |
| } | |
| } | |
| } | |
| #endif | |
| static void svg_parse_iri(GF_Node *elt, XMLRI *iri, char *attribute_content) | |
| { | |
| if (iri->string) { | |
| gf_free(iri->string); | |
| iri->string = NULL; | |
| } | |
| /* TODO: Handle xpointer(id()) syntax */ | |
| if (attribute_content[0] == '#') { | |
| iri->string = gf_strdup(attribute_content); | |
| iri->target = gf_sg_find_node_by_name(elt->sgprivate->scenegraph, attribute_content + 1); | |
| if (!iri->target) { | |
| iri->type = XMLRI_STRING; | |
| } else { | |
| iri->type = XMLRI_ELEMENTID; | |
| gf_node_register_iri(elt->sgprivate->scenegraph, iri); | |
| } | |
| } else { | |
| iri->type = XMLRI_STRING; | |
| iri->string = gf_strdup(attribute_content); | |
| } | |
| } | |
| static void svg_parse_idref(GF_Node *elt, XML_IDREF *iri, char *attribute_content) | |
| { | |
| iri->type = XMLRI_ELEMENTID; | |
| iri->target = gf_sg_find_node_by_name(elt->sgprivate->scenegraph, attribute_content); | |
| if (!iri->target) { | |
| iri->string = gf_strdup(attribute_content); | |
| } else { | |
| gf_node_register_iri(elt->sgprivate->scenegraph, iri); | |
| } | |
| } | |
| /* Parses a paint attribute: none, inherit or color */ | |
| static void svg_parse_paint(GF_Node *n, SVG_Paint *paint, char *attribute_content, GF_Err *out_e) | |
| { | |
| if (!strcmp(attribute_content, "none")) { | |
| paint->type = SVG_PAINT_NONE; | |
| } else if (!strcmp(attribute_content, "inherit")) { | |
| paint->type = SVG_PAINT_INHERIT; | |
| } else if (!strncmp(attribute_content, "url(", 4) ) { | |
| char *ext = strrchr(attribute_content, ')'); | |
| paint->type = SVG_PAINT_URI; | |
| if (ext) ext[0] = 0; | |
| svg_parse_iri(n, &paint->iri, attribute_content+4); | |
| if (ext) ext[0] = ')'; | |
| } else { | |
| paint->type = SVG_PAINT_COLOR; | |
| svg_parse_color(&paint->color, attribute_content, out_e); | |
| } | |
| } | |
| /* Parses a length which is a number with a unit */ | |
| static u32 svg_parse_length(SVG_Number *number, char *value_string, Bool clamp0to1, GF_Err *out_e) | |
| { | |
| char c = '\0'; | |
| char *unit = NULL; | |
| u32 len = 0; | |
| u32 unit_pos = 0; | |
| u32 unit_len = 0; | |
| u32 read_chars; | |
| if (!number || !value_string) return 0; | |
| if (!strcmp(value_string, "inherit")) { | |
| number->type = SVG_NUMBER_INHERIT; | |
| return 7; | |
| } else if (!strcmp(value_string, "auto")) { | |
| number->type = SVG_NUMBER_AUTO; | |
| return 4; | |
| } else if (!strcmp(value_string, "auto-reverse")) { | |
| number->type = SVG_NUMBER_AUTO_REVERSE; | |
| return 12; | |
| } else if ((unit = strstr(value_string, "%")) ) { | |
| number->type = SVG_NUMBER_PERCENTAGE; | |
| unit_len = 1; | |
| } else if ((unit = strstr(value_string, "em"))) { | |
| number->type = SVG_NUMBER_EMS; | |
| } else if ((unit = strstr(value_string, "ex"))) { | |
| number->type = SVG_NUMBER_EXS; | |
| } else if ((unit = strstr(value_string, "px"))) { | |
| number->type = SVG_NUMBER_PX; | |
| } else if ((unit = strstr(value_string, "cm"))) { | |
| number->type = SVG_NUMBER_CM; | |
| } else if ((unit = strstr(value_string, "mm"))) { | |
| number->type = SVG_NUMBER_MM; | |
| } else if ((unit = strstr(value_string, "in"))) { | |
| number->type = SVG_NUMBER_IN; | |
| } else if ((unit = strstr(value_string, "pt"))) { | |
| number->type = SVG_NUMBER_PT; | |
| } else if ((unit = strstr(value_string, "pc"))) { | |
| number->type = SVG_NUMBER_PC; | |
| } else { | |
| number->type = SVG_NUMBER_VALUE; | |
| } | |
| if (unit) { | |
| if (!unit_len) unit_len = 2; | |
| unit_pos = (u32) (unit - value_string); | |
| /* setting the first unit character to 0 for the svg_parse_number method to finish */ | |
| c = value_string[unit_pos]; | |
| value_string[unit_pos] = 0; | |
| } | |
| read_chars = svg_parse_number(value_string, &(number->value), 0, out_e); | |
| if (unit) { | |
| value_string[unit_pos] = c; | |
| } | |
| if (!read_chars) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Error in parsing: %s\n", value_string)); | |
| len = 0; | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } else { | |
| len = unit_len + read_chars; | |
| } | |
| if (clamp0to1) number->value = MAX(0, MIN(1, number->value)); | |
| return len; | |
| } | |
| static void svg_parse_visibility(SVG_Visibility *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_VISIBILITY_INHERIT; | |
| } else if (!strcmp(value_string, "visible")) { | |
| *value = SVG_VISIBILITY_VISIBLE; | |
| } else if (!strcmp(value_string, "hidden")) { | |
| *value = SVG_VISIBILITY_HIDDEN; | |
| } else if (!strcmp(value_string, "collapse")) { | |
| *value = SVG_VISIBILITY_COLLAPSE; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_display(SVG_Display *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_DISPLAY_INHERIT; | |
| } else if (!strcmp(value_string, "none")) { | |
| *value = SVG_DISPLAY_NONE; | |
| } else if (!strcmp(value_string, "inline")) { | |
| *value = SVG_DISPLAY_INLINE; | |
| } else if (!strcmp(value_string, "block")) { | |
| *value = SVG_DISPLAY_BLOCK; | |
| } else if (!strcmp(value_string, "list-item")) { | |
| *value = SVG_DISPLAY_LIST_ITEM; | |
| } else if (!strcmp(value_string, "run-in")) { | |
| *value = SVG_DISPLAY_RUN_IN; | |
| } else if (!strcmp(value_string, "compact")) { | |
| *value = SVG_DISPLAY_COMPACT; | |
| } else if (!strcmp(value_string, "marker")) { | |
| *value = SVG_DISPLAY_MARKER; | |
| } else if (!strcmp(value_string, "table")) { | |
| *value = SVG_DISPLAY_TABLE; | |
| } else if (!strcmp(value_string, "inline-table")) { | |
| *value = SVG_DISPLAY_INLINE_TABLE; | |
| } else if (!strcmp(value_string, "table-row-group")) { | |
| *value = SVG_DISPLAY_TABLE_ROW_GROUP; | |
| } else if (!strcmp(value_string, "table-header-group")) { | |
| *value = SVG_DISPLAY_TABLE_HEADER_GROUP; | |
| } else if (!strcmp(value_string, "table-footer-group")) { | |
| *value = SVG_DISPLAY_TABLE_FOOTER_GROUP; | |
| } else if (!strcmp(value_string, "table-row")) { | |
| *value = SVG_DISPLAY_TABLE_ROW; | |
| } else if (!strcmp(value_string, "table-column-group")) { | |
| *value = SVG_DISPLAY_TABLE_COLUMN_GROUP; | |
| } else if (!strcmp(value_string, "table-column")) { | |
| *value = SVG_DISPLAY_TABLE_COLUMN; | |
| } else if (!strcmp(value_string, "table-cell")) { | |
| *value = SVG_DISPLAY_TABLE_CELL; | |
| } else if (!strcmp(value_string, "table-caption")) { | |
| *value = SVG_DISPLAY_TABLE_CAPTION; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_displayalign(SVG_DisplayAlign *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_DISPLAYALIGN_INHERIT; | |
| } else if (!strcmp(value_string, "auto")) { | |
| *value = SVG_DISPLAYALIGN_AUTO; | |
| } else if (!strcmp(value_string, "before")) { | |
| *value = SVG_DISPLAYALIGN_BEFORE; | |
| } else if (!strcmp(value_string, "center")) { | |
| *value = SVG_DISPLAYALIGN_CENTER; | |
| } else if (!strcmp(value_string, "after")) { | |
| *value = SVG_DISPLAYALIGN_AFTER; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_textalign(SVG_TextAlign *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_TEXTALIGN_INHERIT; | |
| } else if (!strcmp(value_string, "start")) { | |
| *value = SVG_TEXTALIGN_START; | |
| } else if (!strcmp(value_string, "center")) { | |
| *value = SVG_TEXTALIGN_CENTER; | |
| } else if (!strcmp(value_string, "end")) { | |
| *value = SVG_TEXTALIGN_END; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_pointerevents(SVG_PointerEvents *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_POINTEREVENTS_INHERIT; | |
| } else if (!strcmp(value_string, "visiblePainted")) { | |
| *value = SVG_POINTEREVENTS_VISIBLEPAINTED; | |
| } else if (!strcmp(value_string, "visibleFill")) { | |
| *value = SVG_POINTEREVENTS_VISIBLEFILL; | |
| } else if (!strcmp(value_string, "visibleStroke")) { | |
| *value = SVG_POINTEREVENTS_VISIBLESTROKE; | |
| } else if (!strcmp(value_string, "visible")) { | |
| *value = SVG_POINTEREVENTS_VISIBLE; | |
| } else if (!strcmp(value_string, "painted")) { | |
| *value = SVG_POINTEREVENTS_PAINTED; | |
| } else if (!strcmp(value_string, "fill")) { | |
| *value = SVG_POINTEREVENTS_FILL; | |
| } else if (!strcmp(value_string, "stroke")) { | |
| *value = SVG_POINTEREVENTS_STROKE; | |
| } else if (!strcmp(value_string, "all")) { | |
| *value = SVG_POINTEREVENTS_ALL; | |
| } else if (!strcmp(value_string, "boundingBox")) { | |
| *value = SVG_POINTEREVENTS_BOUNDINGBOX; | |
| } else if (!strcmp(value_string, "none")) { | |
| *value = SVG_POINTEREVENTS_NONE; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_renderinghint(SVG_RenderingHint *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_RENDERINGHINT_INHERIT; | |
| } else if (!strcmp(value_string, "auto")) { | |
| *value = SVG_RENDERINGHINT_AUTO; | |
| } else if (!strcmp(value_string, "optimizeQuality")) { | |
| *value = SVG_RENDERINGHINT_OPTIMIZEQUALITY; | |
| } else if (!strcmp(value_string, "optimizeSpeed")) { | |
| *value = SVG_RENDERINGHINT_OPTIMIZESPEED; | |
| } else if (!strcmp(value_string, "optimizeLegibility")) { | |
| *value = SVG_RENDERINGHINT_OPTIMIZELEGIBILITY; | |
| } else if (!strcmp(value_string, "crispEdges")) { | |
| *value = SVG_RENDERINGHINT_CRISPEDGES; | |
| } else if (!strcmp(value_string, "geometricPrecision")) { | |
| *value = SVG_RENDERINGHINT_GEOMETRICPRECISION; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_vectoreffect(SVG_VectorEffect *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_VECTOREFFECT_INHERIT; | |
| } else if (!strcmp(value_string, "none")) { | |
| *value = SVG_VECTOREFFECT_NONE; | |
| } else if (!strcmp(value_string, "non-scaling-stroke")) { | |
| *value = SVG_VECTOREFFECT_NONSCALINGSTROKE; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_playbackorder(SVG_VectorEffect *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "forwardOnly")) { | |
| *value = SVG_PLAYBACKORDER_FORWARDONLY; | |
| } else if (!strcmp(value_string, "all")) { | |
| *value = SVG_PLAYBACKORDER_ALL; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_timelinebegin(SVG_TimelineBegin *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "onStart")) { | |
| *value = SVG_TIMELINEBEGIN_ONSTART; | |
| } else if (!strcmp(value_string, "onLoad")) { | |
| *value = SVG_TIMELINEBEGIN_ONLOAD; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_xmlspace(XML_Space *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "default")) { | |
| *value = XML_SPACE_DEFAULT; | |
| } else if (!strcmp(value_string, "preserve")) { | |
| *value = XML_SPACE_PRESERVE; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_xmlev_propagate(XMLEV_Propagate *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "continue")) { | |
| *value = XMLEVENT_PROPAGATE_CONTINUE; | |
| } else if (!strcmp(value_string, "stop")) { | |
| *value = XMLEVENT_PROPAGATE_STOP; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_xmlev_defaultAction(XMLEV_DefaultAction *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "cancel")) { | |
| *value = XMLEVENT_DEFAULTACTION_CANCEL; | |
| } else if (!strcmp(value_string, "perform")) { | |
| *value = XMLEVENT_DEFAULTACTION_PERFORM; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_xmlev_phase(XMLEV_Phase *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "default")) { | |
| *value = XMLEVENT_PHASE_DEFAULT; | |
| } else if (!strcmp(value_string, "capture")) { | |
| *value = XMLEVENT_PHASE_CAPTURE; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_overflow(SVG_Overflow *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_OVERFLOW_INHERIT; | |
| } else if (!strcmp(value_string, "visible")) { | |
| *value = SVG_OVERFLOW_VISIBLE; | |
| } else if (!strcmp(value_string, "hidden")) { | |
| *value = SVG_OVERFLOW_HIDDEN; | |
| } else if (!strcmp(value_string, "scroll")) { | |
| *value = SVG_OVERFLOW_SCROLL; | |
| } else if (!strcmp(value_string, "auto")) { | |
| *value = SVG_OVERFLOW_AUTO; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_textanchor(SVG_TextAnchor *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_TEXTANCHOR_INHERIT; | |
| } else if (!strcmp(value_string, "start")) { | |
| *value = SVG_TEXTANCHOR_START; | |
| } else if (!strcmp(value_string, "middle")) { | |
| *value = SVG_TEXTANCHOR_MIDDLE; | |
| } else if (!strcmp(value_string, "end")) { | |
| *value = SVG_TEXTANCHOR_END; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_clipfillrule(SVG_FillRule *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_FILLRULE_INHERIT; | |
| } else if (!strcmp(value_string, "nonzero")) { | |
| *value = SVG_FILLRULE_NONZERO; | |
| } else if (!strcmp(value_string, "evenodd")) { | |
| *value = SVG_FILLRULE_EVENODD; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_strokelinejoin(SVG_StrokeLineJoin *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_STROKELINEJOIN_INHERIT; | |
| } else if (!strcmp(value_string, "miter")) { | |
| *value = SVG_STROKELINEJOIN_MITER; | |
| } else if (!strcmp(value_string, "round")) { | |
| *value = SVG_STROKELINEJOIN_ROUND; | |
| } else if (!strcmp(value_string, "bevel")) { | |
| *value = SVG_STROKELINEJOIN_BEVEL; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_strokelinecap(SVG_StrokeLineCap *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_STROKELINECAP_INHERIT; | |
| } else if (!strcmp(value_string, "butt")) { | |
| *value = SVG_STROKELINECAP_BUTT; | |
| } else if (!strcmp(value_string, "round")) { | |
| *value = SVG_STROKELINECAP_ROUND; | |
| } else if (!strcmp(value_string, "square")) { | |
| *value = SVG_STROKELINECAP_SQUARE; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_fontfamily(SVG_FontFamily *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| value->type = SVG_FONTFAMILY_INHERIT; | |
| } else { | |
| value->type = SVG_FONTFAMILY_VALUE; | |
| value->value = gf_strdup(value_string); | |
| } | |
| } | |
| static void svg_parse_fontstyle(SVG_FontStyle *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_FONTSTYLE_INHERIT; | |
| } else if (!strcmp(value_string, "normal")) { | |
| *value = SVG_FONTSTYLE_NORMAL; | |
| } else if (!strcmp(value_string, "italic")) { | |
| *value = SVG_FONTSTYLE_ITALIC; | |
| } else if (!strcmp(value_string, "oblique")) { | |
| *value = SVG_FONTSTYLE_OBLIQUE; | |
| } else if (!strcmp(value_string, "all")) { | |
| *value = SVG_FONTSTYLE_INHERIT; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_fontweight(SVG_FontWeight *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_FONTWEIGHT_INHERIT; | |
| } else if (!strcmp(value_string, "normal")) { | |
| *value = SVG_FONTWEIGHT_NORMAL; | |
| } else if (!strcmp(value_string, "bold")) { | |
| *value = SVG_FONTWEIGHT_BOLD; | |
| } else if (!strcmp(value_string, "bolder")) { | |
| *value = SVG_FONTWEIGHT_BOLDER; | |
| } else if (!strcmp(value_string, "lighter")) { | |
| *value = SVG_FONTWEIGHT_LIGHTER; | |
| } else if (!strcmp(value_string, "100")) { | |
| *value = SVG_FONTWEIGHT_100; | |
| } else if (!strcmp(value_string, "200")) { | |
| *value = SVG_FONTWEIGHT_200; | |
| } else if (!strcmp(value_string, "300")) { | |
| *value = SVG_FONTWEIGHT_300; | |
| } else if (!strcmp(value_string, "400")) { | |
| *value = SVG_FONTWEIGHT_400; | |
| } else if (!strcmp(value_string, "500")) { | |
| *value = SVG_FONTWEIGHT_500; | |
| } else if (!strcmp(value_string, "600")) { | |
| *value = SVG_FONTWEIGHT_600; | |
| } else if (!strcmp(value_string, "700")) { | |
| *value = SVG_FONTWEIGHT_700; | |
| } else if (!strcmp(value_string, "800")) { | |
| *value = SVG_FONTWEIGHT_800; | |
| } else if (!strcmp(value_string, "900")) { | |
| *value = SVG_FONTWEIGHT_900; | |
| } else if (!strcmp(value_string, "all")) { | |
| *value = SVG_FONTWEIGHT_INHERIT; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_fontvariant(SVG_FontVariant *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SVG_FONTVARIANT_INHERIT; | |
| } else if (!strcmp(value_string, "normal")) { | |
| *value = SVG_FONTVARIANT_NORMAL; | |
| } else if (!strcmp(value_string, "small-caps")) { | |
| *value = SVG_FONTVARIANT_SMALLCAPS; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_boolean(SVG_Boolean *value, char *value_string, GF_Err *out_e) | |
| { | |
| /*simple for text editable*/ | |
| if (!strcmp(value_string, "1") || !strcmp(value_string, "true") || !strcmp(value_string, "simple")) | |
| *value = 1; | |
| else | |
| *value = 0; | |
| } | |
| static void smil_parse_time_list(GF_Node *e, GF_List *values, char *begin_or_end_list) | |
| { | |
| SMIL_Time *value; | |
| char value_string[1025]; | |
| char *str = begin_or_end_list, *tmp; | |
| u32 len; | |
| /* get rid of leading spaces */ | |
| while (*str == ' ') str++; | |
| value_string[1024] = 0; | |
| while (1) { | |
| tmp = strchr(str, ';'); | |
| if (tmp) len = (u32) (tmp-str); | |
| else len = (u32) strlen(str); | |
| if (len>1024) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] SMIL time list attribute too long, max supported 1024 bytes\n")); | |
| goto err; | |
| } | |
| memcpy(value_string, str, len); | |
| while ((len > 0) && (value_string[len - 1] == ' ')) | |
| len--; | |
| value_string[len] = 0; | |
| GF_SAFEALLOC(value, SMIL_Time) | |
| if (!value) break; | |
| gf_list_add(values, value); | |
| if (smil_parse_time(e, value, value_string) != GF_OK) goto err; | |
| if (!tmp) break; | |
| str = tmp + 1; | |
| while (*str == ' ') str++; | |
| } | |
| /* sorting timing values */ | |
| if (gf_list_count(values) > 1) { | |
| SMIL_Time *sv; | |
| GF_List *sorted = gf_list_new(); | |
| u32 i, count; | |
| do { | |
| u8 added = 0; | |
| SMIL_Time *v = (SMIL_Time*)gf_list_get(values, 0); | |
| gf_list_rem(values, 0); | |
| count = gf_list_count(sorted); | |
| for (i=0; i<count; i++) { | |
| sv = (SMIL_Time*)gf_list_get(sorted, i); | |
| if (v->type >= GF_SMIL_TIME_EVENT) { | |
| /* unresolved or indefinite so add at the end of the sorted list */ | |
| gf_list_add(sorted, v); | |
| added = 1; | |
| break; | |
| } else { | |
| if (sv->type >= GF_SMIL_TIME_EVENT) { | |
| gf_list_insert(sorted, v, i); | |
| added = 1; | |
| break; | |
| } else { | |
| if (v->clock <= sv->clock) { | |
| gf_list_insert(sorted, v, i); | |
| added = 1; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| if (!added) gf_list_add(sorted, v); | |
| } while (gf_list_count(values) > 0); | |
| count = gf_list_count(sorted); | |
| for (i = 0; i < count; i++) { | |
| gf_list_add(values, gf_list_get(sorted, i)); | |
| } | |
| gf_list_del(sorted); | |
| } | |
| return; | |
| err: | |
| /* See SVG spec: | |
| "If the 'begin' attribute is | |
| syntactically invalid, in the list itself or in any of the individual | |
| list values, it is equivalent to a single 'begin' value of 'indefinite'."*/ | |
| len = gf_list_count(values); | |
| while (len) { | |
| SMIL_Time *v = (SMIL_Time*)gf_list_get(values, 0); | |
| if (v->element_id) gf_free(v->element_id); | |
| gf_list_rem(values, 0); | |
| gf_free(v); | |
| len--; | |
| } | |
| GF_SAFEALLOC(value, SMIL_Time) | |
| if (!value) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Fail to allocate SMIL time\n")); | |
| return; | |
| } | |
| gf_list_add(values, value); | |
| switch (e->sgprivate->tag) { | |
| case TAG_SVG_discard: | |
| value->type = GF_SMIL_TIME_CLOCK; | |
| value->clock = 0; | |
| break; | |
| default: | |
| value->type = GF_SMIL_TIME_INDEFINITE; | |
| break; | |
| } | |
| return; | |
| } | |
| static void smil_parse_attributeType(SMIL_AttributeType *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "auto")) { | |
| *value = SMIL_ATTRIBUTETYPE_AUTO; | |
| } else if (!strcmp(value_string, "XML")) { | |
| *value = SMIL_ATTRIBUTETYPE_XML; | |
| } else if (!strcmp(value_string, "CSS")) { | |
| *value = SMIL_ATTRIBUTETYPE_CSS; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void smil_parse_min_max_dur_repeatdur(SMIL_Duration *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "indefinite")) { | |
| value->type = SMIL_DURATION_INDEFINITE; | |
| } else if (!strcmp(value_string, "media")) { | |
| value->type = SMIL_DURATION_MEDIA; | |
| } else { | |
| Double ftime; | |
| if ((svg_parse_clock_value(value_string, &ftime) == GF_OK) && (ftime >= 0)) { | |
| value->clock_value = ftime; | |
| value->type = SMIL_DURATION_DEFINED; | |
| } else { | |
| /* WARNING: Should this attribute in error be removed ? */ | |
| value->type = SMIL_DURATION_INDEFINITE; | |
| } | |
| } | |
| } | |
| static void smil_parse_repeatcount(SMIL_RepeatCount *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "indefinite")) { | |
| value->type = SMIL_REPEATCOUNT_INDEFINITE; | |
| } else { | |
| Float _val; | |
| if (sscanf(value_string, "%f", &_val)==1) { | |
| value->type = SMIL_REPEATCOUNT_DEFINED; | |
| value->count = FLT2FIX(_val); | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| } | |
| static void smil_parse_fill(SMIL_Fill *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "freeze")) { | |
| *value = SMIL_FILL_FREEZE; | |
| } else if (!strcmp(value_string, "remove")) { | |
| *value = SMIL_FILL_REMOVE; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void smil_parse_restart(SMIL_Restart *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "always")) { | |
| *value = SMIL_RESTART_ALWAYS; | |
| } else if (!strcmp(value_string, "whenNotActive")) { | |
| *value = SMIL_RESTART_WHENNOTACTIVE; | |
| } else if (!strcmp(value_string, "never")) { | |
| *value = SMIL_RESTART_NEVER; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void smil_parse_calcmode(SMIL_CalcMode *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "discrete")) { | |
| *value = SMIL_CALCMODE_DISCRETE; | |
| } else if (!strcmp(value_string, "linear")) { | |
| *value = SMIL_CALCMODE_LINEAR; | |
| } else if (!strcmp(value_string, "paced")) { | |
| *value = SMIL_CALCMODE_PACED; | |
| } else if (!strcmp(value_string, "spline")) { | |
| *value = SMIL_CALCMODE_SPLINE; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void smil_parse_additive(SMIL_Additive *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "replace")) { | |
| *value = SMIL_ADDITIVE_REPLACE; | |
| } else if (!strcmp(value_string, "sum")) { | |
| *value = SMIL_ADDITIVE_SUM; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void smil_parse_accumulate(SMIL_Accumulate *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "none")) { | |
| *value = SMIL_ACCUMULATE_NONE; | |
| } else if (!strcmp(value_string, "sum")) { | |
| *value = SMIL_ACCUMULATE_SUM; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void smil_parse_syncBehaviorOrDefault(SMIL_SyncBehavior *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| *value = SMIL_SYNCBEHAVIOR_INHERIT; | |
| } else if (!strcmp(value_string, "default")) { | |
| *value = SMIL_SYNCBEHAVIOR_DEFAULT; | |
| } else if (!strcmp(value_string, "locked")) { | |
| *value = SMIL_SYNCBEHAVIOR_LOCKED; | |
| } else if (!strcmp(value_string, "canSlip")) { | |
| *value = SMIL_SYNCBEHAVIOR_CANSLIP; | |
| } else if (!strcmp(value_string, "independent")) { | |
| *value = SMIL_SYNCBEHAVIOR_INDEPENDENT; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void smil_parse_syncToleranceOrDefault(SMIL_SyncTolerance *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "inherit")) { | |
| value->type = SMIL_SYNCTOLERANCE_INHERIT; | |
| } else if (!strcmp(value_string, "default")) { | |
| value->type = SMIL_SYNCTOLERANCE_DEFAULT; | |
| } else { | |
| value->type = SMIL_SYNCBEHAVIOR_LOCKED; | |
| svg_parse_clock_value(value_string, &(value->value)); | |
| } | |
| } | |
| static void svg_parse_viewbox(SVG_ViewBox *value, char *value_string, GF_Err *out_e) | |
| { | |
| u32 read_chars; | |
| char *str = value_string; | |
| if (!strcmp(str, "none")) { | |
| value->is_set = 0; | |
| } else { | |
| u32 i = 0; | |
| value->is_set = 1; | |
| read_chars = svg_parse_number(&(str[i]), &(value->x), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(str[i]), &(value->y), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(str[i]), &(value->width), 0, out_e); | |
| if (!read_chars) return; | |
| i += read_chars; | |
| read_chars = svg_parse_number(&(str[i]), &(value->height), 0, out_e); | |
| if (!read_chars) return; | |
| // i += read_chars; | |
| } | |
| } | |
| /* Parses a list of coordinates or a list of lengths (in SVG, length and coordinate is the same type )*/ | |
| static void svg_parse_coordinates(GF_List *values, char *value_string, GF_Err *out_e) | |
| { | |
| SVG_Coordinate *c; | |
| u32 i = 0; | |
| char *str = value_string; | |
| u32 len = (u32) strlen(str); | |
| while (gf_list_count(values)) { | |
| c = (SVG_Coordinate*)gf_list_get(values, 0); | |
| gf_list_rem(values, 0); | |
| gf_free(c); | |
| } | |
| while (i < len) { | |
| u32 sub; | |
| GF_SAFEALLOC(c, SVG_Coordinate) | |
| if (!c) break; | |
| sub = svg_parse_length(c, &(str[i]), 0, out_e); | |
| if (!sub) { | |
| gf_free(c); | |
| return; | |
| } | |
| i+=sub; | |
| gf_list_add(values, c); | |
| } | |
| } | |
| /* Parse a point as a pair of number without units */ | |
| u32 svg_parse_point(SVG_Point *p, char *value_string, GF_Err *out_e) | |
| { | |
| u32 i = 0, j = 0; | |
| i = svg_parse_number(&(value_string[i]), &(p->x), 0, out_e); | |
| /* TODO: handle cases where a point has an invalid syntax */ | |
| j = svg_parse_number(&(value_string[i]), &(p->y), 0, out_e); | |
| /* we need to detect an odd number of coordinates in polygon points list | |
| cf. http://www.w3.org/TR/SVGMobile12/shapes.html#PolygonElement | |
| see svg_parse_points */ | |
| if (j == 0) return 0; | |
| else return i+j; | |
| } | |
| /* Parses the points attribute of a polygon or polyline element */ | |
| static void svg_parse_points(GF_List *values, char *value_string, GF_Err *out_e) | |
| { | |
| u32 i = 0, j; | |
| char *str = value_string; | |
| u32 len = (u32) strlen(str); | |
| while (i < len) { | |
| SVG_Point *p; | |
| GF_SAFEALLOC(p, SVG_Point) | |
| if (!p) break; | |
| j = svg_parse_point(p, &str[i], out_e); | |
| if (j == 0) { | |
| /* cf. http://www.w3.org/TR/SVGMobile12/shapes.html#PolygonElement | |
| If an odd number of coordinates is provided, then the element | |
| is treated as if the attribute had not been specified.*/ | |
| while (gf_list_count(values)) { | |
| p = (SVG_Point *)gf_list_get(values, 0); | |
| gf_free(p); | |
| gf_list_rem(values, 0); | |
| } | |
| return; | |
| } | |
| i += j; | |
| gf_list_add(values, p); | |
| } | |
| } | |
| /* Parses a list of numbers */ | |
| static void svg_parse_numbers(GF_List *values, char *value_string, Bool is_angle, GF_Err *out_e) | |
| { | |
| u32 read_chars; | |
| u32 i = 0; | |
| char *str = value_string; | |
| u32 len = (u32) strlen(str); | |
| while (i < len) { | |
| Fixed *f; | |
| GF_SAFEALLOC(f, Fixed) | |
| if (!f) break; | |
| read_chars = svg_parse_number(&(str[i]), f, is_angle, out_e); | |
| if (!read_chars) { | |
| gf_free(f); | |
| return; | |
| } | |
| i += read_chars; | |
| gf_list_add(values, f); | |
| } | |
| } | |
| static void svg_string_list_add(GF_List *values, char *string, u32 string_type) | |
| { | |
| XMLRI *iri; | |
| switch (string_type) { | |
| case 1: | |
| iri = (XMLRI*)gf_malloc(sizeof(XMLRI)); | |
| iri->type = XMLRI_STRING; | |
| iri->string = gf_strdup(string); | |
| gf_list_add(values, iri); | |
| break; | |
| default: | |
| gf_list_add(values, gf_strdup(string)); | |
| break; | |
| } | |
| } | |
| static void svg_parse_strings(GF_List *values, char *value_string, u32 string_type) | |
| { | |
| char *next, *sep = value_string; | |
| while (gf_list_count(values)) { | |
| next = (char*)gf_list_last(values); | |
| gf_list_rem_last(values); | |
| gf_free(next); | |
| } | |
| while (1) { | |
| while (sep && sep[0]==' ') sep++; | |
| if (!sep || !sep[0]) break; | |
| next = sep+1; | |
| while (next[0]) { | |
| if (strchr(" ;,", next[0])) break; | |
| next++; | |
| } | |
| if (!next[0]) { | |
| svg_string_list_add(values, sep, string_type); | |
| break; | |
| } | |
| next[0]=0; | |
| svg_string_list_add(values, sep, string_type); | |
| next[0]=';'; | |
| sep = next+1; | |
| while (sep && sep[0] && strchr(" ,;", sep[0])) sep++; | |
| } | |
| } | |
| static void svg_parse_strokedasharray(SVG_StrokeDashArray *value, char *value_string, GF_Err *out_e) | |
| { | |
| u32 read_chars; | |
| if (!strcmp(value_string, "none")) { | |
| value->type = SVG_STROKEDASHARRAY_NONE; | |
| } else if (!strcmp(value_string, "inherit")) { | |
| value->type = SVG_STROKEDASHARRAY_INHERIT; | |
| } else { | |
| UnitArray *vals = &(value->array); | |
| GF_List *values = gf_list_new(); | |
| u32 i = 0; | |
| u32 len = (u32) strlen(value_string); | |
| char *str = value_string; | |
| while (i < len) { | |
| SVG_Length *f; | |
| GF_SAFEALLOC(f, SVG_Length) | |
| if (!f) break; | |
| read_chars = svg_parse_length(f, &(str[i]), 0, out_e); | |
| if (!read_chars) { | |
| gf_free(f); | |
| return; | |
| } | |
| i += read_chars; | |
| gf_list_add(values, f); | |
| } | |
| vals->count = gf_list_count(values); | |
| vals->units = (u8 *) gf_malloc(sizeof(u8)*vals->count); | |
| vals->vals = (Fixed *) gf_malloc(sizeof(Fixed)*vals->count); | |
| for (i = 0; i < vals->count; i++) { | |
| SVG_Length *f = (SVG_Length *)gf_list_get(values, i); | |
| vals->vals[i] = f->value; | |
| vals->units[i] = f->type; | |
| gf_free(f); | |
| } | |
| gf_list_del(values); | |
| value->type = SVG_STROKEDASHARRAY_ARRAY; | |
| } | |
| } | |
| static void svg_parse_zoomandpan(SVG_ZoomAndPan *value, char *value_string, GF_Err *out_e) | |
| { | |
| if (!strcmp(value_string, "disable")) { | |
| *value = SVG_ZOOMANDPAN_DISABLE; | |
| } else if (!strcmp(value_string, "magnify")) { | |
| *value = SVG_ZOOMANDPAN_MAGNIFY; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_preserveaspectratio(SVG_PreserveAspectRatio *par, char *attribute_content, GF_Err *out_e) | |
| { | |
| char *content = attribute_content; | |
| while (*content == ' ') content++; | |
| if (strstr(content, "defer")) { | |
| par->defer = 1; | |
| content += 5; | |
| } else { | |
| content = attribute_content; | |
| } | |
| while (*content == ' ') content++; | |
| if (strstr(content, "none")) { | |
| par->align = SVG_PRESERVEASPECTRATIO_NONE; | |
| content+=4; | |
| } else if (strstr(content, "xMinYMin")) { | |
| par->align = SVG_PRESERVEASPECTRATIO_XMINYMIN; | |
| content+=8; | |
| } else if (strstr(content, "xMidYMin")) { | |
| par->align = SVG_PRESERVEASPECTRATIO_XMIDYMIN; | |
| content+=8; | |
| } else if (strstr(content, "xMaxYMin")) { | |
| par->align = SVG_PRESERVEASPECTRATIO_XMAXYMIN; | |
| content+=8; | |
| } else if (strstr(content, "xMinYMid")) { | |
| par->align = SVG_PRESERVEASPECTRATIO_XMINYMID; | |
| content+=8; | |
| } else if (strstr(content, "xMidYMid")) { | |
| par->align = SVG_PRESERVEASPECTRATIO_XMIDYMID; | |
| content+=8; | |
| } else if (strstr(content, "xMaxYMid")) { | |
| par->align = SVG_PRESERVEASPECTRATIO_XMAXYMID; | |
| content+=8; | |
| } else if (strstr(content, "xMinYMax")) { | |
| par->align = SVG_PRESERVEASPECTRATIO_XMINYMAX; | |
| content+=8; | |
| } else if (strstr(content, "xMidYMax")) { | |
| par->align = SVG_PRESERVEASPECTRATIO_XMIDYMAX; | |
| content+=8; | |
| } else if (strstr(content, "xMaxYMax")) { | |
| par->align = SVG_PRESERVEASPECTRATIO_XMAXYMAX; | |
| content+=8; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| while (*content == ' ') content++; | |
| if (*content == 0) return; | |
| if (strstr(content, "meet")) { | |
| par->meetOrSlice = SVG_MEETORSLICE_MEET; | |
| } else if (strstr(content, "slice")) { | |
| par->meetOrSlice = SVG_MEETORSLICE_SLICE; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_animatetransform_type(SVG_TransformType *anim_transform_type, char *attribute_content, GF_Err *out_e) | |
| { | |
| *anim_transform_type = SVG_TRANSFORM_MATRIX; | |
| if (!strcmp(attribute_content, "scale")) { | |
| *anim_transform_type = SVG_TRANSFORM_SCALE; | |
| } else if (!strcmp(attribute_content, "rotate")) { | |
| *anim_transform_type = SVG_TRANSFORM_ROTATE; | |
| } else if (!strcmp(attribute_content, "translate")) { | |
| *anim_transform_type = SVG_TRANSFORM_TRANSLATE; | |
| } else if (!strcmp(attribute_content, "skewX")) { | |
| *anim_transform_type = SVG_TRANSFORM_SKEWX; | |
| } else if (!strcmp(attribute_content, "skewY")) { | |
| *anim_transform_type = SVG_TRANSFORM_SKEWY; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_focushighlight(SVG_FocusHighlight *fh, char *attribute_content, GF_Err *out_e) | |
| { | |
| if (!strcmp(attribute_content, "auto")) { | |
| *fh = SVG_FOCUSHIGHLIGHT_AUTO; | |
| } else if (!strcmp(attribute_content, "none")) { | |
| *fh = SVG_FOCUSHIGHLIGHT_NONE; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_focusable(SVG_Focusable *f, char *attribute_content, GF_Err *out_e) | |
| { | |
| if (!strcmp(attribute_content, "true")) { | |
| *f = SVG_FOCUSABLE_TRUE; | |
| } else if (!strcmp(attribute_content, "false")) { | |
| *f = SVG_FOCUSABLE_FALSE; | |
| } else if (!strcmp(attribute_content, "auto")) { | |
| *f = SVG_FOCUSABLE_AUTO; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_initialvisibility(SVG_InitialVisibility *iv, char *attribute_content, GF_Err *out_e) | |
| { | |
| if (!strcmp(attribute_content, "whenStarted")) { | |
| *iv = SVG_INITIALVISIBILTY_WHENSTARTED; | |
| } else if (!strcmp(attribute_content, "always")) { | |
| *iv = SVG_INITIALVISIBILTY_ALWAYS; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_overlay(SVG_Overlay *o, char *attribute_content, GF_Err *out_e) | |
| { | |
| if (!strcmp(attribute_content, "none")) { | |
| *o = SVG_OVERLAY_NONE; | |
| } else if (!strcmp(attribute_content, "top")) { | |
| *o = SVG_OVERLAY_TOP; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_transformbehavior(SVG_TransformBehavior *tb, char *attribute_content, GF_Err *out_e) | |
| { | |
| if (!strcmp(attribute_content, "geometric")) { | |
| *tb = SVG_TRANSFORMBEHAVIOR_GEOMETRIC; | |
| } else if (!strcmp(attribute_content, "pinned")) { | |
| *tb = SVG_TRANSFORMBEHAVIOR_PINNED; | |
| } else if (!strcmp(attribute_content, "pinned90")) { | |
| *tb = SVG_TRANSFORMBEHAVIOR_PINNED90; | |
| } else if (!strcmp(attribute_content, "pinned180")) { | |
| *tb = SVG_TRANSFORMBEHAVIOR_PINNED180; | |
| } else if (!strcmp(attribute_content, "pinned270")) { | |
| *tb = SVG_TRANSFORMBEHAVIOR_PINNED270; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_focus(GF_Node *e, SVG_Focus *o, char *attribute_content, GF_Err *out_e) | |
| { | |
| if (o->target.string) gf_free(o->target.string); | |
| o->target.string = NULL; | |
| o->target.target = NULL; | |
| if (!strcmp(attribute_content, "self")) o->type = SVG_FOCUS_SELF; | |
| else if (!strcmp(attribute_content, "auto")) o->type = SVG_FOCUS_AUTO; | |
| else if (!strnicmp(attribute_content, "url(", 4)) { | |
| char *sep = strrchr(attribute_content, ')'); | |
| if (sep) sep[0] = 0; | |
| o->type = SVG_FOCUS_IRI; | |
| svg_parse_iri(e, &o->target, attribute_content+4); | |
| if (sep) sep[0] = ')'; | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| static void svg_parse_clippath(GF_Node *e, SVG_ClipPath *o, char *attribute_content, GF_Err *out_e) | |
| { | |
| if (o->target.string) gf_free(o->target.string); | |
| o->target.string = NULL; | |
| o->target.target = NULL; | |
| if (!strnicmp(attribute_content, "url(", 4)) { | |
| char *sep = strrchr(attribute_content, ')'); | |
| if (sep) sep[0] = 0; | |
| svg_parse_iri(e, &o->target, attribute_content+4); | |
| if (sep) sep[0] = ')'; | |
| } else if (!strcmp(attribute_content, "none")) { | |
| } else { | |
| *out_e = GF_NON_COMPLIANT_BITSTREAM; | |
| } | |
| } | |
| /* end of Basic SVG datatype parsing functions */ | |
| void svg_parse_one_anim_value(GF_Node *n, SMIL_AnimateValue *anim_value, char *attribute_content, u8 anim_value_type, GF_Err *out_e) | |
| { | |
| GF_FieldInfo info; | |
| info.fieldType = anim_value_type; | |
| info.far_ptr = gf_svg_create_attribute_value(anim_value_type); | |
| if (info.far_ptr) { | |
| *out_e = gf_svg_parse_attribute(n, &info, attribute_content, 0); | |
| } | |
| anim_value->value = info.far_ptr; | |
| anim_value->type = anim_value_type; | |
| } | |
| void svg_parse_anim_values(GF_Node *n, SMIL_AnimateValues *anim_values, char *anim_values_string, u8 anim_value_type, GF_Err *out_e) | |
| { | |
| u32 i = 0; | |
| char *str; | |
| s32 psemi = -1; | |
| GF_FieldInfo info; | |
| info.name = NULL; | |
| info.fieldType = anim_value_type; | |
| anim_values->type = anim_value_type; | |
| str = anim_values_string; | |
| while (1) { | |
| if (str[i] == ';' || str[i] == 0) { | |
| u32 single_value_len = 0; | |
| char c; | |
| single_value_len = i - (psemi+1); | |
| c = str [ (psemi+1) + single_value_len]; | |
| str [ (psemi+1) + single_value_len] = 0; | |
| info.far_ptr = gf_svg_create_attribute_value(anim_value_type); | |
| if (info.far_ptr) { | |
| gf_svg_parse_attribute(n, &info, str + (psemi+1), anim_value_type); | |
| gf_list_add(anim_values->values, info.far_ptr); | |
| } | |
| str [ (psemi+1) + single_value_len] = c; | |
| psemi = i; | |
| if (!str[i]) return; | |
| } | |
| i++; | |
| } | |
| } | |
| GF_Err laser_parse_choice(LASeR_Choice *choice, char *attribute_content) | |
| { | |
| if (!strcmp(attribute_content, "none")) { | |
| choice->type = LASeR_CHOICE_NONE; | |
| } else if (!strcmp(attribute_content, "all")) { | |
| choice->type = LASeR_CHOICE_ALL; | |
| } else { | |
| choice->type = LASeR_CHOICE_N; | |
| choice->choice_index = atoi(attribute_content); | |
| } | |
| return GF_OK; | |
| } | |
| GF_Err laser_parse_size(LASeR_Size *size, char *attribute_content, GF_Err *out_e) | |
| { | |
| char *str = attribute_content; | |
| u32 i = 0; | |
| i+=svg_parse_number(&(str[i]), &(size->width), 0, out_e); | |
| /*i+=*/ svg_parse_number(&(str[i]), &(size->height), 0, out_e); | |
| return GF_OK; | |
| } | |
| GF_EXPORT | |
| GF_Err gf_svg_parse_element_id(GF_Node *n, const char *nodename, Bool warning_if_defined) | |
| { | |
| GF_SceneGraph *sg = gf_node_get_graph((GF_Node *)n); | |
| u32 id = gf_sg_get_max_node_id(sg) + 1; | |
| gf_node_set_id(n, id, nodename); | |
| return GF_OK; | |
| } | |
| /* Parse an SVG attribute */ | |
| GF_EXPORT | |
| GF_Err gf_svg_parse_attribute(GF_Node *n, GF_FieldInfo *info, char *attribute_content, u8 anim_value_type) | |
| { | |
| GF_Err e = GF_OK; | |
| /* for all attributes, except strings, apply some sort of white space normalization*/ | |
| if (info->fieldType != DOM_String_datatype && strlen(attribute_content)) { | |
| u32 i, len; | |
| /*remove spaces at the beginning*/ | |
| while (attribute_content[0] && (strchr("\r\n\t ", attribute_content[0]))) | |
| attribute_content++; | |
| /*change all special chars in spaces*/ | |
| i=0; | |
| len = (u32) strlen(attribute_content); | |
| while (i<len) { | |
| if (strchr("\r\n\t", attribute_content[i])) | |
| attribute_content[i] = ' '; | |
| i++; | |
| } | |
| /*remove spaces in the end*/ | |
| while (len && attribute_content[len-1]==' ') { | |
| attribute_content[len-1] = 0; | |
| len--; | |
| } | |
| } | |
| switch (info->fieldType) { | |
| case SVG_Boolean_datatype: | |
| svg_parse_boolean((SVG_Boolean *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_Color_datatype: | |
| svg_parse_color((SVG_Color *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_Paint_datatype: | |
| svg_parse_paint(n, (SVG_Paint *)info->far_ptr, attribute_content, &e); | |
| break; | |
| /* beginning of keyword type parsing */ | |
| case SVG_FillRule_datatype: | |
| svg_parse_clipfillrule((SVG_FillRule *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_StrokeLineJoin_datatype: | |
| svg_parse_strokelinejoin((SVG_StrokeLineJoin *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_StrokeLineCap_datatype: | |
| svg_parse_strokelinecap((SVG_StrokeLineCap *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_FontStyle_datatype: | |
| svg_parse_fontstyle((SVG_FontStyle *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_FontWeight_datatype: | |
| svg_parse_fontweight((SVG_FontWeight *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_FontVariant_datatype: | |
| svg_parse_fontvariant((SVG_FontVariant *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_TextAnchor_datatype: | |
| svg_parse_textanchor((SVG_TextAnchor *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_Display_datatype: | |
| svg_parse_display((SVG_Display *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_Visibility_datatype: | |
| svg_parse_visibility((SVG_Visibility *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_Overflow_datatype: | |
| svg_parse_overflow((SVG_Overflow *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_ZoomAndPan_datatype: | |
| svg_parse_zoomandpan((SVG_ZoomAndPan *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_DisplayAlign_datatype: | |
| svg_parse_displayalign((SVG_DisplayAlign *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_TextAlign_datatype: | |
| svg_parse_textalign((SVG_TextAlign *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_PointerEvents_datatype: | |
| svg_parse_pointerevents((SVG_PointerEvents *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_RenderingHint_datatype: | |
| svg_parse_renderinghint((SVG_RenderingHint *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_VectorEffect_datatype: | |
| svg_parse_vectoreffect((SVG_VectorEffect *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_PlaybackOrder_datatype: | |
| svg_parse_playbackorder((SVG_PlaybackOrder *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_TimelineBegin_datatype: | |
| svg_parse_timelinebegin((SVG_TimelineBegin *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case XML_Space_datatype: | |
| svg_parse_xmlspace((XML_Space *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case XMLEV_Propagate_datatype: | |
| svg_parse_xmlev_propagate((XMLEV_Propagate *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case XMLEV_DefaultAction_datatype: | |
| svg_parse_xmlev_defaultAction((XMLEV_DefaultAction *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case XMLEV_Phase_datatype: | |
| svg_parse_xmlev_phase((XMLEV_Phase *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SMIL_SyncBehavior_datatype: | |
| smil_parse_syncBehaviorOrDefault((SMIL_SyncBehavior *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SMIL_SyncTolerance_datatype: | |
| smil_parse_syncToleranceOrDefault((SMIL_SyncTolerance *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SMIL_AttributeType_datatype: | |
| smil_parse_attributeType((SMIL_AttributeType *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SMIL_CalcMode_datatype: | |
| smil_parse_calcmode((SMIL_CalcMode *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SMIL_Additive_datatype: | |
| smil_parse_additive((SMIL_CalcMode *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SMIL_Accumulate_datatype: | |
| smil_parse_accumulate((SMIL_Accumulate *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SMIL_Restart_datatype: | |
| smil_parse_restart((SMIL_Restart *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SMIL_Fill_datatype: | |
| smil_parse_fill((SMIL_Fill *)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_GradientUnit_datatype: | |
| if (!strcmp(attribute_content, "userSpaceOnUse")) | |
| *((SVG_GradientUnit *)info->far_ptr) = SVG_GRADIENTUNITS_USER; | |
| else if (!strcmp(attribute_content, "objectBoundingBox")) | |
| *((SVG_GradientUnit *)info->far_ptr) = SVG_GRADIENTUNITS_OBJECT; | |
| else | |
| e = GF_NON_COMPLIANT_BITSTREAM; | |
| break; | |
| case SVG_FocusHighlight_datatype: | |
| svg_parse_focushighlight((SVG_FocusHighlight*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_Focusable_datatype: | |
| svg_parse_focusable((SVG_Focusable*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_InitialVisibility_datatype: | |
| svg_parse_initialvisibility((SVG_InitialVisibility*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_Overlay_datatype: | |
| svg_parse_overlay((SVG_Overlay*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_TransformBehavior_datatype: | |
| svg_parse_transformbehavior((SVG_TransformBehavior*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_SpreadMethod_datatype: | |
| if (!strcmp(attribute_content, "reflect")) *(u8*)info->far_ptr = SVG_SPREAD_REFLECT; | |
| else if (!strcmp(attribute_content, "repeat")) *(u8*)info->far_ptr = SVG_SPREAD_REPEAT; | |
| else if (!strcmp(attribute_content, "pad")) *(u8*)info->far_ptr = SVG_SPREAD_PAD; | |
| else e = GF_NON_COMPLIANT_BITSTREAM; | |
| break; | |
| case SVG_Filter_TransferType_datatype: | |
| if (!strcmp(attribute_content, "table")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_TABLE; | |
| else if (!strcmp(attribute_content, "discrete")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_DISCRETE; | |
| else if (!strcmp(attribute_content, "linear")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_LINEAR; | |
| else if (!strcmp(attribute_content, "gamma")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_GAMMA; | |
| else if (!strcmp(attribute_content, "identity")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_IDENTITY; | |
| else if (!strcmp(attribute_content, "fractalNoise")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_FRACTAL_NOISE; | |
| else if (!strcmp(attribute_content, "turbulence")) *(u8*)info->far_ptr = SVG_FILTER_TRANSFER_TURBULENCE; | |
| else if (!strcmp(attribute_content, "matrix")) *(u8*)info->far_ptr = SVG_FILTER_MX_MATRIX; | |
| else if (!strcmp(attribute_content, "saturate")) *(u8*)info->far_ptr = SVG_FILTER_MX_SATURATE; | |
| else if (!strcmp(attribute_content, "hueRotate")) *(u8*)info->far_ptr = SVG_FILTER_HUE_ROTATE; | |
| else if (!strcmp(attribute_content, "luminanceToAlpha")) *(u8*)info->far_ptr = SVG_FILTER_LUM_TO_ALPHA; | |
| else e = GF_NON_COMPLIANT_BITSTREAM; | |
| break; | |
| /* end of keyword type parsing */ | |
| /* keyword | numbers (with possibly units) */ | |
| case SVG_Length_datatype: | |
| case SVG_Coordinate_datatype: | |
| case SVG_FontSize_datatype: | |
| case SVG_Rotate_datatype: | |
| case SVG_Number_datatype: | |
| svg_parse_length((SVG_Number*)info->far_ptr, attribute_content, 0, &e); | |
| break; | |
| case SMIL_AnimateValue_datatype: | |
| svg_parse_one_anim_value(n, (SMIL_AnimateValue*)info->far_ptr, attribute_content, anim_value_type, &e); | |
| break; | |
| case SMIL_AnimateValues_datatype: | |
| svg_parse_anim_values(n, (SMIL_AnimateValues*)info->far_ptr, attribute_content, anim_value_type, &e); | |
| break; | |
| case XMLRI_datatype: | |
| svg_parse_iri(n, (XMLRI*)info->far_ptr, attribute_content); | |
| break; | |
| case XML_IDREF_datatype: | |
| svg_parse_idref(n, (XMLRI*)info->far_ptr, attribute_content); | |
| break; | |
| case SMIL_AttributeName_datatype: | |
| if (! ((SMIL_AttributeName *)info->far_ptr)->name) | |
| ((SMIL_AttributeName *)info->far_ptr)->name = gf_strdup(attribute_content); | |
| break; | |
| case SMIL_Times_datatype: | |
| smil_parse_time_list(n, *(GF_List **)info->far_ptr, attribute_content); | |
| break; | |
| case SMIL_Duration_datatype: | |
| smil_parse_min_max_dur_repeatdur((SMIL_Duration*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SMIL_RepeatCount_datatype: | |
| smil_parse_repeatcount((SMIL_RepeatCount*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_PathData_datatype: | |
| svg_parse_path((SVG_PathData*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_Points_datatype: | |
| svg_parse_points(*(GF_List **)(info->far_ptr), attribute_content, &e); | |
| break; | |
| case SMIL_KeyTimes_datatype: | |
| case SMIL_KeyPoints_datatype: | |
| case SMIL_KeySplines_datatype: | |
| case SVG_Numbers_datatype: | |
| svg_parse_numbers(*(GF_List **)(info->far_ptr), attribute_content, 0, &e); | |
| break; | |
| case SVG_Coordinates_datatype: | |
| svg_parse_coordinates(*(GF_List **)(info->far_ptr), attribute_content, &e); | |
| break; | |
| case SVG_ViewBox_datatype: | |
| svg_parse_viewbox((SVG_ViewBox*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_StrokeDashArray_datatype: | |
| svg_parse_strokedasharray((SVG_StrokeDashArray*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_FontFamily_datatype: | |
| svg_parse_fontfamily((SVG_FontFamily*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_Motion_datatype: | |
| { | |
| GF_Matrix2D *mx = (GF_Matrix2D*)info->far_ptr; | |
| u32 i = 0; | |
| gf_mx2d_init(*mx); | |
| i = svg_parse_number(&(attribute_content[i]), &(mx->m[2]), 0, &e); | |
| svg_parse_number(&(attribute_content[i]), &(mx->m[5]), 0, &e); | |
| } | |
| break; | |
| case SVG_Transform_datatype: | |
| e = svg_parse_transform((SVG_Transform*)info->far_ptr, attribute_content); | |
| break; | |
| case SVG_Transform_Translate_datatype: | |
| { | |
| u32 i = 0; | |
| SVG_Point *p = (SVG_Point *)info->far_ptr; | |
| i+=svg_parse_number(&(attribute_content[i]), &(p->x), 0, &e); | |
| if (attribute_content[i] == 0) { | |
| p->y = 0; | |
| } else { | |
| /*i+=*/svg_parse_number(&(attribute_content[i]), &(p->y), 0, &e); | |
| } | |
| } | |
| break; | |
| case SVG_Transform_Scale_datatype: | |
| { | |
| u32 i = 0; | |
| SVG_Point *p = (SVG_Point *)info->far_ptr; | |
| i+=svg_parse_number(&(attribute_content[i]), &(p->x), 0, &e); | |
| if (attribute_content[i] == 0) { | |
| p->y = p->x; | |
| } else { | |
| /*i+=*/svg_parse_number(&(attribute_content[i]), &(p->y), 0, &e); | |
| } | |
| } | |
| break; | |
| case SVG_Transform_SkewX_datatype: | |
| case SVG_Transform_SkewY_datatype: | |
| { | |
| Fixed *p = (Fixed *)info->far_ptr; | |
| svg_parse_number(attribute_content, p, 1, &e); | |
| } | |
| break; | |
| case SVG_Transform_Rotate_datatype: | |
| { | |
| u32 i = 0; | |
| SVG_Point_Angle *p = (SVG_Point_Angle *)info->far_ptr; | |
| i+=svg_parse_number(&(attribute_content[i]), &(p->angle), 1, &e); | |
| if (attribute_content[i] == 0) { | |
| p->y = p->x = 0; | |
| } else { | |
| i+=svg_parse_number(&(attribute_content[i]), &(p->x), 0, &e); | |
| /*i+=*/svg_parse_number(&(attribute_content[i]), &(p->y), 0, &e); | |
| } | |
| } | |
| break; | |
| case SVG_PreserveAspectRatio_datatype: | |
| svg_parse_preserveaspectratio((SVG_PreserveAspectRatio*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_TransformType_datatype: | |
| svg_parse_animatetransform_type((SVG_TransformType*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_ID_datatype: | |
| case DOM_String_datatype: | |
| case SVG_ContentType_datatype: | |
| case SVG_LanguageID_datatype: | |
| if (*(SVG_String *)info->far_ptr) gf_free(*(SVG_String *)info->far_ptr); | |
| *(SVG_String *)info->far_ptr = gf_strdup(attribute_content); | |
| break; | |
| case DOM_StringList_datatype: | |
| svg_parse_strings(*(GF_List **)info->far_ptr, attribute_content, 0); | |
| break; | |
| case XMLRI_List_datatype: | |
| svg_parse_strings(*(GF_List **)info->far_ptr, attribute_content, 1); | |
| break; | |
| case XMLEV_Event_datatype: | |
| { | |
| XMLEV_Event *xml_ev = (XMLEV_Event *)info->far_ptr; | |
| char *sep = strchr(attribute_content, '('); | |
| if (sep) { | |
| sep[0] = 0; | |
| xml_ev->type = gf_dom_event_type_by_name(attribute_content); | |
| sep[0] = '('; | |
| if ((xml_ev->type == GF_EVENT_REPEAT) || (xml_ev->type == GF_EVENT_REPEAT_EVENT)) { | |
| char _v; | |
| sscanf(sep, "(%c)", &_v); | |
| xml_ev->parameter = _v; | |
| } else { /* key events ... */ | |
| char *sep2 = strchr(attribute_content, ')'); | |
| if (sep2) { | |
| sep2[0] = 0; | |
| xml_ev->parameter = gf_dom_get_key_type(sep+1); | |
| sep2[0] = ')'; | |
| } | |
| } | |
| } else { | |
| xml_ev->parameter = 0; | |
| xml_ev->type = gf_dom_event_type_by_name(attribute_content); | |
| } | |
| } | |
| break; | |
| case SVG_Focus_datatype: | |
| svg_parse_focus(n, (SVG_Focus*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_ClipPath_datatype: | |
| svg_parse_clippath(n, (SVG_ClipPath*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case LASeR_Choice_datatype: | |
| e = laser_parse_choice((LASeR_Choice*)info->far_ptr, attribute_content); | |
| break; | |
| case LASeR_Size_datatype: | |
| e = laser_parse_size((LASeR_Size*)info->far_ptr, attribute_content, &e); | |
| break; | |
| case SVG_Clock_datatype: | |
| svg_parse_clock_value(attribute_content, (SVG_Clock*)info->far_ptr); | |
| break; | |
| case SVG_Unknown_datatype: | |
| if (*(SVG_String *)info->far_ptr) gf_free(*(SVG_String *)info->far_ptr); | |
| *(SVG_String *)info->far_ptr = gf_strdup(attribute_content); | |
| break; | |
| default: | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Parsing] Cannot parse attribute \"%s\"\n", info->name ? info->name : "")); | |
| return GF_OK; | |
| } | |
| if (e) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SVG Parsing] Cannot parse attribute \"%s\" value %s: %s\n", info->name ? info->name : "", attribute_content, gf_error_to_string(e))); | |
| //continue parsing if not test mode | |
| if (!gf_sys_is_test_mode()) | |
| e = GF_OK; | |
| } | |
| return e; | |
| } | |
| void svg_parse_one_style(GF_Node *n, char *one_style) | |
| { | |
| GF_FieldInfo info; | |
| char *c, sep; | |
| u32 attributeNameLen; | |
| while (*one_style == ' ') one_style++; | |
| c = strchr(one_style, ':'); | |
| if (!c) return; | |
| attributeNameLen = (u32) (c - one_style); | |
| sep = one_style[attributeNameLen]; | |
| one_style[attributeNameLen] = 0; | |
| while (one_style[0] && strchr("\r\n\t ", one_style[0])) | |
| one_style++; | |
| if (!gf_node_get_field_by_name(n, one_style, &info)) { | |
| c++; | |
| gf_svg_parse_attribute(n, &info, c, 0); | |
| } else { | |
| 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))); | |
| } | |
| one_style[attributeNameLen] = sep; | |
| } | |
| GF_EXPORT | |
| void gf_svg_parse_style(GF_Node *n, char *style) | |
| { | |
| u32 i = 0; | |
| char *str = style; | |
| s32 psemi = -1; | |
| while (1) { | |
| if (str[i] == ';' || str[i] == 0) { | |
| u32 single_value_len = 0; | |
| single_value_len = i - (psemi+1); | |
| if (single_value_len) { | |
| char c = str[psemi+1 + single_value_len]; | |
| str[psemi+1 + single_value_len] = 0; | |
| svg_parse_one_style(n, str + psemi+1); | |
| str[psemi+1 + single_value_len] = c; | |
| psemi = i; | |
| } | |
| if (!str[i]) return; | |
| } | |
| i++; | |
| } | |
| } | |
| GF_EXPORT | |
| void *gf_svg_create_attribute_value(u32 attribute_type) | |
| { | |
| switch (attribute_type) { | |
| case SVG_Boolean_datatype: | |
| { | |
| SVG_Boolean *b; | |
| GF_SAFEALLOC(b, SVG_Boolean) | |
| return b; | |
| } | |
| break; | |
| case SVG_Color_datatype: | |
| { | |
| SVG_Color *color; | |
| GF_SAFEALLOC(color, SVG_Color) | |
| return color; | |
| } | |
| break; | |
| case SVG_Paint_datatype: | |
| { | |
| SVG_Paint *paint; | |
| GF_SAFEALLOC(paint, SVG_Paint) | |
| return paint; | |
| } | |
| break; | |
| /* keyword types */ | |
| case SVG_FillRule_datatype: | |
| case SVG_StrokeLineJoin_datatype: | |
| case SVG_StrokeLineCap_datatype: | |
| case SVG_FontStyle_datatype: | |
| case SVG_FontWeight_datatype: | |
| case SVG_FontVariant_datatype: | |
| case SVG_TextAnchor_datatype: | |
| case SVG_Display_datatype: | |
| case SVG_Visibility_datatype: | |
| case SVG_Overflow_datatype: | |
| case SVG_ZoomAndPan_datatype: | |
| case SVG_DisplayAlign_datatype: | |
| case SVG_TextAlign_datatype: | |
| case SVG_PointerEvents_datatype: | |
| case SVG_RenderingHint_datatype: | |
| case SVG_VectorEffect_datatype: | |
| case SVG_PlaybackOrder_datatype: | |
| case SVG_TimelineBegin_datatype: | |
| case XML_Space_datatype: | |
| case XMLEV_Propagate_datatype: | |
| case XMLEV_DefaultAction_datatype: | |
| case XMLEV_Phase_datatype: | |
| case SMIL_SyncBehavior_datatype: | |
| case SMIL_AttributeType_datatype: | |
| case SMIL_CalcMode_datatype: | |
| case SMIL_Additive_datatype: | |
| case SMIL_Accumulate_datatype: | |
| case SMIL_Restart_datatype: | |
| case SMIL_Fill_datatype: | |
| case SVG_TransformType_datatype: | |
| case SVG_FocusHighlight_datatype: | |
| case SVG_InitialVisibility_datatype: | |
| case SVG_GradientUnit_datatype: | |
| case SVG_Overlay_datatype: | |
| case SVG_TransformBehavior_datatype: | |
| case SVG_SpreadMethod_datatype: | |
| case SVG_Focusable_datatype: | |
| case SVG_Filter_TransferType_datatype: | |
| { | |
| u8 *keyword; | |
| GF_SAFEALLOC(keyword, u8) | |
| return keyword; | |
| } | |
| break; | |
| case SMIL_SyncTolerance_datatype: | |
| { | |
| SMIL_SyncTolerance *st; | |
| GF_SAFEALLOC(st, SMIL_SyncTolerance) | |
| return st; | |
| } | |
| break; | |
| /* inheritable floats */ | |
| case SVG_FontSize_datatype: | |
| case SVG_Length_datatype: | |
| case SVG_Coordinate_datatype: | |
| case SVG_Rotate_datatype: | |
| case SVG_Number_datatype: | |
| { | |
| SVG_Number *number; | |
| GF_SAFEALLOC(number, SVG_Number) | |
| return number; | |
| } | |
| break; | |
| case SVG_StrokeDashArray_datatype: | |
| { | |
| SVG_StrokeDashArray *array; | |
| GF_SAFEALLOC(array, SVG_StrokeDashArray) | |
| return array; | |
| } | |
| break; | |
| case SVG_Motion_datatype: | |
| { | |
| GF_Matrix2D *p; | |
| GF_SAFEALLOC(p, GF_Matrix2D) | |
| if (p) | |
| gf_mx2d_init(*p); | |
| return p; | |
| } | |
| break; | |
| case SVG_Transform_datatype: | |
| { | |
| SVG_Transform *p; | |
| GF_SAFEALLOC(p, SVG_Transform) | |
| if (p) | |
| gf_mx2d_init(p->mat); | |
| return p; | |
| } | |
| break; | |
| case SVG_Transform_Translate_datatype: | |
| case SVG_Transform_Scale_datatype: | |
| { | |
| SVG_Point *p; | |
| GF_SAFEALLOC(p, SVG_Point) | |
| return p; | |
| } | |
| break; | |
| case SVG_Transform_SkewX_datatype: | |
| case SVG_Transform_SkewY_datatype: | |
| { | |
| Fixed *p; | |
| GF_SAFEALLOC(p, Fixed) | |
| return p; | |
| } | |
| break; | |
| case SVG_Transform_Rotate_datatype: | |
| { | |
| SVG_Point_Angle *p; | |
| GF_SAFEALLOC(p, SVG_Point_Angle) | |
| return p; | |
| } | |
| break; | |
| case SVG_ViewBox_datatype: | |
| { | |
| SVG_ViewBox *viewbox; | |
| GF_SAFEALLOC(viewbox, SVG_ViewBox) | |
| return viewbox; | |
| } | |
| break; | |
| case XMLRI_datatype: | |
| case XML_IDREF_datatype: | |
| { | |
| XMLRI *iri; | |
| GF_SAFEALLOC(iri, XMLRI) | |
| return iri; | |
| } | |
| break; | |
| case SVG_FontFamily_datatype: | |
| { | |
| SVG_FontFamily *fontfamily; | |
| GF_SAFEALLOC(fontfamily, SVG_FontFamily) | |
| return fontfamily; | |
| } | |
| break; | |
| case DOM_String_datatype: | |
| case SVG_ContentType_datatype: | |
| case SVG_LanguageID_datatype: | |
| case SVG_ID_datatype: | |
| { | |
| SVG_String *string; | |
| GF_SAFEALLOC(string, SVG_String) | |
| return string; | |
| } | |
| break; | |
| case DOM_StringList_datatype: | |
| case XMLRI_List_datatype: | |
| case SVG_Points_datatype: | |
| case SVG_Coordinates_datatype: | |
| case SMIL_Times_datatype: | |
| case SMIL_KeySplines_datatype: | |
| case SMIL_KeyTimes_datatype: | |
| case SMIL_KeyPoints_datatype: | |
| case SVG_Numbers_datatype: | |
| { | |
| ListOfXXX *list; | |
| GF_SAFEALLOC(list, ListOfXXX) | |
| if (list) *list = gf_list_new(); | |
| return list; | |
| } | |
| break; | |
| case SVG_PreserveAspectRatio_datatype: | |
| { | |
| SVG_PreserveAspectRatio *par; | |
| GF_SAFEALLOC(par, SVG_PreserveAspectRatio) | |
| return par; | |
| } | |
| break; | |
| case SVG_PathData_datatype: | |
| { | |
| SVG_PathData *path; | |
| GF_SAFEALLOC(path, SVG_PathData); | |
| if (!path) return NULL; | |
| #if USE_GF_PATH | |
| gf_path_reset(path); | |
| path->fineness = FIX_ONE; | |
| #else | |
| path->commands = gf_list_new(); | |
| path->points = gf_list_new(); | |
| #endif | |
| return path; | |
| } | |
| break; | |
| case LASeR_Choice_datatype: | |
| { | |
| LASeR_Choice *ch; | |
| GF_SAFEALLOC(ch, LASeR_Choice) | |
| return ch; | |
| } | |
| case SVG_Focus_datatype: | |
| { | |
| SVG_Focus *foc; | |
| GF_SAFEALLOC(foc, SVG_Focus) | |
| return foc; | |
| } | |
| case SVG_ClipPath_datatype: | |
| { | |
| SVG_ClipPath *cp; | |
| GF_SAFEALLOC(cp, SVG_ClipPath) | |
| return cp; | |
| } | |
| case SMIL_AttributeName_datatype: | |
| { | |
| SMIL_AttributeName *an; | |
| GF_SAFEALLOC(an, SMIL_AttributeName) | |
| return an; | |
| } | |
| case SMIL_RepeatCount_datatype: | |
| { | |
| SMIL_RepeatCount *rc; | |
| GF_SAFEALLOC(rc, SMIL_RepeatCount) | |
| return rc; | |
| } | |
| case SMIL_Duration_datatype: | |
| { | |
| SMIL_Duration *sd; | |
| GF_SAFEALLOC(sd, SMIL_Duration) | |
| return sd; | |
| } | |
| case SMIL_AnimateValue_datatype: | |
| { | |
| SMIL_AnimateValue *av; | |
| GF_SAFEALLOC(av, SMIL_AnimateValue) | |
| return av; | |
| } | |
| break; | |
| case SMIL_AnimateValues_datatype: | |
| { | |
| SMIL_AnimateValues *av; | |
| GF_SAFEALLOC(av, SMIL_AnimateValues) | |
| if (!av) return NULL; | |
| av->values = gf_list_new(); | |
| return av; | |
| } | |
| break; | |
| case SVG_Clock_datatype: | |
| { | |
| SVG_Clock *ck; | |
| GF_SAFEALLOC(ck, SVG_Clock) | |
| return ck; | |
| } | |
| break; | |
| case XMLEV_Event_datatype: | |
| { | |
| XMLEV_Event *e; | |
| GF_SAFEALLOC(e, XMLEV_Event); | |
| return e; | |
| } | |
| break; | |
| case LASeR_Size_datatype: | |
| { | |
| LASeR_Size *s; | |
| GF_SAFEALLOC(s, LASeR_Size); | |
| return s; | |
| } | |
| break; | |
| case SVG_Unknown_datatype: | |
| { | |
| SVG_String *string; | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Attributes] Unspecified attribute type - defaulting to string.\n")); | |
| GF_SAFEALLOC(string, SVG_String); | |
| return string; | |
| } | |
| default: | |
| 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))); | |
| break; | |
| } | |
| return NULL; | |
| } | |
| static char *svg_dump_color(SVG_Color *col) | |
| { | |
| char *res; | |
| if (col->type == SVG_COLOR_CURRENTCOLOR) return gf_strdup("currentColor"); | |
| else if (col->type == SVG_COLOR_INHERIT) return gf_strdup("inherit"); | |
| else if (col->type !=SVG_COLOR_RGBCOLOR) { | |
| u32 i, count; | |
| count = sizeof(system_colors) / sizeof(struct sys_col); | |
| for (i=0; i<count; i++) { | |
| if (col->type == system_colors[i].type) { | |
| return gf_strdup(system_colors[i].name); | |
| } | |
| } | |
| } else { | |
| u8 r, g, b; | |
| const char *name; | |
| r = FIX2INT(255*col->red); | |
| g = FIX2INT(255*col->green); | |
| b = FIX2INT(255*col->blue); | |
| name = gf_color_get_name( GF_COL_ARGB(0xFF, r, g, b) ); | |
| if (name) return gf_strdup(name); | |
| res = gf_malloc(sizeof(char)*8); | |
| sprintf(res, "#%02X%02X%02X", r, g, b); | |
| /*compress it...*/ | |
| if ( (res[1]==res[2]) && (res[3]==res[4]) && (res[5]==res[6]) ) | |
| sprintf(res, "#%c%c%c", res[1], res[3], res[5]); | |
| return res; | |
| } | |
| return NULL; | |
| } | |
| static char *svg_dump_number(SVG_Number *l) | |
| { | |
| char tmp[100]; | |
| if (l->type==SVG_NUMBER_INHERIT) return gf_strdup("inherit"); | |
| else if (l->type == SVG_NUMBER_AUTO) return gf_strdup("auto"); | |
| else if (l->type == SVG_NUMBER_AUTO_REVERSE) return gf_strdup("auto-reverse"); | |
| else { | |
| sprintf(tmp, "%g", _FIX2FLT(l->value)); | |
| if (l->type == SVG_NUMBER_PERCENTAGE) gf_strcat(tmp, "%"); | |
| else if (l->type == SVG_NUMBER_EMS) gf_strcat(tmp, "em"); | |
| else if (l->type == SVG_NUMBER_EXS) gf_strcat(tmp, "ex"); | |
| else if (l->type == SVG_NUMBER_PX) gf_strcat(tmp, "px"); | |
| else if (l->type == SVG_NUMBER_CM) gf_strcat(tmp, "cm"); | |
| else if (l->type == SVG_NUMBER_MM) gf_strcat(tmp, "mm"); | |
| else if (l->type == SVG_NUMBER_IN) gf_strcat(tmp, "in"); | |
| else if (l->type == SVG_NUMBER_PT) gf_strcat(tmp, "pt"); | |
| else if (l->type == SVG_NUMBER_PC) gf_strcat(tmp, "pc"); | |
| return gf_strdup(tmp); | |
| } | |
| } | |
| static char *svg_dump_iri(XMLRI*iri) | |
| { | |
| if (iri->type == XMLRI_ELEMENTID) { | |
| const char *name; | |
| char *res; | |
| name = gf_node_get_name((GF_Node *)iri->target); | |
| if (name) { | |
| res = gf_malloc(sizeof(char)*(strlen(name)+2)); | |
| sprintf(res, "#%s", name); | |
| } else if (iri->target) { | |
| res = gf_malloc(sizeof(char)*32); | |
| sprintf(res, "#N%d", gf_node_get_id((GF_Node *)iri->target) - 1); | |
| } else { | |
| res = gf_strdup(""); | |
| } | |
| return res; | |
| } | |
| else if ((iri->type == XMLRI_STRING) && iri->string) | |
| return gf_strdup(iri->string); | |
| else | |
| return gf_strdup(""); | |
| } | |
| static char *svg_dump_idref(XMLRI*iri) | |
| { | |
| if (iri->target) { | |
| const char *name = gf_node_get_name((GF_Node *)iri->target); | |
| if (name) return gf_strdup(name); | |
| else { | |
| char tmp[50]; | |
| sprintf(tmp, "N%d", gf_node_get_id((GF_Node *)iri->target) - 1); | |
| return gf_strdup(tmp); | |
| } | |
| } | |
| if (iri->string) return gf_strdup(iri->string); | |
| return gf_strdup(""); | |
| } | |
| #if USE_GF_PATH | |
| static char *svg_dump_path(SVG_PathData *path) | |
| { | |
| char szT[1000]; | |
| GF_Point2D *pt, last_pt, *ct1, *ct2, *end; | |
| u32 i, *contour; | |
| char *res = gf_malloc(sizeof(char)); | |
| res[0] = 0; | |
| contour = path->contours; | |
| last_pt.x = last_pt.y = 0; | |
| for (i=0; i<path->n_points; ) { | |
| szT[0] = 0; | |
| switch (path->tags[i]) { | |
| case GF_PATH_CURVE_ON: | |
| case GF_PATH_CLOSE: | |
| pt = &path->points[i]; | |
| if (!i || (*contour == i-1) ) { | |
| sprintf(szT, "M%g %g", _FIX2FLT(pt->x), _FIX2FLT(pt->y)); | |
| if (i) contour++; | |
| } else if (path->tags[i]==GF_PATH_CLOSE) { | |
| sprintf(szT, "z"); | |
| } else { | |
| if (last_pt.x==pt->x) sprintf(szT, "V%g", _FIX2FLT(pt->y)); | |
| else if (last_pt.y==pt->y) sprintf(szT, "H%g", _FIX2FLT(pt->x)); | |
| else sprintf(szT, "L%g %g", _FIX2FLT(pt->x), _FIX2FLT(pt->y)); | |
| } | |
| last_pt = *pt; | |
| i++; | |
| break; | |
| case GF_PATH_CURVE_CONIC: | |
| ct1 = &path->points[i]; | |
| end = &path->points[i+1]; | |
| sprintf(szT, "Q%g %g %g %g", _FIX2FLT(ct1->x), _FIX2FLT(ct1->y), _FIX2FLT(end->x), _FIX2FLT(end->y)); | |
| last_pt = *end; | |
| if (path->tags[i+2]==GF_PATH_CLOSE) { | |
| gf_strcat(szT, "z"); | |
| } | |
| i+=2; | |
| break; | |
| case GF_PATH_CURVE_CUBIC: | |
| ct1 = &path->points[i]; | |
| ct2 = &path->points[i+1]; | |
| end = &path->points[i+2]; | |
| 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)); | |
| last_pt = *end; | |
| if (path->tags[i+2]==GF_PATH_CLOSE) { | |
| gf_strcat(szT, "z"); | |
| } | |
| i+=3; | |
| break; | |
| } | |
| if (szT[0]) { | |
| gf_dynstrcat(&res, szT, NULL); | |
| } | |
| } | |
| return res; | |
| } | |
| #else | |
| static void svg_dump_point(SVG_Point *pt, char *attValue) | |
| { | |
| if (pt) sprintf(attValue, "%g %g ", _FIX2FLT(pt->x), _FIX2FLT(pt->y) ); | |
| } | |
| static void svg_dump_path(SVG_PathData *path, char *attValue) | |
| { | |
| char szT[1000]; | |
| u32 i, pt_i, count; | |
| count = gf_list_count(path->commands); | |
| pt_i = 0; | |
| gf_strcpy(attValue, ""); | |
| for (i = 0; i < count; i++) { | |
| u8 command = *(u8 *)gf_list_get(path->commands, i); | |
| switch(command) { | |
| case SVG_PATHCOMMAND_M: | |
| gf_strcat(attValue, "M"); | |
| svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT); | |
| gf_strcat(attValue, szT); | |
| pt_i++; | |
| break; | |
| case SVG_PATHCOMMAND_L: | |
| gf_strcat(attValue, "L"); | |
| svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT); | |
| gf_strcat(attValue, szT); | |
| pt_i++; | |
| break; | |
| case SVG_PATHCOMMAND_C: | |
| gf_strcat(attValue, "C"); | |
| svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT); | |
| gf_strcat(attValue, szT); | |
| pt_i++; | |
| svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT); | |
| gf_strcat(attValue, szT); | |
| pt_i++; | |
| svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT); | |
| gf_strcat(attValue, szT); | |
| pt_i++; | |
| break; | |
| case SVG_PATHCOMMAND_S: | |
| gf_strcat(attValue, "S"); | |
| svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT); | |
| gf_strcat(attValue, szT); | |
| pt_i++; | |
| svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT); | |
| gf_strcat(attValue, szT); | |
| pt_i++; | |
| break; | |
| case SVG_PATHCOMMAND_Q: | |
| gf_strcat(attValue, "Q"); | |
| svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT); | |
| gf_strcat(attValue, szT); | |
| pt_i++; | |
| svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT); | |
| gf_strcat(attValue, szT); | |
| pt_i++; | |
| break; | |
| case SVG_PATHCOMMAND_T: | |
| gf_strcat(attValue, "T"); | |
| svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT); | |
| gf_strcat(attValue, szT); | |
| pt_i++; | |
| break; | |
| case SVG_PATHCOMMAND_A: | |
| gf_strcat(attValue, "A"); | |
| svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT); | |
| gf_strcat(attValue, szT); | |
| pt_i++; | |
| gf_strcat(attValue, "0 0 0 "); | |
| svg_dump_point((SVG_Point*)gf_list_get(path->points, pt_i), szT); | |
| gf_strcat(attValue, szT); | |
| pt_i++; | |
| break; | |
| case SVG_PATHCOMMAND_Z: | |
| gf_strcat(attValue, "Z"); | |
| break; | |
| default: | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Dumping] unknown path command %d\n", command)); | |
| break; | |
| } | |
| } | |
| } | |
| #endif | |
| static void svg_dump_access_key(XMLEV_Event *evt, char attValue[1024]) | |
| { | |
| u32 i, count; | |
| gf_strlcpy(attValue, "accessKey(", 1024); | |
| count = sizeof(predefined_key_identifiers) / sizeof(struct predef_keyid); | |
| for (i=0; i<count; i++) { | |
| if (evt->parameter == predefined_key_identifiers[i].key_code) { | |
| gf_strlcat(attValue, predefined_key_identifiers[i].name, 1024); | |
| break; | |
| } | |
| } | |
| /* OLD LASeR CODE | |
| switch (evt->parameter) { | |
| case 0: gf_strcat(attValue, "UP"); break; | |
| case 1: gf_strcat(attValue, "DOWN"); break; | |
| case 2: gf_strcat(attValue, "LEFT"); break; | |
| case 3: gf_strcat(attValue, "RIGHT"); break; | |
| case 4: gf_strcat(attValue, "FIRE"); break; | |
| case 5: gf_strcat(attValue, "NO_KEY"); break; | |
| case 6: gf_strcat(attValue, "ANY_KEY"); break; | |
| case 7: gf_strcat(attValue, "SOFT_KEY_1"); break; | |
| case 8: gf_strcat(attValue, "SOFT_KEY_2"); break; | |
| case 35: gf_strcat(attValue, "#"); break; | |
| case 42: gf_strcat(attValue, "*"); break; | |
| case 48: gf_strcat(attValue, "0"); break; | |
| case 49: gf_strcat(attValue, "1"); break; | |
| case 50: gf_strcat(attValue, "2"); break; | |
| case 51: gf_strcat(attValue, "3"); break; | |
| case 52: gf_strcat(attValue, "4"); break; | |
| case 53: gf_strcat(attValue, "5"); break; | |
| case 54: gf_strcat(attValue, "6"); break; | |
| case 55: gf_strcat(attValue, "7"); break; | |
| case 56: gf_strcat(attValue, "8"); break; | |
| case 57: gf_strcat(attValue, "9"); break; | |
| */ | |
| gf_strlcat(attValue, ")", 1024); | |
| } | |
| static char *gf_svg_dump_matrix(GF_Matrix2D *matrix) | |
| { | |
| char attValue[1024]; | |
| attValue[0]=0; | |
| /*try to do a simple decomposition...*/ | |
| if (!matrix->m[1] && !matrix->m[3]) { | |
| if (matrix->m[2] != 0 || matrix->m[5] != 0) sprintf(attValue, "translate(%g,%g)", _FIX2FLT(matrix->m[2]), _FIX2FLT(matrix->m[5]) ); | |
| if ((matrix->m[0]!=FIX_ONE) || (matrix->m[4]!=FIX_ONE)) { | |
| char szT[1024]; | |
| if ((matrix->m[0]==-FIX_ONE) && (matrix->m[4]==-FIX_ONE)) { | |
| gf_strcpy(szT, " rotate(180)"); | |
| } else { | |
| sprintf(szT, " scale(%g,%g)", _FIX2FLT(matrix->m[0]), _FIX2FLT(matrix->m[4]) ); | |
| } | |
| gf_strcat(attValue, szT); | |
| } | |
| } else if (matrix->m[1] == - matrix->m[3]) { | |
| Fixed angle = gf_asin(matrix->m[3]); | |
| Fixed cos_a = gf_cos(angle); | |
| if (ABS(cos_a)>FIX_EPSILON) { | |
| Fixed sx, sy; | |
| sx = gf_divfix(matrix->m[0], cos_a); | |
| sy = gf_divfix(matrix->m[4], cos_a); | |
| angle = gf_divfix(180*angle, GF_PI); | |
| if ((sx==sy) && ( ABS(FIX_ONE - ABS(sx) ) < FIX_ONE/100)) { | |
| if (matrix->m[2] != 0 || matrix->m[5] != 0) | |
| sprintf(attValue, "translate(%g,%g) rotate(%g)", _FIX2FLT(matrix->m[2]), _FIX2FLT(matrix->m[5]), _FIX2FLT(gf_divfix(angle*180, GF_PI) ) ); | |
| else | |
| sprintf(attValue, "rotate(%g)", _FIX2FLT(gf_divfix(angle*180, GF_PI) ) ); | |
| } else { | |
| if (matrix->m[2] != 0 || matrix->m[5] != 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) ) ); | |
| else | |
| sprintf(attValue, "scale(%g,%g) rotate(%g)", _FIX2FLT(sx), _FIX2FLT(sy), _FIX2FLT(gf_divfix(angle*180, GF_PI) ) ); | |
| } | |
| } else { | |
| Fixed a = angle; | |
| if (a<0) a += GF_2PI; | |
| if (matrix->m[2] != 0 || matrix->m[5] != 0) | |
| sprintf(attValue, "translate(%g,%g) rotate(%g)", _FIX2FLT(matrix->m[2]), _FIX2FLT(matrix->m[5]), _FIX2FLT(gf_divfix(a*180, GF_PI) ) ); | |
| else | |
| sprintf(attValue, "rotate(%g)", _FIX2FLT(gf_divfix(a*180, GF_PI) ) ); | |
| } | |
| } | |
| /*default*/ | |
| if (!strlen(attValue)) | |
| 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]) ); | |
| return gf_strdup(attValue); | |
| } | |
| char *gf_svg_dump_attribute(GF_Node *elt, GF_FieldInfo *info) | |
| { | |
| char tmp[1024]; | |
| u8 intVal; | |
| if (!info->far_ptr) return gf_strdup(""); | |
| intVal = *(u8 *)info->far_ptr; | |
| switch (info->fieldType) { | |
| case SVG_Boolean_datatype: | |
| return gf_strdup( *(SVG_Boolean *)info->far_ptr ? "true" : "false"); | |
| case SVG_Color_datatype: | |
| return svg_dump_color((SVG_Color *)info->far_ptr); | |
| case SVG_Paint_datatype: | |
| { | |
| SVG_Paint *paint = (SVG_Paint *)info->far_ptr; | |
| if (paint->type == SVG_PAINT_NONE) return gf_strdup("none"); | |
| else if (paint->type == SVG_PAINT_INHERIT) return gf_strdup("inherit"); | |
| else if (paint->type == SVG_PAINT_URI) { | |
| char *iritmp = svg_dump_iri(&paint->iri); | |
| char *res = gf_malloc(sizeof(char)*(strlen(iritmp)+6)); | |
| sprintf(res, "url(%s)", iritmp); | |
| gf_free(iritmp); | |
| return res; | |
| } else { | |
| return svg_dump_color(&paint->color); | |
| } | |
| } | |
| break; | |
| /* beginning of keyword type parsing */ | |
| case SVG_FillRule_datatype: | |
| if (intVal == SVG_FILLRULE_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal == SVG_FILLRULE_NONZERO) return gf_strdup("nonzero"); | |
| else return gf_strdup("evenodd"); | |
| break; | |
| case SVG_StrokeLineJoin_datatype: | |
| if (intVal==SVG_STROKELINEJOIN_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_STROKELINEJOIN_MITER) return gf_strdup("miter"); | |
| else if (intVal==SVG_STROKELINEJOIN_ROUND) return gf_strdup("round"); | |
| else if (intVal==SVG_STROKELINEJOIN_BEVEL) return gf_strdup("bevel"); | |
| break; | |
| case SVG_StrokeLineCap_datatype: | |
| if (intVal==SVG_STROKELINECAP_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_STROKELINECAP_BUTT) return gf_strdup("butt"); | |
| else if (intVal==SVG_STROKELINECAP_ROUND) return gf_strdup("round"); | |
| else if (intVal==SVG_STROKELINECAP_SQUARE) return gf_strdup("square"); | |
| break; | |
| case SVG_FontStyle_datatype: | |
| if (intVal==SVG_FONTSTYLE_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_FONTSTYLE_NORMAL) return gf_strdup("normal"); | |
| else if (intVal==SVG_FONTSTYLE_ITALIC) return gf_strdup("italic"); | |
| else if (intVal==SVG_FONTSTYLE_OBLIQUE) return gf_strdup("oblique"); | |
| break; | |
| case SVG_FontWeight_datatype: | |
| if (intVal==SVG_FONTWEIGHT_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_FONTWEIGHT_NORMAL) return gf_strdup("normal"); | |
| else if (intVal==SVG_FONTWEIGHT_BOLD) return gf_strdup("bold"); | |
| else if (intVal==SVG_FONTWEIGHT_BOLDER) return gf_strdup("bolder"); | |
| else if (intVal==SVG_FONTWEIGHT_LIGHTER) return gf_strdup("lighter"); | |
| else if (intVal==SVG_FONTWEIGHT_100) return gf_strdup("100"); | |
| else if (intVal==SVG_FONTWEIGHT_200) return gf_strdup("200"); | |
| else if (intVal==SVG_FONTWEIGHT_300) return gf_strdup("300"); | |
| else if (intVal==SVG_FONTWEIGHT_400) return gf_strdup("400"); | |
| else if (intVal==SVG_FONTWEIGHT_500) return gf_strdup("500"); | |
| else if (intVal==SVG_FONTWEIGHT_600) return gf_strdup("600"); | |
| else if (intVal==SVG_FONTWEIGHT_700) return gf_strdup("700"); | |
| else if (intVal==SVG_FONTWEIGHT_800) return gf_strdup("800"); | |
| else if (intVal==SVG_FONTWEIGHT_900) return gf_strdup("900"); | |
| break; | |
| case SVG_FontVariant_datatype: | |
| if (intVal==SVG_FONTVARIANT_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_FONTVARIANT_NORMAL) return gf_strdup("normal"); | |
| else if (intVal==SVG_FONTVARIANT_SMALLCAPS) return gf_strdup("small-caps"); | |
| break; | |
| case SVG_TextAnchor_datatype: | |
| if (intVal==SVG_TEXTANCHOR_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_TEXTANCHOR_START) return gf_strdup("start"); | |
| else if (intVal==SVG_TEXTANCHOR_MIDDLE) return gf_strdup("middle"); | |
| else if (intVal==SVG_TEXTANCHOR_END) return gf_strdup("end"); | |
| break; | |
| case SVG_Display_datatype: | |
| if (intVal==SVG_DISPLAY_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_DISPLAY_NONE) return gf_strdup("none"); | |
| else if (intVal==SVG_DISPLAY_INLINE) return gf_strdup("inline"); | |
| else if (intVal==SVG_DISPLAY_BLOCK) return gf_strdup("block"); | |
| else if (intVal==SVG_DISPLAY_LIST_ITEM) return gf_strdup("list-item"); | |
| else if (intVal==SVG_DISPLAY_RUN_IN) return gf_strdup("run-in"); | |
| else if (intVal==SVG_DISPLAY_COMPACT) return gf_strdup("compact"); | |
| else if (intVal==SVG_DISPLAY_MARKER) return gf_strdup("marker"); | |
| else if (intVal==SVG_DISPLAY_TABLE) return gf_strdup("table"); | |
| else if (intVal==SVG_DISPLAY_INLINE_TABLE) return gf_strdup("inline-table"); | |
| else if (intVal==SVG_DISPLAY_TABLE_ROW_GROUP) return gf_strdup("table-row-group"); | |
| else if (intVal==SVG_DISPLAY_TABLE_HEADER_GROUP) return gf_strdup("table-header-group"); | |
| else if (intVal==SVG_DISPLAY_TABLE_FOOTER_GROUP) return gf_strdup("table-footer-group"); | |
| else if (intVal==SVG_DISPLAY_TABLE_ROW) return gf_strdup("table-row"); | |
| else if (intVal==SVG_DISPLAY_TABLE_COLUMN_GROUP) return gf_strdup("table-column-group"); | |
| else if (intVal==SVG_DISPLAY_TABLE_COLUMN) return gf_strdup("table-column"); | |
| else if (intVal==SVG_DISPLAY_TABLE_CELL) return gf_strdup("table-cell"); | |
| else if (intVal==SVG_DISPLAY_TABLE_CAPTION) return gf_strdup("table-caption"); | |
| break; | |
| case SVG_Visibility_datatype: | |
| if (intVal==SVG_VISIBILITY_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_VISIBILITY_VISIBLE) return gf_strdup("visible"); | |
| else if (intVal==SVG_VISIBILITY_HIDDEN) return gf_strdup("hidden"); | |
| else if (intVal==SVG_VISIBILITY_COLLAPSE) return gf_strdup("collapse"); | |
| break; | |
| case SVG_Overflow_datatype: | |
| if (intVal==SVG_OVERFLOW_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_OVERFLOW_VISIBLE) return gf_strdup("visible"); | |
| else if (intVal==SVG_OVERFLOW_HIDDEN) return gf_strdup("hidden"); | |
| else if (intVal==SVG_OVERFLOW_SCROLL) return gf_strdup("scroll"); | |
| else if (intVal==SVG_OVERFLOW_AUTO) return gf_strdup("auto"); | |
| break; | |
| case SVG_ZoomAndPan_datatype: | |
| if (intVal==SVG_ZOOMANDPAN_DISABLE) return gf_strdup("disable"); | |
| else return gf_strdup("magnify"); | |
| break; | |
| case SVG_DisplayAlign_datatype: | |
| if (intVal==SVG_DISPLAYALIGN_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_DISPLAYALIGN_AUTO) return gf_strdup("auto"); | |
| else if (intVal==SVG_DISPLAYALIGN_BEFORE) return gf_strdup("before"); | |
| else if (intVal==SVG_DISPLAYALIGN_CENTER) return gf_strdup("center"); | |
| else if (intVal==SVG_DISPLAYALIGN_AFTER) return gf_strdup("after"); | |
| break; | |
| case SVG_TextAlign_datatype: | |
| if (intVal==SVG_TEXTALIGN_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_TEXTALIGN_START) return gf_strdup("start"); | |
| else if (intVal==SVG_TEXTALIGN_CENTER) return gf_strdup("center"); | |
| else if (intVal==SVG_TEXTALIGN_END) return gf_strdup("end"); | |
| break; | |
| case SVG_PointerEvents_datatype: | |
| if (intVal==SVG_POINTEREVENTS_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_POINTEREVENTS_VISIBLEPAINTED) return gf_strdup("visiblePainted"); | |
| else if (intVal==SVG_POINTEREVENTS_VISIBLEFILL) return gf_strdup("visibleFill"); | |
| else if (intVal==SVG_POINTEREVENTS_VISIBLESTROKE) return gf_strdup("visibleStroke"); | |
| else if (intVal==SVG_POINTEREVENTS_VISIBLE) return gf_strdup("visible"); | |
| else if (intVal==SVG_POINTEREVENTS_PAINTED) return gf_strdup("painted"); | |
| else if (intVal==SVG_POINTEREVENTS_FILL) return gf_strdup("fill"); | |
| else if (intVal==SVG_POINTEREVENTS_STROKE) return gf_strdup("stroke"); | |
| else if (intVal==SVG_POINTEREVENTS_ALL) return gf_strdup("all"); | |
| else if (intVal==SVG_POINTEREVENTS_NONE) return gf_strdup("none"); | |
| else if (intVal==SVG_POINTEREVENTS_BOUNDINGBOX) return gf_strdup("boundingBox"); | |
| break; | |
| case SVG_RenderingHint_datatype: | |
| if (intVal==SVG_RENDERINGHINT_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_RENDERINGHINT_AUTO) return gf_strdup("auto"); | |
| else if (intVal==SVG_RENDERINGHINT_OPTIMIZEQUALITY) return gf_strdup("optimizeQuality"); | |
| else if (intVal==SVG_RENDERINGHINT_OPTIMIZESPEED) return gf_strdup("optimizeSpeed"); | |
| else if (intVal==SVG_RENDERINGHINT_OPTIMIZELEGIBILITY) return gf_strdup("optimizeLegibility"); | |
| else if (intVal==SVG_RENDERINGHINT_CRISPEDGES) return gf_strdup("crispEdges"); | |
| else if (intVal==SVG_RENDERINGHINT_GEOMETRICPRECISION) return gf_strdup("geometricPrecision"); | |
| break; | |
| case SVG_VectorEffect_datatype: | |
| if (intVal==SVG_VECTOREFFECT_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SVG_VECTOREFFECT_NONE) return gf_strdup("none"); | |
| else if (intVal==SVG_VECTOREFFECT_NONSCALINGSTROKE) return gf_strdup("non-scaling-stroke"); | |
| break; | |
| case SVG_PlaybackOrder_datatype: | |
| if (intVal== SVG_PLAYBACKORDER_FORWARDONLY) return gf_strdup("forwardOnly"); | |
| else if (intVal== SVG_PLAYBACKORDER_ALL) return gf_strdup("all"); | |
| break; | |
| case SVG_TimelineBegin_datatype: | |
| if (intVal== SVG_TIMELINEBEGIN_ONSTART) return gf_strdup("onStart"); | |
| else if (intVal== SVG_TIMELINEBEGIN_ONLOAD) return gf_strdup("onLoad"); | |
| break; | |
| case XML_Space_datatype: | |
| if (intVal==XML_SPACE_DEFAULT) return gf_strdup("default"); | |
| else if (intVal==XML_SPACE_PRESERVE) return gf_strdup("preserve"); | |
| break; | |
| case XMLEV_Propagate_datatype: | |
| if (intVal==XMLEVENT_PROPAGATE_CONTINUE) return gf_strdup("continue"); | |
| else if (intVal==XMLEVENT_PROPAGATE_STOP) return gf_strdup("stop"); | |
| break; | |
| case XMLEV_DefaultAction_datatype: | |
| if (intVal==XMLEVENT_DEFAULTACTION_CANCEL) return gf_strdup("cancel"); | |
| else if (intVal==XMLEVENT_DEFAULTACTION_PERFORM) return gf_strdup("perform"); | |
| break; | |
| case XMLEV_Phase_datatype: | |
| if (intVal==XMLEVENT_PHASE_DEFAULT) return gf_strdup("default"); | |
| else if (intVal==XMLEVENT_PHASE_CAPTURE) return gf_strdup("capture"); | |
| break; | |
| case SMIL_SyncBehavior_datatype: | |
| if (intVal==SMIL_SYNCBEHAVIOR_INHERIT) return gf_strdup("inherit"); | |
| else if (intVal==SMIL_SYNCBEHAVIOR_DEFAULT) return gf_strdup("default"); | |
| else if (intVal==SMIL_SYNCBEHAVIOR_LOCKED) return gf_strdup("locked"); | |
| else if (intVal==SMIL_SYNCBEHAVIOR_CANSLIP) return gf_strdup("canSlip"); | |
| else if (intVal==SMIL_SYNCBEHAVIOR_INDEPENDENT) return gf_strdup("independent"); | |
| break; | |
| case SMIL_SyncTolerance_datatype: | |
| if (((SMIL_SyncTolerance*)info->far_ptr)->type==SMIL_SYNCTOLERANCE_INHERIT) return gf_strdup("inherit"); | |
| else if (((SMIL_SyncTolerance*)info->far_ptr)->type==SMIL_SYNCTOLERANCE_DEFAULT) return gf_strdup("default"); | |
| else if (((SMIL_SyncTolerance*)info->far_ptr)->type==SMIL_SYNCBEHAVIOR_LOCKED) { | |
| sprintf(tmp, "%g", ((SMIL_SyncTolerance*)info->far_ptr)->value); | |
| return gf_strdup(tmp); | |
| } | |
| break; | |
| case SMIL_AttributeType_datatype: | |
| if (intVal==SMIL_ATTRIBUTETYPE_AUTO) return gf_strdup("auto"); | |
| else if (intVal==SMIL_ATTRIBUTETYPE_XML) return gf_strdup("XML"); | |
| else if (intVal==SMIL_ATTRIBUTETYPE_CSS) return gf_strdup("CSS"); | |
| break; | |
| case SMIL_CalcMode_datatype: | |
| if (intVal==SMIL_CALCMODE_DISCRETE) return gf_strdup("discrete"); | |
| else if (intVal==SMIL_CALCMODE_LINEAR) return gf_strdup("linear"); | |
| else if (intVal==SMIL_CALCMODE_PACED) return gf_strdup("paced"); | |
| else if (intVal==SMIL_CALCMODE_SPLINE) return gf_strdup("spline"); | |
| break; | |
| case SMIL_Additive_datatype: | |
| if (intVal==SMIL_ADDITIVE_REPLACE) return gf_strdup("replace"); | |
| else if (intVal==SMIL_ADDITIVE_SUM) return gf_strdup("sum"); | |
| break; | |
| case SMIL_Accumulate_datatype: | |
| if (intVal==SMIL_ACCUMULATE_NONE) return gf_strdup("none"); | |
| else if (intVal==SMIL_ACCUMULATE_SUM) return gf_strdup("sum"); | |
| break; | |
| case SMIL_Restart_datatype: | |
| if (intVal==SMIL_RESTART_ALWAYS) return gf_strdup("always"); | |
| else if (intVal==SMIL_RESTART_WHENNOTACTIVE) return gf_strdup("whenNotActive"); | |
| else if (intVal==SMIL_RESTART_NEVER) return gf_strdup("never"); | |
| break; | |
| case SMIL_Fill_datatype: | |
| if (intVal==SMIL_FILL_FREEZE) return gf_strdup("freeze"); | |
| else if (intVal==SMIL_FILL_REMOVE) return gf_strdup("remove"); | |
| break; | |
| case SVG_GradientUnit_datatype: | |
| if (intVal==SVG_GRADIENTUNITS_USER) return gf_strdup("userSpaceOnUse"); | |
| else if (intVal==SVG_GRADIENTUNITS_OBJECT) return gf_strdup("objectBoundingBox"); | |
| break; | |
| case SVG_InitialVisibility_datatype: | |
| if (intVal==SVG_INITIALVISIBILTY_WHENSTARTED) return gf_strdup("whenStarted"); | |
| else if (intVal==SVG_INITIALVISIBILTY_ALWAYS) return gf_strdup("always"); | |
| break; | |
| case SVG_FocusHighlight_datatype: | |
| if (intVal==SVG_FOCUSHIGHLIGHT_AUTO) return gf_strdup("auto"); | |
| else if (intVal==SVG_FOCUSHIGHLIGHT_NONE) return gf_strdup("none"); | |
| break; | |
| case SVG_Overlay_datatype: | |
| if (intVal==SVG_OVERLAY_NONE) return gf_strdup("none"); | |
| else if (intVal==SVG_OVERLAY_TOP) return gf_strdup("top"); | |
| break; | |
| case SVG_TransformBehavior_datatype: | |
| if (intVal==SVG_TRANSFORMBEHAVIOR_GEOMETRIC) return gf_strdup("geometric"); | |
| else if (intVal==SVG_TRANSFORMBEHAVIOR_PINNED) return gf_strdup("pinned"); | |
| else if (intVal==SVG_TRANSFORMBEHAVIOR_PINNED90) return gf_strdup("pinned90"); | |
| else if (intVal==SVG_TRANSFORMBEHAVIOR_PINNED180) return gf_strdup("pinned180"); | |
| else if (intVal==SVG_TRANSFORMBEHAVIOR_PINNED270) return gf_strdup("pinned270"); | |
| break; | |
| case SVG_SpreadMethod_datatype: | |
| if (intVal==SVG_SPREAD_REFLECT) return gf_strdup("reflect"); | |
| else if (intVal==SVG_SPREAD_REPEAT) return gf_strdup("repeat"); | |
| else return gf_strdup("pad"); | |
| break; | |
| case SVG_Filter_TransferType_datatype: | |
| if (intVal==SVG_FILTER_TRANSFER_TABLE) return gf_strdup("table"); | |
| else if (intVal==SVG_FILTER_TRANSFER_DISCRETE) return gf_strdup("discrete"); | |
| else if (intVal==SVG_FILTER_TRANSFER_LINEAR) return gf_strdup("linear"); | |
| else if (intVal==SVG_FILTER_TRANSFER_GAMMA) return gf_strdup("gamma"); | |
| else return gf_strdup("identity"); | |
| break; | |
| case LASeR_Choice_datatype: | |
| if (intVal==LASeR_CHOICE_ALL) return gf_strdup("all"); | |
| else if (intVal==LASeR_CHOICE_NONE) return gf_strdup("none"); | |
| else if (intVal==LASeR_CHOICE_N) { | |
| sprintf(tmp, "%d", ((LASeR_Choice *)info->far_ptr)->choice_index); | |
| return gf_strdup(tmp); | |
| } | |
| break; | |
| case LASeR_Size_datatype: | |
| sprintf(tmp, "%g %g", _FIX2FLT(((LASeR_Size *)info->far_ptr)->width), _FIX2FLT(((LASeR_Size *)info->far_ptr)->height)); | |
| return gf_strdup(tmp); | |
| /* end of keyword type parsing */ | |
| /* inheritable floats */ | |
| case SVG_FontSize_datatype: | |
| case SVG_Length_datatype: | |
| case SVG_Coordinate_datatype: | |
| case SVG_Rotate_datatype: | |
| case SVG_Number_datatype: | |
| #if DUMP_COORDINATES | |
| return svg_dump_number((SVG_Number *)info->far_ptr); | |
| #endif | |
| case XMLRI_datatype: | |
| return svg_dump_iri((XMLRI*)info->far_ptr); | |
| case XML_IDREF_datatype: | |
| return svg_dump_idref((XMLRI*)info->far_ptr); | |
| case XMLRI_List_datatype: | |
| { | |
| GF_List *l = *(GF_List **)info->far_ptr; | |
| u32 i, count = gf_list_count(l); | |
| char *attVal = gf_malloc(sizeof(char)); | |
| attVal[0] = 0; | |
| for (i=0; i<count; i++) { | |
| u32 len; | |
| char *szT; | |
| XMLRI *iri = (XMLRI *)gf_list_get(l, i); | |
| szT = svg_dump_iri(iri); | |
| len = (u32) strlen(szT); | |
| if (len) { | |
| if (i) gf_dynstrcat(&attVal, " ", NULL); | |
| gf_dynstrcat(&attVal, szT, NULL); | |
| } | |
| gf_free(szT); | |
| } | |
| return attVal; | |
| } | |
| break; | |
| case SVG_PathData_datatype: | |
| #if DUMP_COORDINATES | |
| return svg_dump_path((SVG_PathData *)info->far_ptr); | |
| #endif | |
| break; | |
| case SVG_Points_datatype: | |
| { | |
| #if DUMP_COORDINATES | |
| GF_List *l = *(GF_List **) info->far_ptr; | |
| u32 i = 0; | |
| u32 count = gf_list_count(l); | |
| char *attVal = gf_malloc(sizeof(char)); | |
| attVal[0] = 0; | |
| for (i=0; i<count; i++) { | |
| char szT[200]; | |
| SVG_Point *p = (SVG_Point *)gf_list_get(l, i); | |
| sprintf(szT, "%g %g", _FIX2FLT(p->x), _FIX2FLT(p->y)); | |
| if (i) gf_dynstrcat(&attVal, " ", NULL); | |
| gf_dynstrcat(&attVal, szT, NULL); | |
| } | |
| return attVal; | |
| #endif | |
| } | |
| break; | |
| case SMIL_KeyTimes_datatype: | |
| case SMIL_KeyPoints_datatype: | |
| case SMIL_KeySplines_datatype: | |
| { | |
| GF_List *l = *(GF_List **) info->far_ptr; | |
| u32 i = 0; | |
| u32 count = gf_list_count(l); | |
| char *attVal = gf_malloc(sizeof(char)); | |
| attVal[0] = 0; | |
| for (i=0; i<count; i++) { | |
| char szT[1000]; | |
| Fixed *p = (Fixed *)gf_list_get(l, i); | |
| sprintf(szT, "%g", _FIX2FLT(*p)); | |
| if (i) gf_dynstrcat(&attVal, " ", NULL); | |
| gf_dynstrcat(&attVal, szT, NULL); | |
| } | |
| return attVal; | |
| } | |
| break; | |
| case SVG_Coordinates_datatype: | |
| { | |
| #if DUMP_COORDINATES | |
| GF_List *l = *(GF_List **) info->far_ptr; | |
| u32 i = 0; | |
| u32 count = gf_list_count(l); | |
| char *attVal = gf_malloc(sizeof(char)); | |
| attVal[0]=0; | |
| for (i=0; i<count; i++) { | |
| char *szT; | |
| SVG_Coordinate *p = (SVG_Coordinate *)gf_list_get(l, i); | |
| szT = svg_dump_number((SVG_Length *)p); | |
| if (i) gf_dynstrcat(&attVal, " ", NULL); | |
| gf_dynstrcat(&attVal, szT, NULL); | |
| gf_free(szT); | |
| } | |
| return attVal; | |
| #endif | |
| } | |
| break; | |
| case SVG_ViewBox_datatype: | |
| { | |
| SVG_ViewBox *v = (SVG_ViewBox *)info->far_ptr; | |
| if (v->is_set) { | |
| sprintf(tmp, "%g %g %g %g", _FIX2FLT(v->x), _FIX2FLT(v->y), _FIX2FLT(v->width), _FIX2FLT(v->height) ); | |
| return gf_strdup(tmp); | |
| } else | |
| return gf_strdup("none"); | |
| } | |
| break; | |
| case SVG_StrokeDashArray_datatype: | |
| { | |
| SVG_StrokeDashArray *p = (SVG_StrokeDashArray *)info->far_ptr; | |
| if (p->type==SVG_STROKEDASHARRAY_NONE) return gf_strdup("none"); | |
| else if (p->type==SVG_STROKEDASHARRAY_INHERIT) return gf_strdup("inherit"); | |
| else if (p->type==SVG_STROKEDASHARRAY_ARRAY) { | |
| u32 i = 0; | |
| char *attVal = gf_malloc(sizeof(char)); | |
| attVal[0] = 0; | |
| for (i=0; i<p->array.count; i++) { | |
| char *szT; | |
| SVG_Length l; | |
| l.type = p->array.units[i]; | |
| l.value = p->array.vals[i]; | |
| szT = svg_dump_number(&l); | |
| if (i) gf_dynstrcat(&attVal, " ", NULL); | |
| gf_dynstrcat(&attVal, szT, NULL); | |
| gf_free(szT); | |
| } | |
| return attVal; | |
| } | |
| } | |
| break; | |
| case SVG_FontFamily_datatype: | |
| { | |
| SVG_FontFamily *f = (SVG_FontFamily *)info->far_ptr; | |
| return gf_strdup( (!f->value || (f->type==SVG_FONTFAMILY_INHERIT)) ? "inherit" : (const char *) f->value); | |
| } | |
| case SVG_PreserveAspectRatio_datatype: | |
| { | |
| SVG_PreserveAspectRatio *par = (SVG_PreserveAspectRatio *)info->far_ptr; | |
| tmp[0] = 0; | |
| if (par->defer) gf_strcat(tmp, "defer "); | |
| if (par->align == SVG_PRESERVEASPECTRATIO_NONE) gf_strcat(tmp, "none"); | |
| else if (par->align == SVG_PRESERVEASPECTRATIO_XMINYMIN) gf_strcat(tmp, "xMinYMin"); | |
| else if (par->align == SVG_PRESERVEASPECTRATIO_XMIDYMIN) gf_strcat(tmp, "xMidYMin"); | |
| else if (par->align == SVG_PRESERVEASPECTRATIO_XMAXYMIN) gf_strcat(tmp, "xMaxYMin"); | |
| else if (par->align == SVG_PRESERVEASPECTRATIO_XMINYMID) gf_strcat(tmp, "xMinYMid"); | |
| else if (par->align == SVG_PRESERVEASPECTRATIO_XMIDYMID) gf_strcat(tmp, "xMidYMid"); | |
| else if (par->align == SVG_PRESERVEASPECTRATIO_XMAXYMID) gf_strcat(tmp, "xMaxYMid"); | |
| else if (par->align == SVG_PRESERVEASPECTRATIO_XMINYMAX) gf_strcat(tmp, "xMinYMax"); | |
| else if (par->align == SVG_PRESERVEASPECTRATIO_XMIDYMAX) gf_strcat(tmp, "xMidYMax"); | |
| else if (par->align == SVG_PRESERVEASPECTRATIO_XMAXYMAX) gf_strcat(tmp, "xMaxYMax"); | |
| if (par->meetOrSlice== SVG_MEETORSLICE_SLICE) gf_strcat(tmp, " slice"); | |
| return gf_strdup(tmp); | |
| } | |
| case SVG_Clock_datatype: | |
| sprintf(tmp, "%g", * (SVG_Clock *)info->far_ptr ); | |
| return gf_strdup(tmp); | |
| case SVG_ID_datatype: | |
| case SVG_LanguageID_datatype: | |
| case SVG_GradientOffset_datatype: | |
| case DOM_String_datatype: | |
| case SVG_ContentType_datatype: | |
| if (*(SVG_String *)info->far_ptr) | |
| return gf_strdup( *(SVG_String *)info->far_ptr ); | |
| break; | |
| case SVG_Focus_datatype: | |
| { | |
| SVG_Focus *foc = (SVG_Focus *)info->far_ptr; | |
| if (foc->type==SVG_FOCUS_SELF) return gf_strdup("self"); | |
| else if (foc->type==SVG_FOCUS_AUTO) return gf_strdup("auto"); | |
| else { | |
| sprintf(tmp, "#%s", foc->target.string); | |
| return gf_strdup(tmp); | |
| } | |
| } | |
| case SVG_ClipPath_datatype: | |
| { | |
| SVG_ClipPath *cp = (SVG_ClipPath *)info->far_ptr; | |
| sprintf(tmp, "url(#%s)", cp->target.string); | |
| return gf_strdup(tmp); | |
| } | |
| break; | |
| case SVG_Focusable_datatype: | |
| { | |
| SVG_Focusable *f = (SVG_Focusable *)info->far_ptr; | |
| if (*f == SVG_FOCUSABLE_TRUE) return gf_strdup("true"); | |
| else if (*f == SVG_FOCUSABLE_FALSE) return gf_strdup("false"); | |
| else return gf_strdup("auto"); | |
| } | |
| case DOM_StringList_datatype: | |
| { | |
| GF_List *l1 = *(GF_List **) info->far_ptr; | |
| u32 i = 0; | |
| u32 count = gf_list_count(l1); | |
| char *attVal = gf_malloc(sizeof(char)); | |
| attVal[0] = 0; | |
| for (i=0; i<count; i++) { | |
| char *p1 = (char *)gf_list_get(l1, i); | |
| if (i) gf_dynstrcat(&attVal, " ", NULL); | |
| gf_dynstrcat(&attVal, p1, NULL); | |
| } | |
| return attVal; | |
| } | |
| case SVG_Numbers_datatype: | |
| { | |
| #if DUMP_COORDINATES | |
| GF_List *l1 = *(GF_List **) info->far_ptr; | |
| u32 i = 0; | |
| u32 count = gf_list_count(l1); | |
| char *attVal = gf_malloc(sizeof(char)); | |
| attVal[0]=0; | |
| for (i=0; i<count; i++) { | |
| char *szT; | |
| SVG_Number *p = (SVG_Number *)gf_list_get(l1, i); | |
| szT = svg_dump_number(p); | |
| if (i) gf_dynstrcat(&attVal, " ", NULL); | |
| gf_dynstrcat(&attVal, szT, NULL); | |
| gf_free(szT); | |
| } | |
| return attVal; | |
| #endif | |
| } | |
| break; | |
| case SVG_Motion_datatype: | |
| { | |
| #if DUMP_COORDINATES | |
| GF_Matrix2D *m = (GF_Matrix2D *)info->far_ptr; | |
| sprintf(tmp, "%g %g", _FIX2FLT(m->m[2]), _FIX2FLT(m->m[5])); | |
| return gf_strdup(tmp); | |
| #endif | |
| } | |
| break; | |
| case SVG_Transform_datatype: | |
| { | |
| SVG_Transform *t= (SVG_Transform *)info->far_ptr; | |
| if (t->is_ref) { | |
| sprintf(tmp, "ref(svg,%g,%g)", _FIX2FLT(t->mat.m[2]), _FIX2FLT(t->mat.m[5]) ); | |
| return gf_strdup(tmp); | |
| } else { | |
| return gf_svg_dump_matrix(&t->mat); | |
| } | |
| } | |
| break; | |
| case SVG_Transform_Translate_datatype: | |
| { | |
| SVG_Point *pt = (SVG_Point *)info->far_ptr; | |
| #if DUMP_COORDINATES | |
| sprintf(tmp, "%g %g", _FIX2FLT(pt->x), _FIX2FLT(pt->y) ); | |
| return gf_strdup(tmp); | |
| #endif | |
| } | |
| break; | |
| case SVG_Transform_Scale_datatype: | |
| { | |
| SVG_Point *pt = (SVG_Point *)info->far_ptr; | |
| #if DUMP_COORDINATES | |
| if (pt->x == pt->y) { | |
| sprintf(tmp, "%g", _FIX2FLT(pt->x)); | |
| } else { | |
| sprintf(tmp, "%g %g", _FIX2FLT(pt->x), _FIX2FLT(pt->y) ); | |
| } | |
| return gf_strdup(tmp); | |
| #endif | |
| } | |
| break; | |
| case SVG_Transform_SkewX_datatype: | |
| case SVG_Transform_SkewY_datatype: | |
| { | |
| Fixed *f = (Fixed *)info->far_ptr; | |
| #if DUMP_COORDINATES | |
| sprintf(tmp, "%g", _FIX2FLT( 180 * gf_divfix(*f, GF_PI) )); | |
| return gf_strdup(tmp); | |
| #endif | |
| } | |
| break; | |
| case SVG_Transform_Rotate_datatype: | |
| { | |
| SVG_Point_Angle *pt = (SVG_Point_Angle *)info->far_ptr; | |
| #if DUMP_COORDINATES | |
| if (pt->x || pt->y) { | |
| sprintf(tmp, "%g %g %g", _FIX2FLT( 180 * gf_divfix(pt->angle, GF_PI) ), _FIX2FLT(pt->x), _FIX2FLT(pt->y) ); | |
| } else { | |
| sprintf(tmp, "%g", _FIX2FLT(gf_divfix(180 * pt->angle, GF_PI) )); | |
| } | |
| return gf_strdup(tmp); | |
| #endif | |
| } | |
| break; | |
| case SMIL_AttributeName_datatype: | |
| { | |
| SMIL_AttributeName *att_name = (SMIL_AttributeName *) info->far_ptr; | |
| if (att_name->name) | |
| return gf_strdup(att_name->name); | |
| if (att_name->tag) { | |
| char *att_name_val = (char *)gf_svg_get_attribute_name(elt, att_name->tag); | |
| if (!att_name_val) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG] unknown attribute name for tag %d\n", att_name->tag)); | |
| return NULL; | |
| } | |
| return gf_strdup(att_name_val ); | |
| } | |
| } | |
| break; | |
| case SMIL_Times_datatype: | |
| { | |
| u32 i, count; | |
| GF_Node *par = gf_node_get_parent((GF_Node *)elt, 0); | |
| GF_List *l = *(GF_List **) info->far_ptr; | |
| char *attVal = gf_malloc(sizeof(char)); | |
| attVal[0] = 0; | |
| count = gf_list_count(l); | |
| for (i=0; i<count; i++) { | |
| char szBuf[1024]; | |
| SMIL_Time *t = (SMIL_Time *)gf_list_get(l, i); | |
| szBuf[0] = 0; | |
| if (t->type == GF_SMIL_TIME_CLOCK) { | |
| sprintf(szBuf, "%gs", t->clock); | |
| } else if (t->type==GF_SMIL_TIME_INDEFINITE) { | |
| gf_strcpy(szBuf, "indefinite"); | |
| } else if (t->type==GF_SMIL_TIME_WALLCLOCK) { | |
| u32 h, m, s; | |
| /*TODO - day month and year*/ | |
| h = (u32) t->clock * 3600; | |
| m = (u32) (t->clock * 60 - 60*h); | |
| s = (u32) (t->clock - 3600*h - 60*m); | |
| sprintf(szBuf, "wallclock(%d:%d:%d)", h, m, s); | |
| } | |
| else if (t->type==GF_SMIL_TIME_EVENT) { | |
| if (t->event.type == GF_EVENT_KEYDOWN) { | |
| svg_dump_access_key(&t->event, szBuf); | |
| } else { | |
| if (t->element_id) { | |
| gf_strcpy(szBuf, t->element_id); | |
| gf_strcat(szBuf, "."); | |
| } else if (t->element && (t->element!=par) && gf_node_get_id(t->element) ) { | |
| const char *name = gf_node_get_name(t->element); | |
| if (name) { | |
| gf_strcpy(szBuf, name); | |
| } else { | |
| sprintf(szBuf, "N%d", gf_node_get_id(t->element)-1 ); | |
| } | |
| gf_strcat(szBuf, "."); | |
| } | |
| gf_strcat(szBuf, gf_dom_event_get_name(t->event.type)); | |
| } | |
| if (t->clock) { | |
| char szCk[40]; | |
| sprintf(szCk, "+%gs", t->clock); | |
| gf_strcat(szBuf, szCk); | |
| } | |
| } | |
| if (szBuf[0]) { | |
| gf_dynstrcat(&attVal, szBuf, ";"); | |
| } | |
| } | |
| return attVal; | |
| } | |
| break; | |
| case SMIL_Duration_datatype: | |
| { | |
| SMIL_Duration *dur = (SMIL_Duration *)info->far_ptr; | |
| if (dur->type == SMIL_DURATION_INDEFINITE) return gf_strdup("indefinite"); | |
| else if (dur->type == SMIL_DURATION_MEDIA) return gf_strdup("media"); | |
| else if (dur->type == SMIL_DURATION_DEFINED) { | |
| sprintf(tmp, "%gs", dur->clock_value); | |
| return gf_strdup(tmp); | |
| } else { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Dumping] smil duration not assigned\n")); | |
| } | |
| } | |
| break; | |
| case SMIL_RepeatCount_datatype: | |
| { | |
| SMIL_RepeatCount *rep = (SMIL_RepeatCount *)info->far_ptr; | |
| if (rep->type == SMIL_REPEATCOUNT_INDEFINITE) return gf_strdup("indefinite"); | |
| else if (rep->type == SMIL_REPEATCOUNT_DEFINED) { | |
| sprintf(tmp, "%g", _FIX2FLT(rep->count) ); | |
| return gf_strdup(tmp); | |
| } | |
| else { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[SVG Dumping] smil repeat count not assigned\n")); | |
| } | |
| } | |
| break; | |
| case SVG_TransformType_datatype: | |
| { | |
| SVG_TransformType tr = *(SVG_TransformType *)info->far_ptr; | |
| if (tr == SVG_TRANSFORM_MATRIX) return gf_strdup("matrix"); | |
| else if (tr == SVG_TRANSFORM_SCALE) return gf_strdup("scale"); | |
| else if (tr == SVG_TRANSFORM_ROTATE) return gf_strdup("rotate"); | |
| else if (tr == SVG_TRANSFORM_TRANSLATE) return gf_strdup("translate"); | |
| else if (tr == SVG_TRANSFORM_SKEWX) return gf_strdup("skewX"); | |
| else if (tr == SVG_TRANSFORM_SKEWY) return gf_strdup("skewY"); | |
| } | |
| break; | |
| case SMIL_AnimateValue_datatype: | |
| { | |
| GF_FieldInfo a_fi; | |
| SMIL_AnimateValue*av = (SMIL_AnimateValue*)info->far_ptr; | |
| a_fi.fieldIndex = 0; | |
| a_fi.fieldType = av->type; | |
| a_fi.name = info->name; | |
| a_fi.far_ptr = av->value; | |
| return gf_svg_dump_attribute(elt, &a_fi); | |
| } | |
| break; | |
| case SMIL_AnimateValues_datatype: | |
| { | |
| GF_FieldInfo a_fi; | |
| u32 i, count; | |
| SMIL_AnimateValues *av = (SMIL_AnimateValues*)info->far_ptr; | |
| char *attVal = gf_malloc(sizeof(char)); | |
| attVal[0] = 0; | |
| if (av->type) { | |
| count = gf_list_count(av->values); | |
| a_fi.fieldIndex = 0; | |
| a_fi.fieldType = av->type; | |
| a_fi.name = info->name; | |
| for (i=0; i<count; i++) { | |
| char *szBuf; | |
| a_fi.far_ptr = gf_list_get(av->values, i); | |
| szBuf = gf_svg_dump_attribute(elt, &a_fi); | |
| if (i) gf_dynstrcat(&attVal, ";", NULL); | |
| gf_dynstrcat(&attVal, szBuf, NULL); | |
| gf_free(szBuf); | |
| } | |
| } | |
| return attVal; | |
| } | |
| case XMLEV_Event_datatype: | |
| { | |
| XMLEV_Event *d = (XMLEV_Event *)info->far_ptr; | |
| if (d->parameter) { | |
| svg_dump_access_key(d, tmp); | |
| } else { | |
| gf_strcpy(tmp, gf_dom_event_get_name(d->type)); | |
| } | |
| return gf_strdup(tmp); | |
| } | |
| default: | |
| 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))); | |
| break; | |
| } | |
| return gf_strdup(""); | |
| } | |
| char *gf_svg_dump_attribute_indexed(GF_Node *elt, GF_FieldInfo *info) | |
| { | |
| char tmp[1024]; | |
| switch (info->fieldType) { | |
| case SVG_PointerEvents_datatype: | |
| break; | |
| case XMLRI_List_datatype: | |
| return gf_strdup(info->far_ptr ? (char *) info->far_ptr : ""); | |
| case SVG_Points_datatype: | |
| { | |
| #if DUMP_COORDINATES | |
| SVG_Point *p = (SVG_Point *)gf_list_get(*(GF_List **)info->far_ptr, 0); | |
| sprintf(tmp, "%g %g", _FIX2FLT(p->x), _FIX2FLT(p->y)); | |
| return gf_strdup(tmp); | |
| #endif | |
| } | |
| break; | |
| case SMIL_KeyPoints_datatype: | |
| case SMIL_KeyTimes_datatype: | |
| case SMIL_KeySplines_datatype: | |
| { | |
| Fixed *p = (Fixed *)gf_list_get(*(GF_List **)info->far_ptr, 0); | |
| sprintf(tmp, "%g", _FIX2FLT(*p)); | |
| return gf_strdup(tmp); | |
| } | |
| break; | |
| case SVG_Coordinates_datatype: | |
| #if DUMP_COORDINATES | |
| return svg_dump_number((SVG_Length *) (SVG_Coordinate *)info->far_ptr); | |
| #endif | |
| break; | |
| case SVG_ViewBox_datatype: | |
| { | |
| Fixed *v = (Fixed *)info->far_ptr; | |
| sprintf(tmp, "%g", _FIX2FLT(*v)); | |
| return gf_strdup(tmp); | |
| } | |
| break; | |
| case SVG_StrokeDashArray_datatype: | |
| { | |
| /*TODO: fix this: should be an SVG_Length*/ | |
| Fixed *p = (Fixed *)info->far_ptr; | |
| sprintf(tmp, "%g", _FIX2FLT(*p)); | |
| return gf_strdup(tmp); | |
| } | |
| break; | |
| case SMIL_Times_datatype: | |
| { | |
| SMIL_Time *t = (SMIL_Time *)gf_list_get(*(GF_List **)info->far_ptr, 0); | |
| if (t->type == GF_SMIL_TIME_CLOCK) { | |
| sprintf(tmp, "%gs", t->clock); | |
| } else if (t->type==GF_SMIL_TIME_INDEFINITE) { | |
| gf_strcpy(tmp, "indefinite"); | |
| } else if (t->type==GF_SMIL_TIME_WALLCLOCK) { | |
| u32 h, m, s; | |
| /*TODO - day month and year*/ | |
| h = (u32) t->clock * 3600; | |
| m = (u32) (t->clock * 60 - 60*h); | |
| s = (u32) (t->clock - 3600*h - 60*m); | |
| sprintf(tmp, "wallclock(%d:%d:%d)", h, m, s); | |
| } | |
| else if (t->type==GF_SMIL_TIME_EVENT) { | |
| GF_Node *par = gf_node_get_parent((GF_Node *)elt, 0); | |
| if (t->event.type == GF_EVENT_KEYDOWN) { | |
| svg_dump_access_key(&t->event, tmp); | |
| } else { | |
| gf_strcpy(tmp, ""); | |
| if (t->element_id) { | |
| gf_strcat(tmp, t->element_id); | |
| gf_strcat(tmp, "."); | |
| } else if (t->element && (t->element!=par) && gf_node_get_id(t->element) ) { | |
| const char *name = gf_node_get_name(t->element); | |
| if (name) { | |
| gf_strcat(tmp, name); | |
| } else { | |
| sprintf(tmp, "N%d", gf_node_get_id(t->element)-1 ); | |
| } | |
| gf_strcat(tmp, "."); | |
| } | |
| gf_strcat(tmp, gf_dom_event_get_name(t->event.type)); | |
| } | |
| if (t->clock) { | |
| char szBuf[100]; | |
| sprintf(szBuf, "+%gs", t->clock); | |
| gf_strcat(tmp, szBuf); | |
| } | |
| } | |
| return gf_strdup(tmp); | |
| } | |
| default: | |
| 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))); | |
| break; | |
| } | |
| return gf_strdup(""); | |
| } | |
| static Bool svg_viewbox_equal(SVG_ViewBox *v1, SVG_ViewBox *v2) | |
| { | |
| if (v1->is_set != v2->is_set) return 0; | |
| if (!v1->is_set) | |
| return 1; | |
| else { | |
| if ( (v1->x == v2->x) && (v1->y == v2->y) && (v1->width == v2->width) && (v1->height == v2->height) ) | |
| return 1; | |
| else | |
| return 0; | |
| } | |
| } | |
| static Bool svg_colors_equal(SVG_Color *c1, SVG_Color *c2) | |
| { | |
| if (c1->type != c2->type) return 0; | |
| if (c1->red != c2->red) return 0; | |
| if (c1->green != c2->green) return 0; | |
| if (c1->blue != c2->blue) return 0; | |
| return 1; | |
| } | |
| static Bool svg_numbers_equal(SVG_Length *l1, SVG_Length *l2) | |
| { | |
| if (l1->type!=l2->type) return 0; | |
| if (l1->type >= SVG_NUMBER_INHERIT) return 1; | |
| return (l1->value==l2->value) ? 1 : 0; | |
| } | |
| static Bool svg_iris_equal(XMLRI*iri1, XMLRI*iri2) | |
| { | |
| u32 type1, type2; | |
| type1 = iri1->type; | |
| type2 = iri2->type; | |
| /*ignore undef hrefs, these are internall ones*/ | |
| if ((iri1->type == XMLRI_ELEMENTID) && iri1->target) { | |
| if (!gf_node_get_id((GF_Node *)iri1->target)) type1 = 0; | |
| } | |
| if ((iri2->type == XMLRI_ELEMENTID) && iri2->target) { | |
| if (!gf_node_get_id((GF_Node *)iri2->target)) type2 = 0; | |
| } | |
| if (type1 != type2) return 0; | |
| if ((type1 == XMLRI_ELEMENTID) && (iri1->target == iri2->target) ) return 1; | |
| if (iri1->string && iri2->string && !strcmp(iri1->string, iri2->string)) return 1; | |
| if (!iri1->string && !iri2->string) return 1; | |
| return 0; | |
| } | |
| static Bool svg_matrices_equal(GF_Matrix2D *m1, GF_Matrix2D *m2) | |
| { | |
| if (m1->m[0] != m2->m[0]) return 0; | |
| if (m1->m[1] != m2->m[1]) return 0; | |
| if (m1->m[2] != m2->m[2]) return 0; | |
| if (m1->m[3] != m2->m[3]) return 0; | |
| if (m1->m[4] != m2->m[4]) return 0; | |
| if (m1->m[5] != m2->m[5]) return 0; | |
| return 1; | |
| } | |
| Bool gf_svg_attributes_equal(GF_FieldInfo *f1, GF_FieldInfo *f2) | |
| { | |
| u32 v1, v2; | |
| if (f1->fieldType!=f2->fieldType) return 0; | |
| if (f1->far_ptr && !f2->far_ptr) return 0; | |
| if (f2->far_ptr && !f1->far_ptr) return 0; | |
| if (!f1->far_ptr) return 1; | |
| v1 = *(u8 *)f1->far_ptr; | |
| v2 = *(u8 *)f2->far_ptr; | |
| switch (f1->fieldType) { | |
| case SVG_Boolean_datatype: | |
| case SVG_FillRule_datatype: | |
| case SVG_StrokeLineJoin_datatype: | |
| case SVG_StrokeLineCap_datatype: | |
| case SVG_FontStyle_datatype: | |
| case SVG_FontWeight_datatype: | |
| case SVG_FontVariant_datatype: | |
| case SVG_TextAnchor_datatype: | |
| case SVG_Display_datatype: | |
| case SVG_Visibility_datatype: | |
| case SVG_GradientUnit_datatype: | |
| case SVG_PreserveAspectRatio_datatype: | |
| case XML_Space_datatype: | |
| case XMLEV_Propagate_datatype: | |
| case XMLEV_DefaultAction_datatype: | |
| case XMLEV_Phase_datatype: | |
| case SMIL_SyncBehavior_datatype: | |
| case SMIL_AttributeType_datatype: | |
| case SMIL_CalcMode_datatype: | |
| case SMIL_Additive_datatype: | |
| case SMIL_Accumulate_datatype: | |
| case SMIL_Restart_datatype: | |
| case SMIL_Fill_datatype: | |
| case SVG_Overflow_datatype: | |
| case SVG_ZoomAndPan_datatype: | |
| case SVG_DisplayAlign_datatype: | |
| case SVG_TextAlign_datatype: | |
| case SVG_PointerEvents_datatype: | |
| case SVG_RenderingHint_datatype: | |
| case SVG_VectorEffect_datatype: | |
| case SVG_PlaybackOrder_datatype: | |
| case SVG_TimelineBegin_datatype: | |
| case SVG_Focusable_datatype: | |
| case SVG_FocusHighlight_datatype: | |
| case SVG_TransformType_datatype: | |
| case SVG_Overlay_datatype: | |
| case SVG_TransformBehavior_datatype: | |
| case SVG_SpreadMethod_datatype: | |
| case SVG_InitialVisibility_datatype: | |
| case LASeR_Choice_datatype: | |
| return (v1==v2) ? 1 : 0; | |
| case SVG_Color_datatype: | |
| return svg_colors_equal((SVG_Color *)f1->far_ptr, (SVG_Color *)f2->far_ptr); | |
| case SMIL_SyncTolerance_datatype: | |
| { | |
| SMIL_SyncTolerance *st1 = (SMIL_SyncTolerance*)f1->far_ptr; | |
| SMIL_SyncTolerance *st2 = (SMIL_SyncTolerance*)f2->far_ptr; | |
| if (st1->type!=st2->type) return 0; | |
| if ((st1->type==SMIL_SYNCTOLERANCE_VALUE) && (st1->value!=st2->value)) return 0; | |
| return 1; | |
| } | |
| case SVG_Paint_datatype: | |
| { | |
| SVG_Paint *p1 = (SVG_Paint *)f1->far_ptr; | |
| SVG_Paint *p2 = (SVG_Paint *)f2->far_ptr; | |
| if (p1->type != p2->type) return 0; | |
| if (p1->type==SVG_PAINT_COLOR) return svg_colors_equal(&p1->color, &p2->color); | |
| else if (p1->type==SVG_PAINT_URI) return svg_iris_equal(&p1->iri, &p2->iri); | |
| return 1; | |
| } | |
| break; | |
| case SVG_FontSize_datatype: | |
| case SVG_Length_datatype: | |
| case SVG_Coordinate_datatype: | |
| case SVG_Rotate_datatype: | |
| case SVG_Number_datatype: | |
| return svg_numbers_equal((SVG_Number *)f1->far_ptr, (SVG_Number *)f2->far_ptr); | |
| case XMLRI_datatype: | |
| return svg_iris_equal((XMLRI*)f1->far_ptr, (XMLRI*)f2->far_ptr); | |
| case XMLRI_List_datatype: | |
| { | |
| GF_List *l1 = *(GF_List **)f1->far_ptr; | |
| GF_List *l2 = *(GF_List **)f2->far_ptr; | |
| u32 i, count = gf_list_count(l1); | |
| if (gf_list_count(l2)!=count) return 0; | |
| for (i=0; i<count; i++) { | |
| if (!svg_iris_equal((XMLRI*)gf_list_get(l1, i), (XMLRI*)gf_list_get(l2, i) )) return 0; | |
| } | |
| return 1; | |
| } | |
| case SVG_PathData_datatype: | |
| { | |
| SVG_PathData *d1 = (SVG_PathData *)f1->far_ptr; | |
| SVG_PathData *d2 = (SVG_PathData *)f2->far_ptr; | |
| #if USE_GF_PATH | |
| u32 i; | |
| /*FIXME - be less lazy..*/ | |
| if (d1->n_points != d2->n_points) return 0; | |
| if (d1->n_contours != d2->n_contours) return 0; | |
| for (i=0; i<d1->n_points; i++) { | |
| if (d1->points[i].x != d2->points[i].x) return 0; | |
| if (d1->points[i].y != d2->points[i].y) return 0; | |
| } | |
| for (i=0; i<d1->n_points; i++) { | |
| if (d1->tags[i] != d2->tags[i]) return 0; | |
| } | |
| for (i=0; i<d1->n_contours; i++) { | |
| if (d1->contours[i] != d2->contours[i]) return 0; | |
| } | |
| return 1; | |
| #else | |
| if (!gf_list_count(d1->commands) && !gf_list_count(d2->commands)) return 1; | |
| #endif | |
| return 0; | |
| } | |
| case SVG_Points_datatype: | |
| { | |
| GF_List *l1 = *(GF_List **) f1->far_ptr; | |
| GF_List *l2 = *(GF_List **) f2->far_ptr; | |
| u32 i = 0; | |
| u32 count = gf_list_count(l1); | |
| if (gf_list_count(l2)!=count) return 0; | |
| for (i=0; i<count; i++) { | |
| SVG_Point *p1 = (SVG_Point *)gf_list_get(l1, i); | |
| SVG_Point *p2 = (SVG_Point *)gf_list_get(l2, i); | |
| if (p1->x != p2->x) return 0; | |
| if (p1->y != p2->y) return 0; | |
| } | |
| return 1; | |
| } | |
| case SMIL_KeyTimes_datatype: | |
| case SMIL_KeyPoints_datatype: | |
| case SMIL_KeySplines_datatype: | |
| { | |
| GF_List *l1 = *(GF_List **) f1->far_ptr; | |
| GF_List *l2 = *(GF_List **) f2->far_ptr; | |
| u32 i = 0; | |
| u32 count = gf_list_count(l1); | |
| if (gf_list_count(l2)!=count) return 0; | |
| for (i=0; i<count; i++) { | |
| Fixed *p1 = (Fixed *)gf_list_get(l1, i); | |
| Fixed *p2 = (Fixed *)gf_list_get(l2, i); | |
| if (*p1 != *p2) return 0; | |
| } | |
| return 1; | |
| } | |
| case SVG_Coordinates_datatype: | |
| { | |
| GF_List *l1 = *(GF_List **) f1->far_ptr; | |
| GF_List *l2 = *(GF_List **) f2->far_ptr; | |
| u32 i = 0; | |
| u32 count = gf_list_count(l1); | |
| if (gf_list_count(l2) != count) return 0; | |
| for (i=0; i<count; i++) { | |
| SVG_Coordinate *p1 = (SVG_Coordinate *)gf_list_get(l1, i); | |
| SVG_Coordinate *p2 = (SVG_Coordinate *)gf_list_get(l2, i); | |
| if (!svg_numbers_equal(p1, p2)) return 0; | |
| } | |
| return 1; | |
| } | |
| case SVG_ViewBox_datatype: | |
| { | |
| SVG_ViewBox *vb1 = (SVG_ViewBox *)f1->far_ptr; | |
| SVG_ViewBox *vb2 = (SVG_ViewBox *)f2->far_ptr; | |
| return svg_viewbox_equal(vb1, vb2); | |
| } | |
| case SVG_StrokeDashArray_datatype: | |
| { | |
| SVG_StrokeDashArray *p1 = (SVG_StrokeDashArray *)f1->far_ptr; | |
| SVG_StrokeDashArray *p2 = (SVG_StrokeDashArray *)f2->far_ptr; | |
| if (p1->type!=p2->type) return 0; | |
| if (p1->type==SVG_STROKEDASHARRAY_ARRAY) { | |
| u32 i = 0; | |
| if (p1->array.count != p2->array.count) return 0; | |
| for (i=0; i<p1->array.count; i++) { | |
| if (p1->array.units[i] != p2->array.units[i]) return 0; | |
| if (p1->array.vals[i] != p2->array.vals[i]) return 0; | |
| } | |
| } | |
| return 1; | |
| } | |
| case SVG_FontFamily_datatype: | |
| { | |
| SVG_FontFamily *ff1 = (SVG_FontFamily *)f1->far_ptr; | |
| SVG_FontFamily *ff2 = (SVG_FontFamily *)f2->far_ptr; | |
| if (ff1->type!=ff2->type) return 0; | |
| if (ff1->type==SVG_FONTFAMILY_INHERIT) return 1; | |
| return (ff1->value && ff2->value && !strcmp(ff1->value, ff2->value)) ? 1 : 0; | |
| } | |
| case SVG_Clock_datatype: | |
| return (* (SVG_Clock *)f1->far_ptr == * (SVG_Clock *)f2->far_ptr) ? 1 : 0; | |
| /* required for animateMotion */ | |
| case SVG_Motion_datatype: | |
| return svg_matrices_equal((GF_Matrix2D*)f1->far_ptr, (GF_Matrix2D*)f2->far_ptr); | |
| case SVG_Transform_datatype: | |
| { | |
| SVG_Transform *t1 = (SVG_Transform *)f1->far_ptr; | |
| SVG_Transform *t2 = (SVG_Transform *)f2->far_ptr; | |
| if (t1->is_ref == t2->is_ref) | |
| return svg_matrices_equal(&t1->mat, &t2->mat); | |
| else | |
| return 0; | |
| } | |
| case SVG_Transform_Translate_datatype: | |
| case SVG_Transform_Scale_datatype: | |
| { | |
| SVG_Point *p1 = (SVG_Point *)f1->far_ptr; | |
| SVG_Point *p2 = (SVG_Point *)f2->far_ptr; | |
| if (p1->x != p2->x) return 0; | |
| if (p1->y != p2->y) return 0; | |
| return 1; | |
| } | |
| case SVG_Transform_SkewX_datatype: | |
| case SVG_Transform_SkewY_datatype: | |
| { | |
| Fixed *p1 = (Fixed *)f1->far_ptr; | |
| Fixed *p2 = (Fixed *)f2->far_ptr; | |
| return (*p1 == *p2); | |
| } | |
| case SVG_Transform_Rotate_datatype: | |
| { | |
| SVG_Point_Angle *p1 = (SVG_Point_Angle *)f1->far_ptr; | |
| SVG_Point_Angle *p2 = (SVG_Point_Angle *)f2->far_ptr; | |
| if (p1->x != p2->x) return 0; | |
| if (p1->y != p2->y) return 0; | |
| if (p1->angle != p2->angle) return 0; | |
| return 1; | |
| } | |
| case SVG_ID_datatype: | |
| case SVG_LanguageID_datatype: | |
| case SVG_GradientOffset_datatype: | |
| case DOM_String_datatype: | |
| case SVG_ContentType_datatype: | |
| { | |
| char *str1 = *(SVG_String *)f1->far_ptr; | |
| char *str2 = *(SVG_String *)f2->far_ptr; | |
| if (!str1 && !str2) return 1; | |
| return (str1 && str2 && !strcmp(str1, str2)) ? 1 : 0; | |
| } | |
| case SVG_Focus_datatype: | |
| { | |
| SVG_Focus *foc1 = (SVG_Focus *) f1->far_ptr; | |
| SVG_Focus *foc2 = (SVG_Focus *)f2->far_ptr; | |
| if (foc1->type!=foc2->type) return 0; | |
| if (foc1->type != SVG_FOCUS_IRI) return 1; | |
| return (foc1->target.string && foc2->target.string && !strcmp(foc1->target.string, foc2->target.string)) ? 1 : 0; | |
| } | |
| break; | |
| case SVG_ClipPath_datatype: | |
| { | |
| SVG_ClipPath *cp1 = (SVG_ClipPath *) f1->far_ptr; | |
| SVG_ClipPath *cp2 = (SVG_ClipPath *)f2->far_ptr; | |
| return (cp1->target.string && cp2->target.string && !strcmp(cp1->target.string, cp2->target.string)) ? 1 : 0; | |
| } | |
| break; | |
| case DOM_StringList_datatype: | |
| { | |
| GF_List *l1 = *(GF_List **) f1->far_ptr; | |
| GF_List *l2 = *(GF_List **) f2->far_ptr; | |
| u32 i = 0; | |
| u32 count = gf_list_count(l1); | |
| if (gf_list_count(l2) != count) return 0; | |
| for (i=0; i<count; i++) { | |
| char *p1 = (char *)gf_list_get(l1, i); | |
| char *p2 = (char *)gf_list_get(l2, i); | |
| if (strcmp(p1, p2)) return 0; | |
| } | |
| return 1; | |
| } | |
| case SVG_Numbers_datatype: | |
| { | |
| GF_List *l1 = *(GF_List **) f1->far_ptr; | |
| GF_List *l2 = *(GF_List **) f2->far_ptr; | |
| u32 i = 0; | |
| u32 count = gf_list_count(l1); | |
| if (gf_list_count(l2) != count) return 0; | |
| for (i=0; i<count; i++) { | |
| SVG_Number *p1 = (SVG_Number *)gf_list_get(l1, i); | |
| SVG_Number *p2 = (SVG_Number *)gf_list_get(l2, i); | |
| if (!svg_numbers_equal(p1, p2)) return 0; | |
| } | |
| return 1; | |
| } | |
| case SMIL_Times_datatype: | |
| { | |
| GF_List *l1 = *(GF_List **) f1->far_ptr; | |
| GF_List *l2 = *(GF_List **) f2->far_ptr; | |
| u32 i = 0; | |
| u32 count = gf_list_count(l1); | |
| if (gf_list_count(l2) != count) return 0; | |
| for (i=0; i<count; i++) { | |
| SMIL_Time *p1 = (SMIL_Time *)gf_list_get(l1, i); | |
| SMIL_Time *p2 = (SMIL_Time *)gf_list_get(l2, i); | |
| if (p1->type != p2->type) return 0; | |
| if (p1->clock != p2->clock) return 0; | |
| if (p1->type==GF_SMIL_TIME_EVENT) { | |
| if (p1->event.type != p2->event.type) return 0; | |
| if (p1->event.parameter != p2->event.parameter) return 0; | |
| } | |
| } | |
| return 1; | |
| } | |
| case SMIL_Duration_datatype: | |
| { | |
| SMIL_Duration *d1 = (SMIL_Duration *)f1->far_ptr; | |
| SMIL_Duration *d2 = (SMIL_Duration *)f2->far_ptr; | |
| if (d1->type != d2->type) return 0; | |
| if (d1->clock_value != d2->clock_value) return 0; | |
| return 1; | |
| } | |
| case SMIL_RepeatCount_datatype: | |
| { | |
| SMIL_RepeatCount *d1 = (SMIL_RepeatCount *)f1->far_ptr; | |
| SMIL_RepeatCount *d2 = (SMIL_RepeatCount *)f2->far_ptr; | |
| if (d1->type != d2->type) return 0; | |
| if (d1->count != d2->count) return 0; | |
| return 1; | |
| } | |
| case SMIL_AttributeName_datatype: | |
| { | |
| SMIL_AttributeName *att1 = (SMIL_AttributeName *) f1->far_ptr; | |
| SMIL_AttributeName *att2 = (SMIL_AttributeName *) f2->far_ptr; | |
| /*TODO check me...*/ | |
| if (att2->field_ptr == att1->field_ptr) return 1; | |
| return 0; | |
| } | |
| case SMIL_AnimateValue_datatype: | |
| { | |
| SMIL_AnimateValue *av1 = (SMIL_AnimateValue*)f1->far_ptr; | |
| SMIL_AnimateValue *av2 = (SMIL_AnimateValue*)f2->far_ptr; | |
| if (av1->value != av2->value) return 0; | |
| return 1; | |
| } | |
| break; | |
| case SMIL_AnimateValues_datatype: | |
| { | |
| u32 count; | |
| SMIL_AnimateValues *av1 = (SMIL_AnimateValues*)f1->far_ptr; | |
| SMIL_AnimateValues *av2 = (SMIL_AnimateValues*)f2->far_ptr; | |
| if (av1->type != av2->type) return 0; | |
| if ( (count = gf_list_count(av1->values) ) != gf_list_count(av1->values)) return 0; | |
| return count ? 0 : 1; | |
| } | |
| case XMLEV_Event_datatype: | |
| { | |
| XMLEV_Event *d1 = (XMLEV_Event *)f1->far_ptr; | |
| XMLEV_Event *d2 = (XMLEV_Event *)f2->far_ptr; | |
| if (d1->type != d2->type) return 0; | |
| if (d1->parameter != d2->parameter) return 0; | |
| return 1; | |
| } | |
| case LASeR_Size_datatype: | |
| { | |
| LASeR_Size *sz1 = (LASeR_Size *)f1->far_ptr; | |
| LASeR_Size *sz2 = (LASeR_Size *)f2->far_ptr; | |
| if (sz1->width != sz2->width) return 0; | |
| if (sz1->height != sz2->height) return 0; | |
| return 1; | |
| } | |
| default: | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_SCENE, ("[SVG Attributes] comparaison for field %s of type %s not supported\n", f1->name ? f1->name : "unknown", gf_svg_attribute_type_to_string(f1->fieldType))); | |
| return 0; | |
| } | |
| } | |
| static void svg_color_clamp(SVG_Color *a) | |
| { | |
| a->red = MAX(0, MIN(FIX_ONE, a->red)); | |
| a->green = MAX(0, MIN(FIX_ONE, a->green)); | |
| a->blue = MAX(0, MIN(FIX_ONE, a->blue)); | |
| } | |
| static GF_Err svg_color_muladd(Fixed alpha, SVG_Color *a, Fixed beta, SVG_Color *b, SVG_Color *c, Bool clamp) | |
| { | |
| if (a->type != SVG_COLOR_RGBCOLOR || b->type != SVG_COLOR_RGBCOLOR) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] only RGB colors are additive\n")); | |
| return GF_BAD_PARAM; | |
| } | |
| c->type = SVG_COLOR_RGBCOLOR; | |
| c->red = gf_mulfix(alpha, a->red) + gf_mulfix(beta, b->red); | |
| c->green = gf_mulfix(alpha, a->green) + gf_mulfix(beta, b->green); | |
| c->blue = gf_mulfix(alpha, a->blue) + gf_mulfix(beta, b->blue); | |
| if (clamp) svg_color_clamp(c); | |
| return GF_OK; | |
| } | |
| static GF_Err svg_number_muladd(Fixed alpha, SVG_Number *a, Fixed beta, SVG_Number *b, SVG_Number *c) | |
| { | |
| if (!a || !b || !c) return GF_BAD_PARAM; | |
| if (a->type != b->type) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] cannot add lengths of mismatching types\n")); | |
| return GF_BAD_PARAM; | |
| } | |
| if (a->type == SVG_NUMBER_INHERIT || a->type == SVG_NUMBER_AUTO) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] cannot add lengths\n")); | |
| return GF_BAD_PARAM; | |
| } | |
| c->value = gf_mulfix(alpha, a->value) + gf_mulfix(beta, b->value); | |
| return GF_OK; | |
| } | |
| static GF_Err svg_viewbox_muladd(Fixed alpha, SVG_ViewBox *a, Fixed beta, SVG_ViewBox *b, SVG_ViewBox *c) | |
| { | |
| c->is_set = 1; | |
| c->x = gf_mulfix(alpha, a->x) + gf_mulfix(beta, b->x); | |
| c->y = gf_mulfix(alpha, a->y) + gf_mulfix(beta, b->y); | |
| c->width = gf_mulfix(alpha, a->width) + gf_mulfix(beta, b->width); | |
| c->height= gf_mulfix(alpha, a->height) + gf_mulfix(beta, b->height); | |
| return GF_OK; | |
| } | |
| static GF_Err svg_point_muladd(Fixed alpha, SVG_Point *pta, Fixed beta, SVG_Point *ptb, SVG_Point *ptc) | |
| { | |
| if (!pta || !ptb || !ptc) return GF_BAD_PARAM; | |
| ptc->x = gf_mulfix(alpha, pta->x) + gf_mulfix(beta, ptb->x); | |
| ptc->y = gf_mulfix(alpha, pta->y) + gf_mulfix(beta, ptb->y); | |
| return GF_OK; | |
| } | |
| static GF_Err svg_point_angle_muladd(Fixed alpha, SVG_Point_Angle *pta, Fixed beta, SVG_Point_Angle *ptb, SVG_Point_Angle *ptc) | |
| { | |
| ptc->x = gf_mulfix(alpha, pta->x) + gf_mulfix(beta, ptb->x); | |
| ptc->y = gf_mulfix(alpha, pta->y) + gf_mulfix(beta, ptb->y); | |
| ptc->angle = gf_mulfix(alpha, pta->angle) + gf_mulfix(beta, ptb->angle); | |
| return GF_OK; | |
| } | |
| static GF_Err svg_points_muladd(Fixed alpha, SVG_Points *a, Fixed beta, SVG_Points *b, SVG_Points *c) | |
| { | |
| u32 a_count = gf_list_count(*a); | |
| u32 i; | |
| if (a_count != gf_list_count(*b)) return GF_BAD_PARAM; | |
| while (gf_list_count(*c)) { | |
| SVG_Point *ptc = (SVG_Point *)gf_list_get(*c, 0); | |
| gf_list_rem(*c, 0); | |
| gf_free(ptc); | |
| } | |
| for (i = 0; i < a_count; i ++) { | |
| SVG_Point *ptc; | |
| SVG_Point *pta = (SVG_Point *)gf_list_get(*a, i); | |
| SVG_Point *ptb = (SVG_Point *)gf_list_get(*b, i); | |
| GF_SAFEALLOC(ptc, SVG_Point) | |
| if (!ptc) break; | |
| svg_point_muladd(alpha, pta, beta, ptb, ptc); | |
| gf_list_add(*c, ptc); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err svg_points_copy(SVG_Points *a, SVG_Points *b) | |
| { | |
| u32 i, count; | |
| count = gf_list_count(*a); | |
| for (i = 0; i < count; i++) { | |
| SVG_Point *pt = (SVG_Point *)gf_list_get(*a, i); | |
| gf_free(pt); | |
| } | |
| gf_list_reset(*a); | |
| count = gf_list_count(*b); | |
| for (i = 0; i < count; i ++) { | |
| SVG_Point *ptb = (SVG_Point *)gf_list_get(*b, i); | |
| SVG_Point *pta; | |
| GF_SAFEALLOC(pta, SVG_Point) | |
| if (!pta) return GF_OUT_OF_MEM; | |
| *pta = *ptb; | |
| gf_list_add(*a, pta); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err svg_numbers_muladd(Fixed alpha, SVG_Numbers *a, Fixed beta, SVG_Numbers *b, SVG_Numbers *c) | |
| { | |
| u32 a_count = gf_list_count(*a); | |
| u32 i; | |
| if (a_count != gf_list_count(*b)) return GF_BAD_PARAM; | |
| while (gf_list_count(*c)) { | |
| SVG_Number *nc = gf_list_pop_back(*c); | |
| gf_free(nc); | |
| } | |
| for (i = 0; i < a_count; i ++) { | |
| SVG_Number *nc; | |
| SVG_Number *na = (SVG_Number *)gf_list_get(*a, i); | |
| SVG_Number *nb = (SVG_Number *)gf_list_get(*b, i); | |
| GF_SAFEALLOC(nc, SVG_Number) | |
| if (!nc) return GF_OUT_OF_MEM; | |
| svg_number_muladd(alpha, na, beta, nb, nc); | |
| gf_list_add(*c, nc); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err svg_numbers_copy(SVG_Numbers *a, SVG_Numbers *b) | |
| { | |
| u32 i, count; | |
| count = gf_list_count(*a); | |
| for (i = 0; i < count; i++) { | |
| SVG_Coordinate *c = (SVG_Coordinate *)gf_list_get(*a, i); | |
| gf_free(c); | |
| } | |
| gf_list_reset(*a); | |
| count = gf_list_count(*b); | |
| for (i = 0; i < count; i ++) { | |
| SVG_Number *na; | |
| GF_SAFEALLOC(na, SVG_Number) | |
| if (!na) return GF_OUT_OF_MEM; | |
| *na = *(SVG_Number *)gf_list_get(*b, i); | |
| gf_list_add(*a, na); | |
| } | |
| return GF_OK; | |
| } | |
| #if USE_GF_PATH | |
| static GF_Err svg_path_copy(SVG_PathData *a, SVG_PathData *b) | |
| { | |
| if (!b) | |
| return GF_BAD_PARAM; | |
| if (a->contours) gf_free(a->contours); | |
| if (a->points) gf_free(a->points); | |
| if (a->tags) gf_free(a->tags); | |
| memset(a, 0, sizeof(SVG_PathData)); | |
| if (b->contours && b->n_contours) { | |
| a->contours = (u32 *)gf_malloc(sizeof(u32)*b->n_contours); | |
| memcpy(a->contours, b->contours, sizeof(u32)*b->n_contours); | |
| a->n_contours = b->n_contours; | |
| } | |
| if (b->points && b->n_points) { | |
| a->points = (GF_Point2D *) gf_malloc(sizeof(GF_Point2D)*b->n_points); | |
| memcpy(a->points, b->points, sizeof(GF_Point2D)*b->n_points); | |
| a->n_alloc_points = a->n_points = b->n_points; | |
| } | |
| if (b->tags && b->n_points) { | |
| a->tags = (u8 *) gf_malloc(sizeof(u8)*b->n_points); | |
| memcpy(a->tags, b->tags, sizeof(u8)*b->n_points); | |
| } | |
| a->flags = b->flags; | |
| a->bbox = b->bbox; | |
| a->fineness = b->fineness; | |
| return GF_OK; | |
| } | |
| #else | |
| static GF_Err svg_path_copy(SVG_PathData *a, SVG_PathData *b) | |
| { | |
| u32 i, count; | |
| count = gf_list_count(a->commands); | |
| for (i = 0; i < count; i++) { | |
| u8 *command = (u8 *)gf_list_get(a->commands, i); | |
| gf_free(command); | |
| } | |
| gf_list_reset(a->commands); | |
| count = gf_list_count(a->points); | |
| for (i = 0; i < count; i++) { | |
| SVG_Point *pt = (SVG_Point *)gf_list_get(a->points, i); | |
| gf_free(pt); | |
| } | |
| gf_list_reset(a->points); | |
| count = gf_list_count(b->commands); | |
| for (i = 0; i < count; i ++) { | |
| u8 *nc = (u8 *)gf_malloc(sizeof(u8)); | |
| *nc = *(u8*)gf_list_get(b->commands, i); | |
| gf_list_add(a->commands, nc); | |
| } | |
| count = gf_list_count(b->points); | |
| for (i = 0; i < count; i ++) { | |
| SVG_Point *pta; | |
| GF_SAFEALLOC(pta, SVG_Point) | |
| if (!pta) break; | |
| *pta = *(SVG_Point *)gf_list_get(b->points, i); | |
| gf_list_add(a->points, pta); | |
| } | |
| return GF_OK; | |
| } | |
| #endif | |
| #if USE_GF_PATH | |
| static GF_Err svg_path_muladd(Fixed alpha, SVG_PathData *a, Fixed beta, SVG_PathData *b, SVG_PathData *c) | |
| { | |
| u32 i; | |
| if (a->n_points != b->n_points) return GF_BAD_PARAM; | |
| gf_path_reset(c); | |
| svg_path_copy(c, a); | |
| for (i=0; i<a->n_points; i++) { | |
| svg_point_muladd(alpha, (SVG_Point *) &a->points[i], beta, (SVG_Point *) &b->points[i], (SVG_Point *) &c->points[i]); | |
| } | |
| c->flags |= GF_PATH_BBOX_DIRTY; | |
| c->flags &= ~GF_PATH_FLATTENED; | |
| return GF_OK; | |
| } | |
| #else | |
| static GF_Err svg_path_muladd(Fixed alpha, SVG_PathData *a, Fixed beta, SVG_PathData *b, SVG_PathData *c) | |
| { | |
| u32 i, ccount, pcount; | |
| ccount = gf_list_count(a->commands); | |
| pcount = gf_list_count(a->points); | |
| if (pcount != gf_list_count(b->points)) return GF_BAD_PARAM; | |
| #if 0 | |
| if (ccount != gf_list_count(b->commands)) return GF_BAD_PARAM; | |
| for (i = 0; i < ccount; i++) { | |
| u8 *ac = gf_list_get(a->commands, i); | |
| u8 *bc = gf_list_get(b->commands, i); | |
| if (*ac != *bc) return GF_BAD_PARAM; | |
| } | |
| #endif | |
| while (gf_list_count(c->commands)) { | |
| u8 *command = (u8 *)gf_list_last(c->commands); | |
| gf_free(command); | |
| gf_list_rem_last(c->commands); | |
| } | |
| while (gf_list_count(c->points)) { | |
| SVG_Point *pt = (SVG_Point *)gf_list_last(c->points); | |
| gf_free(pt); | |
| gf_list_rem_last(c->points); | |
| } | |
| for (i = 0; i < ccount; i++) { | |
| u8 *nc = (u8 *)gf_malloc(sizeof(u8)); | |
| *nc = *(u8*)gf_list_get(a->commands, i); | |
| gf_list_add(c->commands, nc); | |
| } | |
| for (i = 0; i < pcount; i++) { | |
| SVG_Point *pta = (SVG_Point *)gf_list_get(a->points, i); | |
| SVG_Point *ptb = (SVG_Point *)gf_list_get(b->points, i); | |
| SVG_Point *ptc; | |
| GF_SAFEALLOC(ptc, SVG_Point) | |
| if (!ptc) break; | |
| svg_point_muladd(alpha, pta, beta, ptb, ptc); | |
| gf_list_add(c->points, ptc); | |
| } | |
| return GF_OK; | |
| } | |
| #endif | |
| static GF_Err svg_dasharray_muladd(Fixed alpha, SVG_StrokeDashArray *a, Fixed beta, SVG_StrokeDashArray *b, SVG_StrokeDashArray *c) | |
| { | |
| u32 i; | |
| if (a->type != b->type) return GF_BAD_PARAM; | |
| if (a->array.count != b->array.count) return GF_BAD_PARAM; | |
| c->type = a->type; | |
| if (c->array.count != a->array.count) { | |
| c->array.count = a->array.count; | |
| c->array.vals = (Fixed *) gf_realloc(c->array.vals, sizeof(Fixed)*c->array.count); | |
| c->array.units = (u8 *) gf_realloc(c->array.units, sizeof(u8)*c->array.count); | |
| } | |
| if (!c->array.vals || !c->array.units) return GF_OUT_OF_MEM; | |
| for (i = 0; i < c->array.count; i++) { | |
| /* TODO: convert units if needed */ | |
| c->array.units[i] = a->array.units[i]; | |
| c->array.vals[i] = gf_mulfix(alpha, a->array.vals[i]) + gf_mulfix(beta, b->array.vals[i]); | |
| } | |
| return GF_OK; | |
| } | |
| static GF_Err svg_dasharray_copy(SVG_StrokeDashArray *a, SVG_StrokeDashArray *b) | |
| { | |
| a->type = b->type; | |
| if (a->array.count != b->array.count) { | |
| a->array.count = b->array.count; | |
| a->array.units = (u8*)gf_realloc(a->array.units, sizeof(u8)*a->array.count); | |
| a->array.vals = (Fixed*)gf_realloc(a->array.vals, sizeof(Fixed)*a->array.count); | |
| } | |
| if (!a->array.vals || !a->array.units) return GF_OUT_OF_MEM; | |
| memcpy(a->array.units, b->array.units, sizeof(u8)*a->array.count); | |
| memcpy(a->array.vals, b->array.vals, sizeof(Fixed)*a->array.count); | |
| return GF_OK; | |
| } | |
| static GF_Err svg_matrix_muladd(Fixed alpha, GF_Matrix2D *a, Fixed beta, GF_Matrix2D *b, GF_Matrix2D *c) | |
| { | |
| /* | |
| if ((alpha == beta) && (alpha == FIX_ONE) ) { | |
| GF_Matrix2D tmp; | |
| gf_mx2d_copy(tmp, *b); | |
| gf_mx2d_add_matrix(&tmp, a); | |
| gf_mx2d_copy(*c, tmp); | |
| } else */ | |
| if (alpha <= FIX_ONE) { | |
| /* This case should happen only when using animateMotion and accumulation | |
| see animate-elem-202-t.svg | |
| we only add and multiply the translation component; */ | |
| /* | |
| c->m[0] = gf_mulfix(alpha, a->m[0]) + gf_mulfix(beta, b->m[0]); | |
| c->m[1] = gf_mulfix(alpha, a->m[1]) + gf_mulfix(beta, b->m[1]); | |
| c->m[2] = gf_mulfix(alpha, a->m[2]) + gf_mulfix(beta, b->m[2]); | |
| c->m[3] = gf_mulfix(alpha, a->m[3]) + gf_mulfix(beta, b->m[3]); | |
| */ | |
| c->m[0] = a->m[0]; | |
| c->m[1] = a->m[1]; | |
| c->m[2] = gf_mulfix(alpha, a->m[2]) + gf_mulfix(beta, b->m[2]); | |
| c->m[3] = a->m[3]; | |
| c->m[4] = a->m[4]; | |
| c->m[5] = gf_mulfix(alpha, a->m[5]) + gf_mulfix(beta, b->m[5]); | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] matrix operations not supported\n")); | |
| return GF_BAD_PARAM; | |
| } | |
| return GF_OK; | |
| } | |
| /* c = alpha * a + beta * b */ | |
| GF_Err gf_svg_attributes_muladd(Fixed alpha, GF_FieldInfo *a, | |
| Fixed beta, GF_FieldInfo *b, | |
| GF_FieldInfo *c, | |
| Bool clamp) | |
| { | |
| if (!a->far_ptr || !b->far_ptr || !c->far_ptr) return GF_BAD_PARAM; | |
| if (a->fieldType != b->fieldType) { | |
| if (a->fieldType != SVG_Transform_datatype && | |
| a->fieldType != SVG_Transform_Scale_datatype && | |
| a->fieldType != SVG_Transform_Translate_datatype && | |
| a->fieldType != SVG_Transform_Rotate_datatype && | |
| a->fieldType != SVG_Transform_SkewX_datatype && | |
| a->fieldType != SVG_Transform_SkewY_datatype && | |
| a->fieldType != SVG_Motion_datatype) | |
| return GF_BAD_PARAM; | |
| } | |
| /* by default a and c are of the same type, except for matrix related types */ | |
| c->fieldType = a->fieldType; | |
| switch (a->fieldType) { | |
| /* Numeric types */ | |
| case SVG_Color_datatype: | |
| return svg_color_muladd(alpha, (SVG_Color*)a->far_ptr, beta, (SVG_Color*)b->far_ptr, (SVG_Color*)c->far_ptr, clamp); | |
| case SVG_Paint_datatype: | |
| { | |
| SVG_Paint *pa = (SVG_Paint *)a->far_ptr; | |
| SVG_Paint *pb = (SVG_Paint *)b->far_ptr; | |
| SVG_Paint *pc = (SVG_Paint *)c->far_ptr; | |
| if (pa->type != pb->type || pa->type != SVG_PAINT_COLOR || pb->type != SVG_PAINT_COLOR) { | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_SCENE, ("[SVG Attributes] only color paints are additive, cannot interpolate URIs\n")); | |
| return GF_BAD_PARAM; | |
| } | |
| pc->type = SVG_PAINT_COLOR; | |
| return svg_color_muladd(alpha, &pa->color, beta, &pb->color, &pc->color, clamp); | |
| } | |
| case SVG_Number_datatype: | |
| case SVG_Length_datatype: | |
| case SVG_Coordinate_datatype: | |
| case SVG_FontSize_datatype: | |
| return svg_number_muladd(alpha, (SVG_Number*)a->far_ptr, beta, (SVG_Number*)b->far_ptr, (SVG_Number*)c->far_ptr); | |
| case SVG_ViewBox_datatype: | |
| return svg_viewbox_muladd(alpha, (SVG_ViewBox*)a->far_ptr, beta, (SVG_ViewBox*)b->far_ptr, (SVG_ViewBox*)c->far_ptr); | |
| case SVG_Points_datatype: | |
| return svg_points_muladd(alpha, (GF_List **)a->far_ptr, beta, (GF_List **)b->far_ptr, (GF_List **)c->far_ptr); | |
| case SVG_Numbers_datatype: | |
| case SVG_Coordinates_datatype: | |
| return svg_numbers_muladd(alpha, (GF_List **)a->far_ptr, beta, (GF_List **)b->far_ptr, (GF_List **)c->far_ptr); | |
| case SVG_PathData_datatype: | |
| return svg_path_muladd(alpha, (SVG_PathData*)a->far_ptr, beta, (SVG_PathData*)b->far_ptr, (SVG_PathData*)c->far_ptr); | |
| case SVG_StrokeDashArray_datatype: | |
| return svg_dasharray_muladd(alpha, (SVG_StrokeDashArray*)a->far_ptr, beta, (SVG_StrokeDashArray*)b->far_ptr, (SVG_StrokeDashArray*)c->far_ptr); | |
| case SVG_Motion_datatype: | |
| return svg_matrix_muladd(alpha, (GF_Matrix2D*)a->far_ptr, beta, (GF_Matrix2D*)b->far_ptr, (GF_Matrix2D*)c->far_ptr); | |
| case SVG_Transform_datatype: | |
| if (b->fieldType == SVG_Transform_datatype) { | |
| SVG_Transform *ta = (SVG_Transform *)a->far_ptr; | |
| SVG_Transform *tb = (SVG_Transform *)b->far_ptr; | |
| SVG_Transform *tc = (SVG_Transform *)c->far_ptr; | |
| if (ta->is_ref == tb->is_ref) { | |
| return svg_matrix_muladd(alpha, &ta->mat, beta, &tb->mat, &tc->mat); | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] matrix operations not supported\n")); | |
| return GF_NOT_SUPPORTED; | |
| } | |
| } else { | |
| /* a and c are matrices but b is not */ | |
| GF_Matrix2D tmp; | |
| /*TOCHECK what is this test*/ | |
| /* | |
| if (alpha != FIX_ONE) { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] matrix operations not supported\n")); | |
| return GF_NOT_SUPPORTED; | |
| } | |
| */ | |
| gf_mx2d_init(tmp); | |
| switch (b->fieldType) { | |
| case SVG_Transform_Translate_datatype: | |
| gf_mx2d_add_translation(&tmp, gf_mulfix(((SVG_Point *)b->far_ptr)->x, beta), gf_mulfix(((SVG_Point *)b->far_ptr)->y, beta)); | |
| break; | |
| case SVG_Transform_Scale_datatype: | |
| gf_mx2d_add_scale(&tmp, gf_mulfix(((SVG_Point *)b->far_ptr)->x, beta), gf_mulfix(((SVG_Point *)b->far_ptr)->y, beta)); | |
| break; | |
| case SVG_Transform_Rotate_datatype: | |
| 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)); | |
| break; | |
| case SVG_Transform_SkewX_datatype: | |
| gf_mx2d_add_skew_x(&tmp, gf_mulfix(*(Fixed*)b->far_ptr, beta)); | |
| break; | |
| case SVG_Transform_SkewY_datatype: | |
| gf_mx2d_add_skew_y(&tmp, gf_mulfix(*(Fixed*)b->far_ptr, beta)); | |
| break; | |
| default: | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] copy of attributes %s not supported\n", a->name)); | |
| return GF_NOT_SUPPORTED; | |
| } | |
| gf_mx2d_add_matrix(&tmp, &((SVG_Transform*)a->far_ptr)->mat); | |
| gf_mx2d_copy(((SVG_Transform*)c->far_ptr)->mat, tmp); | |
| return GF_OK; | |
| } | |
| case SVG_Transform_Translate_datatype: | |
| if (b->fieldType == SVG_Transform_Translate_datatype) { | |
| return svg_point_muladd(alpha, (SVG_Point*)a->far_ptr, beta, (SVG_Point*)b->far_ptr, (SVG_Point*)c->far_ptr); | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] matrix operations not supported\n")); | |
| return GF_NOT_SUPPORTED; | |
| } | |
| case SVG_Transform_Scale_datatype: | |
| if (b->fieldType == SVG_Transform_Scale_datatype) { | |
| if (alpha == FIX_ONE && beta == FIX_ONE) { | |
| /* addition of matrices which represent scales is equivalent | |
| to multiplication of scale coefficients, we assume this only happens if | |
| alpha and beta are set to one */ | |
| ((SVG_Point*)c->far_ptr)->x = gf_mulfix(((SVG_Point*)a->far_ptr)->x,((SVG_Point*)b->far_ptr)->x); | |
| ((SVG_Point*)c->far_ptr)->y = gf_mulfix(((SVG_Point*)a->far_ptr)->y,((SVG_Point*)b->far_ptr)->y); | |
| return GF_OK; | |
| } else { | |
| return svg_point_muladd(alpha, (SVG_Point*)a->far_ptr, beta, (SVG_Point*)b->far_ptr, (SVG_Point*)c->far_ptr); | |
| } | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] matrix operations not supported\n")); | |
| return GF_NOT_SUPPORTED; | |
| } | |
| case SVG_Transform_Rotate_datatype: | |
| if (b->fieldType == SVG_Transform_Rotate_datatype) { | |
| 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); | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] matrix operations not supported\n")); | |
| return GF_NOT_SUPPORTED; | |
| } | |
| case SVG_Transform_SkewX_datatype: | |
| if (b->fieldType == SVG_Transform_SkewX_datatype) { | |
| *(Fixed*)c->far_ptr = gf_mulfix(alpha, *(Fixed*)a->far_ptr) + gf_mulfix(beta, *(Fixed*)b->far_ptr); | |
| return GF_OK; | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] matrix operations not supported\n")); | |
| return GF_NOT_SUPPORTED; | |
| } | |
| case SVG_Transform_SkewY_datatype: | |
| if (b->fieldType == SVG_Transform_SkewY_datatype) { | |
| *(Fixed*)c->far_ptr = gf_mulfix(alpha, *(Fixed*)a->far_ptr) + gf_mulfix(beta, *(Fixed*)b->far_ptr); | |
| return GF_OK; | |
| } else { | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] matrix operations not supported\n")); | |
| return GF_NOT_SUPPORTED; | |
| } | |
| case DOM_String_datatype: | |
| { | |
| u32 len; | |
| char *res; | |
| SVG_String *s_a = (SVG_String *)a->far_ptr; | |
| SVG_String *s_b = (SVG_String *)b->far_ptr; | |
| u32 len_a = *s_a ? (u32) strlen(*s_a) : 0; | |
| u32 len_b = *s_b ? (u32) strlen(*s_b) : 0; | |
| len_a = FIX2INT(alpha * len_a); | |
| len_b = FIX2INT(beta * len_b); | |
| len = len_a + len_b + 1; | |
| res = (char*)gf_malloc(sizeof(char) * len); | |
| if (len_a) | |
| memcpy(res, *s_a, len_a); | |
| if (len_b) | |
| memcpy(res+len_a, *s_b, len_b); | |
| res[len-1] = 0; | |
| s_a = (SVG_String*)c->far_ptr; | |
| if (*s_a) gf_free(*s_a); | |
| *s_a = res; | |
| } | |
| break; | |
| case LASeR_Size_datatype: | |
| { | |
| LASeR_Size *sza = (LASeR_Size*)a->far_ptr; | |
| LASeR_Size *szb = (LASeR_Size*)b->far_ptr; | |
| LASeR_Size *szc = (LASeR_Size*)c->far_ptr; | |
| szc->width = gf_mulfix(alpha, sza->width) + gf_mulfix(beta, szb->width); | |
| szc->height = gf_mulfix(alpha, sza->height) + gf_mulfix(beta, szb->height); | |
| } | |
| break; | |
| /* Keyword types */ | |
| case SVG_Boolean_datatype: | |
| case SVG_FillRule_datatype: | |
| case SVG_StrokeLineJoin_datatype: | |
| case SVG_StrokeLineCap_datatype: | |
| case SVG_FontStyle_datatype: | |
| case SVG_FontWeight_datatype: | |
| case SVG_FontVariant_datatype: | |
| case SVG_TextAnchor_datatype: | |
| case SVG_Display_datatype: | |
| case SVG_Visibility_datatype: | |
| case SVG_GradientUnit_datatype: | |
| case SVG_PreserveAspectRatio_datatype: | |
| case XML_Space_datatype: | |
| case XMLEV_Propagate_datatype: | |
| case XMLEV_DefaultAction_datatype: | |
| case XMLEV_Phase_datatype: | |
| case SMIL_SyncBehavior_datatype: | |
| case SMIL_SyncTolerance_datatype: | |
| case SMIL_AttributeType_datatype: | |
| case SMIL_CalcMode_datatype: | |
| case SMIL_Additive_datatype: | |
| case SMIL_Accumulate_datatype: | |
| case SMIL_Restart_datatype: | |
| case SMIL_Fill_datatype: | |
| case SVG_Overflow_datatype: | |
| case SVG_ZoomAndPan_datatype: | |
| case SVG_DisplayAlign_datatype: | |
| case SVG_TextAlign_datatype: | |
| case SVG_PointerEvents_datatype: | |
| case SVG_RenderingHint_datatype: | |
| case SVG_VectorEffect_datatype: | |
| case SVG_PlaybackOrder_datatype: | |
| case SVG_TimelineBegin_datatype: | |
| case SVG_SpreadMethod_datatype: | |
| case SVG_TransformType_datatype: | |
| /* Unsupported types */ | |
| case SVG_ContentType_datatype: | |
| case SVG_LanguageID_datatype: | |
| case SVG_FontFamily_datatype: | |
| case XMLRI_datatype: | |
| case XMLRI_List_datatype: | |
| case DOM_StringList_datatype: | |
| case SVG_Clock_datatype: | |
| case SVG_Focus_datatype: | |
| case SVG_ID_datatype: | |
| case SVG_GradientOffset_datatype: | |
| case SMIL_KeyTimes_datatype: | |
| case SMIL_KeyPoints_datatype: | |
| case SMIL_KeySplines_datatype: | |
| case SMIL_AnimateValue_datatype: | |
| case SMIL_AnimateValues_datatype: | |
| case SMIL_AttributeName_datatype: | |
| case SMIL_Times_datatype: | |
| case SMIL_Duration_datatype: | |
| case SMIL_RepeatCount_datatype: | |
| case SVG_ClipPath_datatype: | |
| default: | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_SCENE, ("[SVG Attributes] addition for attributes %s of type %s not supported\n", a->name, gf_svg_attribute_type_to_string(a->fieldType))); | |
| return GF_NOT_SUPPORTED; | |
| } | |
| return GF_OK; | |
| } | |
| /* *a = *b, copy by value */ | |
| GF_EXPORT | |
| GF_Err gf_svg_attributes_copy(GF_FieldInfo *a, GF_FieldInfo *b, Bool clamp) | |
| { | |
| if (!a->far_ptr || !b->far_ptr) return GF_BAD_PARAM; | |
| switch (a->fieldType) { | |
| /* Numeric types */ | |
| case SVG_Color_datatype: | |
| *((SVG_Color *)a->far_ptr) = *((SVG_Color *)b->far_ptr); | |
| if (clamp) svg_color_clamp((SVG_Color *)a->far_ptr); | |
| break; | |
| case SVG_Paint_datatype: | |
| { | |
| SVG_Paint *pa = (SVG_Paint *)a->far_ptr; | |
| SVG_Paint *pb = (SVG_Paint *)b->far_ptr; | |
| pa->type = pb->type; | |
| if (pb->type == SVG_PAINT_URI) { | |
| GF_FieldInfo tmp_a, tmp_b; | |
| tmp_a.fieldType = tmp_b.fieldType = XMLRI_datatype; | |
| tmp_a.far_ptr = &pa->iri; | |
| tmp_b.far_ptr = &pb->iri; | |
| gf_svg_attributes_copy(&tmp_a, &tmp_b, 0); | |
| } else { | |
| pa->color = pb->color; | |
| } | |
| return GF_OK; | |
| } | |
| break; | |
| case SVG_Number_datatype: | |
| case SVG_Length_datatype: | |
| case SVG_Coordinate_datatype: | |
| case SVG_FontSize_datatype: | |
| *((SVG_Number *)a->far_ptr) = *((SVG_Number *)b->far_ptr); | |
| break; | |
| case SVG_ViewBox_datatype: | |
| *((SVG_ViewBox *)a->far_ptr) = *((SVG_ViewBox *)b->far_ptr); | |
| break; | |
| case SVG_Points_datatype: | |
| return svg_points_copy((GF_List**)a->far_ptr, (GF_List**)b->far_ptr); | |
| case SVG_Numbers_datatype: | |
| case SVG_Coordinates_datatype: | |
| return svg_numbers_copy((GF_List**)a->far_ptr, (GF_List**)b->far_ptr); | |
| case SVG_PathData_datatype: | |
| return svg_path_copy((SVG_PathData*)a->far_ptr, (SVG_PathData*)b->far_ptr); | |
| case SVG_StrokeDashArray_datatype: | |
| return svg_dasharray_copy((SVG_StrokeDashArray*)a->far_ptr, (SVG_StrokeDashArray*)b->far_ptr); | |
| case SVG_Motion_datatype: | |
| gf_mx2d_copy(*(GF_Matrix2D *)a->far_ptr, *(GF_Matrix2D *)b->far_ptr); | |
| return GF_OK; | |
| case SVG_Transform_datatype: | |
| switch (b->fieldType) { | |
| case SVG_Transform_Translate_datatype: | |
| gf_mx2d_init(((SVG_Transform *)a->far_ptr)->mat); | |
| gf_mx2d_add_translation(&((SVG_Transform *)a->far_ptr)->mat, ((SVG_Point*)b->far_ptr)->x, ((SVG_Point*)b->far_ptr)->y); | |
| break; | |
| case SVG_Transform_Scale_datatype: | |
| gf_mx2d_init(((SVG_Transform *)a->far_ptr)->mat); | |
| gf_mx2d_add_scale(&((SVG_Transform *)a->far_ptr)->mat, ((SVG_Point*)b->far_ptr)->x, ((SVG_Point*)b->far_ptr)->y); | |
| break; | |
| case SVG_Transform_Rotate_datatype: | |
| gf_mx2d_init(((SVG_Transform *)a->far_ptr)->mat); | |
| 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); | |
| break; | |
| case SVG_Transform_SkewX_datatype: | |
| gf_mx2d_init(((SVG_Transform *)a->far_ptr)->mat); | |
| gf_mx2d_add_skew_x(&((SVG_Transform *)a->far_ptr)->mat, *(Fixed *)b->far_ptr); | |
| break; | |
| case SVG_Transform_SkewY_datatype: | |
| gf_mx2d_init(((SVG_Transform *)a->far_ptr)->mat); | |
| gf_mx2d_add_skew_y(&((SVG_Transform *)a->far_ptr)->mat, *(Fixed *)b->far_ptr); | |
| break; | |
| case SVG_Transform_datatype: | |
| gf_mx2d_copy(((SVG_Transform *)a->far_ptr)->mat, ((SVG_Transform *)b->far_ptr)->mat); | |
| break; | |
| default: | |
| GF_LOG(GF_LOG_ERROR, GF_LOG_SCENE, ("[SVG Attributes] forbidden type of transform\n")); | |
| return GF_NOT_SUPPORTED; | |
| } | |
| return GF_OK; | |
| /* Keyword types */ | |
| case SVG_Boolean_datatype: | |
| case SVG_FillRule_datatype: | |
| case SVG_StrokeLineJoin_datatype: | |
| case SVG_StrokeLineCap_datatype: | |
| case SVG_FontStyle_datatype: | |
| case SVG_FontWeight_datatype: | |
| case SVG_FontVariant_datatype: | |
| case SVG_TextAnchor_datatype: | |
| case SVG_Display_datatype: | |
| case SVG_Visibility_datatype: | |
| case SVG_GradientUnit_datatype: | |
| case SVG_PreserveAspectRatio_datatype: | |
| case XML_Space_datatype: | |
| case XMLEV_Propagate_datatype: | |
| case XMLEV_DefaultAction_datatype: | |
| case XMLEV_Phase_datatype: | |
| case SMIL_SyncBehavior_datatype: | |
| case SMIL_AttributeType_datatype: | |
| case SMIL_CalcMode_datatype: | |
| case SMIL_Additive_datatype: | |
| case SMIL_Accumulate_datatype: | |
| case SMIL_Restart_datatype: | |
| case SMIL_Fill_datatype: | |
| case SVG_Overflow_datatype: | |
| case SVG_ZoomAndPan_datatype: | |
| case SVG_DisplayAlign_datatype: | |
| case SVG_TextAlign_datatype: | |
| case SVG_PointerEvents_datatype: | |
| case SVG_RenderingHint_datatype: | |
| case SVG_VectorEffect_datatype: | |
| case SVG_PlaybackOrder_datatype: | |
| case SVG_TimelineBegin_datatype: | |
| case SVG_TransformType_datatype: | |
| case SVG_Focusable_datatype: | |
| case SVG_FocusHighlight_datatype: | |
| *(u8 *)a->far_ptr = *(u8 *)b->far_ptr; | |
| return GF_OK; | |
| case SMIL_SyncTolerance_datatype: | |
| *(SMIL_SyncTolerance*)a->far_ptr = *(SMIL_SyncTolerance*)b->far_ptr; | |
| return GF_OK; | |
| /* Other types */ | |
| case SVG_ID_datatype: | |
| case SVG_LanguageID_datatype: | |
| case SVG_ContentType_datatype: | |
| case DOM_String_datatype: | |
| if (* (SVG_String *)a->far_ptr) gf_free(* (SVG_String *)a->far_ptr); | |
| * (SVG_String *)a->far_ptr = *(SVG_String *)b->far_ptr ? gf_strdup(*(SVG_String *)b->far_ptr) : NULL; | |
| return GF_OK; | |
| case SVG_FontFamily_datatype: | |
| ((SVG_FontFamily *)a->far_ptr)->type = ((SVG_FontFamily *)b->far_ptr)->type; | |
| if ( ((SVG_FontFamily *)a->far_ptr)->value) gf_free( ((SVG_FontFamily *)a->far_ptr)->value ); | |
| ((SVG_FontFamily *)a->far_ptr)->value = (((SVG_FontFamily *)b->far_ptr)->value ? gf_strdup(((SVG_FontFamily *)b->far_ptr)->value) : NULL ); | |
| return GF_OK; | |
| case XMLRI_datatype: | |
| case XML_IDREF_datatype: | |
| ((XMLRI *)a->far_ptr)->type = ((XMLRI *)b->far_ptr)->type; | |
| if (((XMLRI *)a->far_ptr)->string) gf_free(((XMLRI *)a->far_ptr)->string); | |
| if (((XMLRI *)b->far_ptr)->string) { | |
| ((XMLRI *)a->far_ptr)->string = gf_strdup(((XMLRI *)b->far_ptr)->string); | |
| } else { | |
| ((XMLRI *)a->far_ptr)->string = gf_strdup(""); | |
| } | |
| ((XMLRI *)a->far_ptr)->target = ((XMLRI *)b->far_ptr)->target; | |
| if (((XMLRI *)a->far_ptr)->type == XMLRI_ELEMENTID) { | |
| GF_Node *n = (GF_Node *) ((XMLRI *)b->far_ptr)->target; | |
| /*TODO Check if assigning IRI from # scenegraph can happen*/ | |
| if (n) gf_node_register_iri(gf_node_get_graph(n), (XMLRI*)a->far_ptr); | |
| } | |
| return GF_OK; | |
| case SVG_Focus_datatype: | |
| { | |
| ((SVG_Focus *)a->far_ptr)->type = ((SVG_Focus *)b->far_ptr)->type; | |
| if ( ((SVG_Focus *)b->far_ptr)->target.string) { | |
| if ( ((SVG_Focus *)a->far_ptr)->target.string) | |
| gf_free( ((SVG_Focus *)a->far_ptr)->target.string); | |
| ((SVG_Focus *)a->far_ptr)->target.string = gf_strdup( ((SVG_Focus *)b->far_ptr)->target.string); | |
| } | |
| } | |
| return GF_OK; | |
| case SVG_ClipPath_datatype: | |
| if ( ((SVG_ClipPath *)b->far_ptr)->target.string) { | |
| if (((SVG_ClipPath *)a->far_ptr)->target.string) | |
| gf_free(((SVG_ClipPath *)a->far_ptr)->target.string); | |
| ((SVG_ClipPath *)a->far_ptr)->target.string = gf_strdup( ((SVG_ClipPath *)b->far_ptr)->target.string); | |
| } | |
| return GF_OK; | |
| case SMIL_Times_datatype: | |
| { | |
| u32 i, count; | |
| GF_List *dst = *(GF_List **)a->far_ptr; | |
| GF_List *src = *(GF_List **)b->far_ptr; | |
| while (gf_list_count(dst)) { | |
| SMIL_Time *t = gf_list_get(dst, 0); | |
| gf_list_rem(dst, 0); | |
| gf_free(t); | |
| } | |
| count = gf_list_count(src); | |
| for (i=0; i<count; i++) { | |
| SMIL_Time *t2; | |
| SMIL_Time *t = gf_list_get(src, i); | |
| t2 = (SMIL_Time*)gf_malloc(sizeof(SMIL_Time)); | |
| memcpy(t2, t, sizeof(SMIL_Time)); | |
| gf_list_add(dst, t2); | |
| } | |
| } | |
| return GF_OK; | |
| case SMIL_AttributeName_datatype: | |
| { | |
| SMIL_AttributeName *saa = (SMIL_AttributeName *)a->far_ptr; | |
| SMIL_AttributeName *sab = (SMIL_AttributeName *)b->far_ptr; | |
| saa->tag = sab->tag; | |
| saa->type = sab->type; | |
| saa->name = sab->name ? gf_strdup(sab->name) : NULL; | |
| } | |
| break; | |
| case SMIL_Duration_datatype: | |
| { | |
| SMIL_Duration *da = (SMIL_Duration*)a->far_ptr; | |
| SMIL_Duration *db = (SMIL_Duration*)b->far_ptr; | |
| da->type = db->type; | |
| da->clock_value = db->clock_value; | |
| } | |
| break; | |
| case SMIL_AnimateValue_datatype: | |
| { | |
| SMIL_AnimateValue *sa = (SMIL_AnimateValue*)a->far_ptr; | |
| SMIL_AnimateValue *sb = (SMIL_AnimateValue*)b->far_ptr; | |
| sa->type = sb->type; | |
| if (sb->value) { | |
| GF_FieldInfo ava, avb; | |
| sa->value = gf_svg_create_attribute_value(sa->type); | |
| ava.fieldIndex = avb.fieldIndex = 0; | |
| ava.fieldType = avb.fieldType = sb->type; | |
| ava.far_ptr = sa->value; | |
| avb.far_ptr = sb->value; | |
| gf_svg_attributes_copy(&ava, &avb, 0); | |
| } | |
| } | |
| break; | |
| /* Unsupported types */ | |
| case XMLRI_List_datatype: | |
| case DOM_StringList_datatype: | |
| case SVG_GradientOffset_datatype: | |
| case SVG_Clock_datatype: | |
| case SMIL_KeyTimes_datatype: | |
| case SMIL_KeyPoints_datatype: | |
| case SMIL_KeySplines_datatype: | |
| case SMIL_AnimateValues_datatype: | |
| case SMIL_RepeatCount_datatype: | |
| default: | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_SCENE, ("[SVG Attributes] copy of attributes %s of type %s not supported\n", a->name, gf_svg_attribute_type_to_string(a->fieldType))); | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| /* c = a + b */ | |
| GF_Err gf_svg_attributes_add(GF_FieldInfo *a, GF_FieldInfo *b, GF_FieldInfo *c, Bool clamp) | |
| { | |
| return gf_svg_attributes_muladd(FIX_ONE, a, FIX_ONE, b, c, clamp); | |
| } | |
| Bool gf_svg_attribute_is_interpolatable(u32 type) | |
| { | |
| switch (type) { | |
| /* additive types which can really be interpolated */ | |
| case SVG_Color_datatype: | |
| case SVG_Paint_datatype: | |
| case SVG_Number_datatype: | |
| case SVG_Length_datatype: | |
| case SVG_Coordinate_datatype: | |
| case SVG_FontSize_datatype: | |
| case SVG_ViewBox_datatype: | |
| case SVG_Points_datatype: | |
| case SVG_Numbers_datatype: | |
| case SVG_Coordinates_datatype: | |
| case SVG_PathData_datatype: | |
| case SVG_Motion_datatype: | |
| case SVG_Transform_datatype: | |
| case SVG_Transform_Translate_datatype: | |
| case SVG_Transform_Scale_datatype: | |
| case SVG_Transform_Rotate_datatype: | |
| case SVG_Transform_SkewX_datatype: | |
| case SVG_Transform_SkewY_datatype: | |
| case SVG_StrokeDashArray_datatype: | |
| case LASeR_Size_datatype: | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| GF_Err gf_svg_attributes_interpolate(GF_FieldInfo *a, GF_FieldInfo *b, GF_FieldInfo *c, Fixed coef, Bool clamp) | |
| { | |
| if (!a->far_ptr || !b->far_ptr || !c->far_ptr) return GF_BAD_PARAM; | |
| c->fieldType = a->fieldType; | |
| #ifdef GPAC_ENABLE_COVERAGE | |
| if (gf_sys_is_cov_mode()) { | |
| gf_svg_attributes_equal(a, b); | |
| } | |
| #endif | |
| switch (a->fieldType) { | |
| /* additive types which can really be interpolated */ | |
| case SVG_Color_datatype: | |
| case SVG_Paint_datatype: | |
| case SVG_Number_datatype: | |
| case SVG_Length_datatype: | |
| case SVG_Coordinate_datatype: | |
| case SVG_FontSize_datatype: | |
| case SVG_ViewBox_datatype: | |
| case SVG_Points_datatype: | |
| case SVG_Numbers_datatype: | |
| case SVG_Coordinates_datatype: | |
| case SVG_PathData_datatype: | |
| case SVG_Motion_datatype: | |
| case SVG_Transform_datatype: | |
| case SVG_Transform_Translate_datatype: | |
| case SVG_Transform_Scale_datatype: | |
| case SVG_Transform_Rotate_datatype: | |
| case SVG_Transform_SkewX_datatype: | |
| case SVG_Transform_SkewY_datatype: | |
| case LASeR_Size_datatype: | |
| case SVG_StrokeDashArray_datatype: | |
| return gf_svg_attributes_muladd(FIX_ONE-coef, a, coef, b, c, clamp); | |
| /* discrete types: interpolation is the selection of one of the 2 values | |
| using the coeff and a the 0.5 threshold */ | |
| /* Keyword types */ | |
| case SVG_Boolean_datatype: | |
| case SVG_FillRule_datatype: | |
| case SVG_StrokeLineJoin_datatype: | |
| case SVG_StrokeLineCap_datatype: | |
| case SVG_FontStyle_datatype: | |
| case SVG_FontWeight_datatype: | |
| case SVG_FontVariant_datatype: | |
| case SVG_TextAnchor_datatype: | |
| case SVG_Display_datatype: | |
| case SVG_Visibility_datatype: | |
| case SVG_GradientUnit_datatype: | |
| case SVG_PreserveAspectRatio_datatype: | |
| case SVG_TransformType_datatype: | |
| case XML_Space_datatype: | |
| case XMLEV_Propagate_datatype: | |
| case XMLEV_DefaultAction_datatype: | |
| case XMLEV_Phase_datatype: | |
| case SMIL_SyncBehavior_datatype: | |
| case SMIL_SyncTolerance_datatype: | |
| case SMIL_AttributeType_datatype: | |
| case SMIL_CalcMode_datatype: | |
| case SMIL_Additive_datatype: | |
| case SMIL_Accumulate_datatype: | |
| case SMIL_Restart_datatype: | |
| case SMIL_Fill_datatype: | |
| case SVG_Overflow_datatype: | |
| case SVG_ZoomAndPan_datatype: | |
| case SVG_DisplayAlign_datatype: | |
| case SVG_TextAlign_datatype: | |
| case SVG_PointerEvents_datatype: | |
| case SVG_RenderingHint_datatype: | |
| case SVG_VectorEffect_datatype: | |
| case SVG_PlaybackOrder_datatype: | |
| case SVG_TimelineBegin_datatype: | |
| /* Other non keyword types but which can still be discretely interpolated */ | |
| case DOM_String_datatype: | |
| case SVG_ContentType_datatype: | |
| case SVG_LanguageID_datatype: | |
| case SVG_FontFamily_datatype: | |
| case XMLRI_datatype: | |
| case XMLRI_List_datatype: | |
| case DOM_StringList_datatype: | |
| case SVG_Clock_datatype: | |
| case SVG_ID_datatype: | |
| case SVG_GradientOffset_datatype: | |
| case LASeR_Choice_datatype: | |
| if (coef < FIX_ONE/2) { | |
| gf_svg_attributes_copy(c, a, clamp); | |
| } else { | |
| gf_svg_attributes_copy(c, b, clamp); | |
| } | |
| return GF_OK; | |
| /* Unsupported types */ | |
| case SMIL_KeyTimes_datatype: | |
| case SMIL_KeyPoints_datatype: | |
| case SMIL_KeySplines_datatype: | |
| case SMIL_AnimateValue_datatype: | |
| case SMIL_AnimateValues_datatype: | |
| case SMIL_AttributeName_datatype: | |
| case SMIL_Times_datatype: | |
| case SMIL_Duration_datatype: | |
| case SMIL_RepeatCount_datatype: | |
| default: | |
| GF_LOG(GF_LOG_WARNING, GF_LOG_SCENE, ("[SVG Attributes] interpolation for attributes %s of type %s not supported\n", a->name, gf_svg_attribute_type_to_string(a->fieldType))); | |
| return GF_OK; | |
| } | |
| return GF_OK; | |
| } | |
| Bool gf_svg_is_current_color(GF_FieldInfo *a) | |
| { | |
| switch (a->fieldType) { | |
| case SVG_Color_datatype: | |
| return (((SVG_Color *)a->far_ptr)->type == SVG_COLOR_CURRENTCOLOR); | |
| break; | |
| case SVG_Paint_datatype: | |
| if ( ((SVG_Paint *)a->far_ptr)->type == SVG_PAINT_COLOR) { | |
| return (((SVG_Paint *)a->far_ptr)->color.type == SVG_COLOR_CURRENTCOLOR); | |
| } else { | |
| return 0; | |
| } | |
| break; | |
| } | |
| return 0; | |
| } | |
| const char *gf_svg_attribute_type_to_string(u32 att_type) | |
| { | |
| switch (att_type) { | |
| case SVG_FillRule_datatype: | |
| return "FillRule"; | |
| case SVG_StrokeLineJoin_datatype: | |
| return "StrokeLineJoin"; | |
| case SVG_StrokeLineCap_datatype: | |
| return "StrokeLineCap"; | |
| case SVG_FontStyle_datatype: | |
| return "FontStyle"; | |
| case SVG_FontWeight_datatype: | |
| return "FontWeight"; | |
| case SVG_FontVariant_datatype: | |
| return "FontVariant"; | |
| case SVG_TextAnchor_datatype: | |
| return "TextAnchor"; | |
| case SVG_TransformType_datatype: | |
| return "TransformType"; | |
| case SVG_Display_datatype: | |
| return "Display"; | |
| case SVG_Visibility_datatype: | |
| return "Visibility"; | |
| case SVG_Overflow_datatype: | |
| return "Overflow"; | |
| case SVG_ZoomAndPan_datatype: | |
| return "ZoomAndPan"; | |
| case SVG_DisplayAlign_datatype: | |
| return "DisplayAlign"; | |
| case SVG_PointerEvents_datatype: | |
| return "PointerEvents"; | |
| case SVG_RenderingHint_datatype: | |
| return "RenderingHint"; | |
| case SVG_VectorEffect_datatype: | |
| return "VectorEffect"; | |
| case SVG_PlaybackOrder_datatype: | |
| return "PlaybackOrder"; | |
| case SVG_TimelineBegin_datatype: | |
| return "TimelineBegin"; | |
| case XML_Space_datatype: | |
| return "XML_Space"; | |
| case XMLEV_Propagate_datatype: | |
| return "XMLEV_Propagate"; | |
| case XMLEV_DefaultAction_datatype: | |
| return "XMLEV_DefaultAction"; | |
| case XMLEV_Phase_datatype: | |
| return "XMLEV_Phase"; | |
| case SMIL_SyncBehavior_datatype: | |
| return "SMIL_SyncBehavior"; | |
| case SMIL_SyncTolerance_datatype: | |
| return "SMIL_SyncTolerance"; | |
| case SMIL_AttributeType_datatype: | |
| return "SMIL_AttributeType"; | |
| case SMIL_CalcMode_datatype: | |
| return "SMIL_CalcMode"; | |
| case SMIL_Additive_datatype: | |
| return "SMIL_Additive"; | |
| case SMIL_Accumulate_datatype: | |
| return "SMIL_Accumulate"; | |
| case SMIL_Restart_datatype: | |
| return "SMIL_Restart"; | |
| case SMIL_Fill_datatype: | |
| return "SMIL_Fill"; | |
| case SVG_GradientUnit_datatype: | |
| return "GradientUnit"; | |
| case SVG_InitialVisibility_datatype: | |
| return "InitialVisibility"; | |
| case SVG_FocusHighlight_datatype: | |
| return "FocusHighlight"; | |
| case SVG_Overlay_datatype: | |
| return "Overlay"; | |
| case SVG_TransformBehavior_datatype: | |
| return "TransformBehavior"; | |
| case SVG_SpreadMethod_datatype: | |
| return "SpreadMethod"; | |
| case SVG_TextAlign_datatype: | |
| return "TextAlign"; | |
| case SVG_Number_datatype: | |
| return "Number"; | |
| case SVG_FontSize_datatype: | |
| return "FontSize"; | |
| case SVG_Length_datatype: | |
| return "Length"; | |
| case SVG_Coordinate_datatype: | |
| return "Coordinate"; | |
| case SVG_Rotate_datatype: | |
| return "Rotate"; | |
| case SVG_Numbers_datatype: | |
| return "Numbers"; | |
| case SVG_Points_datatype: | |
| return "Points"; | |
| case SVG_Coordinates_datatype: | |
| return "Coordinates"; | |
| case DOM_StringList_datatype: | |
| return "StringList"; | |
| case XMLRI_List_datatype: | |
| return "ListOfIRI"; | |
| case SMIL_KeyTimes_datatype: | |
| return "SMIL_KeyTimes"; | |
| case SMIL_KeySplines_datatype: | |
| return "SMIL_KeySplines"; | |
| case SMIL_KeyPoints_datatype: | |
| return "SMIL_KeyPoints"; | |
| case SMIL_Times_datatype: | |
| return "SMIL_Times"; | |
| case SMIL_AnimateValue_datatype: | |
| return "SMIL_AnimateValue"; | |
| case SMIL_AnimateValues_datatype: | |
| return "SMIL_AnimateValues"; | |
| case SMIL_Duration_datatype: | |
| return "SMIL_Duration"; | |
| case SMIL_RepeatCount_datatype: | |
| return "SMIL_RepeatCount"; | |
| case SMIL_AttributeName_datatype: | |
| return "SMIL_AttributeName"; | |
| case SVG_Boolean_datatype: | |
| return "Boolean"; | |
| case SVG_Color_datatype: | |
| return "Color"; | |
| case SVG_Paint_datatype: | |
| return "Paint"; | |
| case SVG_PathData_datatype: | |
| return "PathData"; | |
| case SVG_FontFamily_datatype: | |
| return "FontFamily"; | |
| case SVG_ID_datatype: | |
| return "ID"; | |
| case XMLRI_datatype: | |
| return "IRI"; | |
| case XML_IDREF_datatype: | |
| return "IDREF"; | |
| case SVG_StrokeDashArray_datatype: | |
| return "StrokeDashArray"; | |
| case SVG_PreserveAspectRatio_datatype: | |
| return "PreserveAspectRatio"; | |
| case SVG_ViewBox_datatype: | |
| return "ViewBox"; | |
| case SVG_GradientOffset_datatype: | |
| return "GradientOffset"; | |
| case SVG_Focus_datatype : | |
| return "Focus"; | |
| case SVG_ClipPath_datatype : | |
| return "ClipPath"; | |
| case SVG_Clock_datatype : | |
| return "Clock"; | |
| case DOM_String_datatype : | |
| return "String"; | |
| case SVG_ContentType_datatype: | |
| return "ContentType"; | |
| case SVG_LanguageID_datatype: | |
| return "LanguageID"; | |
| case XMLEV_Event_datatype: | |
| return "XMLEV_Event"; | |
| case SVG_Motion_datatype: | |
| return "Motion"; | |
| case SVG_Transform_datatype: | |
| return "Transform"; | |
| case SVG_Transform_Translate_datatype: | |
| return "Translate"; | |
| case SVG_Transform_Scale_datatype: | |
| return "Scale"; | |
| case SVG_Transform_SkewX_datatype: | |
| return "SkewX"; | |
| case SVG_Transform_SkewY_datatype: | |
| return "SkewY"; | |
| case SVG_Transform_Rotate_datatype: | |
| return "Rotate"; | |
| case LASeR_Choice_datatype: | |
| return "LASeR_Choice"; | |
| case LASeR_Size_datatype: | |
| return "LASeR_Size"; | |
| default: | |
| return "UnknownType"; | |
| } | |
| } | |
| #endif /*GPAC_DISABLE_SVG*/ |