├── .clang-format ├── .clang-tidy ├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── .vscode ├── launch.json └── tasks.json ├── LICENSE ├── README.adoc ├── android ├── .gitignore ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── res │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle ├── svgdom-$(version).pom.in └── svgdom │ ├── .gitignore │ ├── CMakeLists.txt │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ └── main │ ├── AndroidManifest.xml │ └── res │ └── values │ └── strings.xml ├── archlinux └── PKGBUILD ├── build ├── cmake │ └── CMakeLists.txt └── vcpkg │ ├── portfile.cmake.in │ ├── test │ ├── CMakeLists.txt │ ├── main.cpp │ ├── vcpkg-configuration.json │ └── vcpkg.json │ ├── usage │ └── vcpkg.json.in ├── cocoapods └── svgdom.podspec.in ├── conan ├── conanfile.py └── test_package │ ├── CMakeLists.txt │ ├── conanfile.py │ └── example.cpp ├── config ├── asan.mk ├── base │ └── base.mk ├── dbg.mk ├── default.mk ├── emsc.mk ├── gcov.mk └── rel.mk ├── debian ├── changelog ├── compat ├── control.in ├── libsvgdom$(soname)-dbgsrc.install.in ├── libsvgdom-dev.install ├── libsvgdom-doc.install ├── libsvgdom.install.in ├── rules └── source │ └── format ├── doc ├── doxygen.cfg.in └── makefile ├── emscripten └── conan.profile ├── homebrew └── libsvgdom.rb.in ├── makefile ├── msvs_solution ├── libsvgdom │ ├── libsvgdom.vcxproj │ ├── libsvgdom.vcxproj.filters │ ├── libsvgdom.vcxproj.user │ └── packages.config ├── msvs_solution.sln └── test_dom │ ├── packages.config │ ├── test_dom.vcxproj │ ├── test_dom.vcxproj.filters │ └── test_dom.vcxproj.user ├── msys2 └── PKGBUILD.in ├── nuget ├── build_nuget.ps1 └── nuget.autopkg.in ├── pkg-config ├── makefile └── svgdom.pc.in ├── src ├── .clang-tidy ├── makefile ├── soname.txt └── svgdom │ ├── config.hpp │ ├── dom.cpp │ ├── dom.hpp │ ├── elements │ ├── aspect_ratioed.cpp │ ├── aspect_ratioed.hpp │ ├── container.hpp │ ├── coordinate_units.hpp │ ├── element.cpp │ ├── element.hpp │ ├── filter.cpp │ ├── filter.hpp │ ├── gradients.cpp │ ├── gradients.hpp │ ├── image_element.cpp │ ├── image_element.hpp │ ├── rectangle.cpp │ ├── rectangle.hpp │ ├── referencing.cpp │ ├── referencing.hpp │ ├── shapes.cpp │ ├── shapes.hpp │ ├── structurals.cpp │ ├── structurals.hpp │ ├── style.cpp │ ├── style.hpp │ ├── styleable.cpp │ ├── styleable.hpp │ ├── text_element.cpp │ ├── text_element.hpp │ ├── transformable.cpp │ ├── transformable.hpp │ ├── view_boxed.cpp │ └── view_boxed.hpp │ ├── length.cpp │ ├── length.hpp │ ├── malformed_svg_error.hpp │ ├── parser.cpp │ ├── parser.hxx │ ├── util.cpp │ ├── util.hxx │ ├── util │ ├── casters.hpp │ ├── cloner.cpp │ ├── cloner.hpp │ ├── finder_by_class.cpp │ ├── finder_by_class.hpp │ ├── finder_by_id.cpp │ ├── finder_by_id.hpp │ ├── finder_by_tag.cpp │ ├── finder_by_tag.hpp │ ├── stream_writer.cpp │ ├── stream_writer.hpp │ ├── style_stack.cpp │ ├── style_stack.hpp │ ├── style_stack_cache.cpp │ └── style_stack_cache.hpp │ ├── visitor.cpp │ └── visitor.hpp ├── tests ├── .clang-tidy ├── makefile └── unit │ ├── cloner.cpp │ ├── custom_element.cpp │ ├── edit_dom_visitor.cpp │ ├── finders.cpp │ ├── makefile │ ├── misc.cpp │ ├── performance.cpp │ ├── samples.cpp │ ├── samples_data │ ├── back.svg │ ├── back.svg.cmp │ ├── background_test.svg │ ├── background_test.svg.cmp │ ├── camera.svg │ ├── camera.svg.cmp │ ├── car.svg │ ├── car.svg.cmp │ ├── cubic_smooth.svg │ ├── cubic_smooth.svg.cmp │ ├── dasharray1.svg │ ├── dasharray1.svg.cmp │ ├── dashoffset1.svg │ ├── dashoffset1.svg.cmp │ ├── defs_style_2.svg │ ├── defs_style_2.svg.cmp │ ├── finders.svg │ ├── finders.svg.cmp │ ├── gauge_arrow_shadow.svg │ ├── gauge_arrow_shadow.svg.cmp │ ├── gradient-transform-rotate-compare.svg │ ├── gradient-transform-rotate-compare.svg.cmp │ ├── interface-ethernet.svg │ ├── interface-ethernet.svg.cmp │ ├── masking.svg │ ├── masking.svg.cmp │ ├── mouse.svg │ ├── mouse.svg.cmp │ ├── rect_no_width_height.svg │ ├── rect_no_width_height.svg.cmp │ ├── rgb_percent.svg │ ├── rgb_percent.svg.cmp │ ├── sample4.svg │ ├── sample4.svg.cmp │ ├── simple_css.svg │ ├── simple_css.svg.cmp │ ├── six_ball.svg │ ├── six_ball.svg.cmp │ ├── symbol.svg │ ├── symbol.svg.cmp │ ├── test2.svg │ ├── test2.svg.cmp │ ├── text.svg │ ├── text.svg.cmp │ ├── tiger.svg │ ├── tiger.svg.cmp │ ├── use.svg │ └── use.svg.cmp │ ├── style_stack.cpp │ ├── style_stack_cache.cpp │ └── to_string.cpp ├── wiki └── Main.adoc └── xcode ├── Podfile └── svgdom ├── svgdom.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── ivan.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── ivan.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist └── svgdom └── Info.plist /.clang-format: -------------------------------------------------------------------------------- 1 | tool-configs/clang-format/.clang-format -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | tool-configs/clang-tidy/.clang-tidy -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # disable line endings conversion for all files 2 | * -text 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [igagis] 4 | patreon: igagis 5 | custom: ["https://paypal.me/igagis"] 6 | # open_collective: # Replace with a single Open Collective username 7 | # ko_fi: # Replace with a single Ko-fi username 8 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 9 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 10 | # liberapay: # Replace with a single Liberapay username 11 | # issuehunt: # Replace with a single IssueHunt username 12 | # otechie: # Replace with a single Otechie username 13 | # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/out/* 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tool-configs"] 2 | path = tool-configs 3 | url = ../../cppfw/tool-configs 4 | branch = main 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "debug unit", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/tests/unit/out/dbg/tests", 12 | "args": ["--suite=samples", "--test=sample[16]"], 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceFolder}/tests/unit/", 15 | "environment": [{"name": "LD_LIBRARY_PATH", "value":"${workspaceFolder}/src/out/dbg"}], 16 | "externalConsole": false, 17 | "MIMode": "gdb", 18 | "setupCommands": [ 19 | { 20 | "description": "Enable pretty-printing for gdb", 21 | "text": "-enable-pretty-printing", 22 | "ignoreFailures": true 23 | } 24 | ], 25 | "preLaunchTask": "build_dbg" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "build", 8 | "type": "shell", 9 | "command": "make", 10 | "problemMatcher": [ 11 | "$gcc" 12 | ], 13 | "group": "build" 14 | }, 15 | { 16 | "label": "build_dbg", 17 | "type": "shell", 18 | "command": "make config=dbg", 19 | "problemMatcher": [ 20 | "$gcc" 21 | ], 22 | "group": "build" 23 | }, 24 | { 25 | "label": "clean-all", 26 | "type": "shell", 27 | "command": "make clean-all", 28 | "problemMatcher": [], 29 | "group": "build" 30 | }, 31 | { 32 | "label": "clean", 33 | "type": "shell", 34 | "command": "make clean", 35 | "problemMatcher": [], 36 | "group": "build" 37 | }, 38 | { 39 | "label": "clean_dbg", 40 | "type": "shell", 41 | "command": "make clean config=dbg", 42 | "problemMatcher": [], 43 | "group": "build" 44 | }, 45 | { 46 | "label": "test", 47 | "type": "shell", 48 | "command": "make test", 49 | "problemMatcher": [], 50 | "dependsOn": "build", 51 | "group": "build" 52 | }, 53 | { 54 | "label": "test_dbg", 55 | "type": "shell", 56 | "command": "make test config=dbg", 57 | "problemMatcher": [], 58 | "dependsOn": "build_dbg", 59 | "group": "build" 60 | }, 61 | { 62 | "label": "test_", 63 | "type": "shell", 64 | "command": "make test", 65 | "problemMatcher": [], 66 | "dependsOn": "build", 67 | "group": "build" 68 | }, 69 | { 70 | "label": "test_style_stack_dbg", 71 | "type": "shell", 72 | "command": "make -C tests/style_stack test config=dbg", 73 | "problemMatcher": [], 74 | "dependsOn": "build_dbg", 75 | "group": "build" 76 | }, 77 | { 78 | "label": "test_unit_dbg", 79 | "type": "shell", 80 | "command": "make -C tests/unit test config=dbg", 81 | "problemMatcher": [], 82 | "dependsOn": "build_dbg", 83 | "group": "build" 84 | }, 85 | { 86 | "label": "test_unit", 87 | "type": "shell", 88 | "command": "make -C tests/unit test", 89 | "problemMatcher": [], 90 | "dependsOn": "build", 91 | "group": "build" 92 | }, 93 | { 94 | "label": "format", 95 | "type": "shell", 96 | "command": "make apply-format", 97 | "problemMatcher": [], 98 | "group": "build" 99 | } 100 | ] 101 | } 102 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2025 Ivan Gagis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | :name: svgdom 2 | 3 | = {name} 4 | 5 | |==== 6 | | link:https://github.com/cppfw/{name}/releases[image:https://img.shields.io/github/tag/cppfw/{name}.svg[releases]] | link:https://github.com/cppfw/{name}/actions[image:https://github.com/cppfw/{name}/workflows/ci/badge.svg[ci status]] | link:https://codecov.io/gh/cppfw/{name}[image:https://codecov.io/gh/cppfw/{name}/branch/main/graph/badge.svg?token=LKA3SRSkc3[codecov.io]] 7 | |==== 8 | 9 | SVG document object model library in C++. 10 | 11 | = Installation 12 | 13 | Please, see link:wiki/Main.adoc[WiKi] for installation instructions. 14 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | defaultConfig { 6 | applicationId "io.github.cppfw.svgdom_tests" 7 | minSdkVersion 21 8 | targetSdkVersion 29 9 | 10 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 11 | 12 | externalNativeBuild { 13 | cmake { 14 | targets "mordavokneapp" 15 | 16 | arguments "-DANDROID_STL=c++_shared", "-DANDROID_TOOLCHAIN=clang" 17 | } 18 | } 19 | } 20 | 21 | buildTypes { 22 | release { 23 | minifyEnabled false 24 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 25 | } 26 | } 27 | 28 | // Encapsulates your external native build configurations. 29 | externalNativeBuild { 30 | 31 | // Encapsulates your CMake build configurations. 32 | cmake { 33 | // Provides a relative path to your CMake build script. 34 | // path "CMakeLists.txt" 35 | } 36 | } 37 | } 38 | 39 | repositories { 40 | maven { 41 | url 'http://gagis.hopto.org/nexus/repository/android/' 42 | allowInsecureProtocol = true 43 | } 44 | } 45 | dependencies { 46 | // implementation project(path: ':svgdom', configuration: 'default') 47 | } 48 | 49 | 50 | task copyResToAssets { 51 | doLast { 52 | copy{ 53 | from "../../tests/app/res" 54 | into "src/main/assets/res" 55 | include "**/*" 56 | } 57 | } 58 | } 59 | tasks.whenTaskAdded { task -> 60 | if (task.name.startsWith('package')) { 61 | task.dependsOn('copyResToAssets') 62 | } 63 | } 64 | 65 | 66 | 67 | 68 | //=================================== 69 | //=== Extract NDK files from AARs === 70 | 71 | // This is needed to be able to write "configurations.implementation.each" below. 72 | configurations.implementation.setCanBeResolved(true) 73 | 74 | task extractNDKLibs { 75 | doLast { 76 | configurations.implementation.each { 77 | def file = it.absoluteFile 78 | copy { 79 | from zipTree(file) 80 | into "build/" 81 | include "ndkLibs/**/*" 82 | } 83 | } 84 | } 85 | } 86 | 87 | tasks.whenTaskAdded { task -> 88 | logger.info('task added') 89 | if (task.name.startsWith('externalNativeBuild')) { 90 | task.dependsOn extractNDKLibs 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\ivan.gagis\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgdom/86a25a04f6fac1949c09d3a0ecfe871a9859a555/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgdom/86a25a04f6fac1949c09d3a0ecfe871a9859a555/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgdom/86a25a04f6fac1949c09d3a0ecfe871a9859a555/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgdom/86a25a04f6fac1949c09d3a0ecfe871a9859a555/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgdom/86a25a04f6fac1949c09d3a0ecfe871a9859a555/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgdom/86a25a04f6fac1949c09d3a0ecfe871a9859a555/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgdom/86a25a04f6fac1949c09d3a0ecfe871a9859a555/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgdom/86a25a04f6fac1949c09d3a0ecfe871a9859a555/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgdom/86a25a04f6fac1949c09d3a0ecfe871a9859a555/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgdom/86a25a04f6fac1949c09d3a0ecfe871a9859a555/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | svgdomtests 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | google() 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.4.0' 10 | classpath 'io.github.howardpang:androidNativeBundle:1.1.3' 11 | 12 | // NOTE: Do not place your application dependencies here; they belong 13 | // in the individual module build.gradle files 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | google() 20 | mavenCentral() 21 | } 22 | } 23 | 24 | task clean(type: Delete) { 25 | delete rootProject.buildDir 26 | } 27 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgdom/86a25a04f6fac1949c09d3a0ecfe871a9859a555/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Mar 26 13:38:03 EET 2025 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':svgdom' 2 | -------------------------------------------------------------------------------- /android/svgdom-$(version).pom.in: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | io.github.cppfw 6 | svgdom 7 | $(version) 8 | aar 9 | 10 | 11 | io.github.cppfw 12 | utki 13 | [1.1.150,) 14 | aar 15 | compile 16 | 17 | 18 | io.github.cppfw 19 | papki 20 | [1.0.93,) 21 | aar 22 | compile 23 | 24 | 25 | io.github.cppfw 26 | mikroxml 27 | [0.1.36,) 28 | aar 29 | compile 30 | 31 | 32 | io.github.cppfw 33 | cssom 34 | [0.1.19,) 35 | aar 36 | compile 37 | 38 | 39 | io.github.cppfw 40 | r4 41 | [1.0.53,) 42 | aar 43 | compile 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /android/svgdom/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /android/svgdom/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Sets the minimum version of CMake required to build your native library. 2 | # This ensures that a certain set of CMake features is available to 3 | # your build. 4 | 5 | cmake_minimum_required(VERSION 3.4.1) 6 | 7 | # Specifies a library name, specifies whether the library is STATIC or 8 | # SHARED, and provides relative paths to the source code. You can 9 | # define multiple libraries by adding multiple add_library() commands, 10 | # and CMake builds them for you. When you build your app, Gradle 11 | # automatically packages shared libraries with your APK. 12 | 13 | set(name svgdom) 14 | 15 | file(GLOB_RECURSE srcs "../../src/*.cpp") 16 | 17 | include (${ANDROID_GRADLE_NATIVE_BUNDLE_PLUGIN_MK}) 18 | 19 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") 20 | 21 | add_library( 22 | # Specifies the name of the library. 23 | ${name} 24 | 25 | # Sets the library as a shared library. 26 | STATIC 27 | 28 | # Provides a relative path to your source file(s). 29 | ${srcs} 30 | ) 31 | 32 | target_link_libraries( 33 | ${name} 34 | android log ${ANDROID_GRADLE_NATIVE_MODULES} 35 | ) 36 | -------------------------------------------------------------------------------- /android/svgdom/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.ydq.android.gradle.native-aar.export' // must go after android gradle plugin 3 | apply plugin: 'com.ydq.android.gradle.native-aar.import' // must go after android gradle plugin 4 | 5 | android { 6 | compileSdkVersion 29 7 | 8 | defaultConfig { 9 | minSdkVersion 21 10 | targetSdkVersion 29 11 | 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | 14 | externalNativeBuild { 15 | cmake { 16 | targets "svgdom" 17 | } 18 | } 19 | } 20 | 21 | nativeBundleExport { 22 | headerDir = "${project.projectDir}/../../src/" 23 | bundleStatic = true 24 | includeHeaderFilter.add("**/*.hpp") 25 | } 26 | 27 | buildTypes { 28 | release { 29 | minifyEnabled false 30 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 31 | } 32 | debug {} 33 | } 34 | 35 | // Encapsulates your external native build configurations. 36 | externalNativeBuild { 37 | // Encapsulates your CMake build configurations. 38 | cmake { 39 | // Provides a relative path to your CMake build script. 40 | path "CMakeLists.txt" 41 | } 42 | } 43 | } 44 | 45 | repositories { 46 | maven { 47 | url 'http://gagis.hopto.org/nexus/repository/android/' 48 | allowInsecureProtocol = true 49 | } 50 | } 51 | dependencies { 52 | implementation 'io.github.cppfw:utki:+' 53 | implementation 'io.github.cppfw:papki:+' 54 | implementation 'io.github.cppfw:mikroxml:+' 55 | implementation 'io.github.cppfw:cssom:+' 56 | implementation 'io.github.cppfw:r4:+' 57 | } 58 | 59 | // copy and rename release AAR to unified name 60 | task copy_aar(type: Copy) { 61 | from file("build/outputs/aar/") 62 | into file("../") 63 | include("*-static-release.aar") 64 | rename { String fileName -> 65 | fileName.replace("static-release.aar", "\$(version).aar.in") 66 | } 67 | } 68 | 69 | afterEvaluate { 70 | copy_aar.dependsOn(assembleRelease) 71 | copy_aar.dependsOn(bundleStaticLibRelease) 72 | } 73 | -------------------------------------------------------------------------------- /android/svgdom/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\ivan.gagis\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /android/svgdom/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/svgdom/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /archlinux/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Ivan Gagis 2 | 3 | pkgname=svgdom 4 | pkgver=$PACKAGE_VERSION 5 | pkgrel=1 6 | arch=('x86_64' 'armv7h' 'aarch64') 7 | epoch= 8 | pkgdesc="SVG DOM library in C++" 9 | url="http://github.com/cppfw/${pkgname}" 10 | license=('MIT') 11 | groups=() 12 | 13 | depends=( 14 | "utki" 15 | "mikroxml" 16 | "cssom" 17 | "r4" 18 | ) 19 | 20 | makedepends=( 21 | 'myci' 22 | 'prorab' 23 | 'prorab-extra' 24 | 'doxygen' 25 | "tst" 26 | "clang" # for clang-tidy and clang-format 27 | ) 28 | checkdepends=('myci') 29 | optdepends=() 30 | provides=() 31 | conflicts=() 32 | replaces=() 33 | backup=() 34 | options=() 35 | install= 36 | changelog= 37 | source=() # do not download any sources 38 | noextract=() 39 | md5sums=() 40 | validpgpkeys=() 41 | 42 | rootDir=$(pwd)/.. # project root directory 43 | 44 | prepare() { 45 | cd "$rootDir" 46 | } 47 | 48 | build() { 49 | cd "$rootDir" 50 | # TODO: turn on lint when arch adopts more modern clang-tidy 51 | make lint=off 52 | } 53 | 54 | check() { 55 | cd "$rootDir" 56 | make test 57 | } 58 | 59 | package() { 60 | cd "$rootDir" 61 | make DESTDIR="$pkgdir" PREFIX=/usr install 62 | } 63 | -------------------------------------------------------------------------------- /build/cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | set(name svgdom) 4 | project(${name}) 5 | 6 | # !!! find_package must go after project() declaration !!! 7 | # Otherwise VCPKG does not set the CMAKE_PREFIX_PATH to find packages. 8 | find_package(myci CONFIG REQUIRED) 9 | 10 | find_package(ZLIB REQUIRED) 11 | 12 | set(srcs) 13 | myci_add_source_files(srcs 14 | DIRECTORY 15 | ../../src/${name} 16 | RECURSIVE 17 | ) 18 | 19 | myci_declare_library(${name} 20 | SOURCES 21 | ${srcs} 22 | PUBLIC_INCLUDE_DIRECTORIES 23 | ../../src 24 | INSTALL_INCLUDE_DIRECTORIES 25 | ../../src/${name} 26 | DEPENDENCIES 27 | utki 28 | papki 29 | r4 30 | mikroxml 31 | cssom 32 | EXTERNAL_DEPENDENCIES 33 | ZLIB::ZLIB 34 | ) 35 | -------------------------------------------------------------------------------- /build/vcpkg/portfile.cmake.in: -------------------------------------------------------------------------------- 1 | vcpkg_check_linkage(ONLY_STATIC_LIBRARY) 2 | 3 | vcpkg_from_github( 4 | OUT_SOURCE_PATH SOURCE_PATH 5 | REPO cppfw/${PORT} 6 | REF $(git_ref) 7 | SHA512 $(archive_hash) 8 | HEAD_REF main 9 | ) 10 | 11 | vcpkg_cmake_configure( 12 | SOURCE_PATH "${SOURCE_PATH}/build/cmake" 13 | ) 14 | 15 | vcpkg_cmake_install() 16 | 17 | vcpkg_cmake_config_fixup() 18 | 19 | # Delete the include directory from the debug installation to prevent overlap. 20 | file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") 21 | 22 | # Install the LICENSE file to the package's share directory and rename it to copyright. 23 | file(INSTALL "${SOURCE_PATH}/LICENSE" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) 24 | 25 | # Copy the usage instruction file to the package's share directory. 26 | configure_file("${CMAKE_CURRENT_LIST_DIR}/usage" "${CURRENT_PACKAGES_DIR}/share/${PORT}/usage" COPYONLY) 27 | -------------------------------------------------------------------------------- /build/vcpkg/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(CMAKE_TOOLCHAIN_FILE $ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake) 4 | 5 | project(test) 6 | 7 | find_package(utki CONFIG REQUIRED) 8 | find_package(ZLIB REQUIRED) 9 | find_package(papki CONFIG REQUIRED) 10 | find_package(cssom CONFIG REQUIRED) 11 | find_package(mikroxml CONFIG REQUIRED) 12 | find_package(r4 CONFIG REQUIRED) 13 | find_package(svgdom CONFIG REQUIRED) 14 | 15 | add_executable(test main.cpp) 16 | 17 | target_link_libraries(test PRIVATE svgdom::svgdom) 18 | -------------------------------------------------------------------------------- /build/vcpkg/test/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std::string_view_literals; 4 | 5 | int main(int argc, const char** argv){ 6 | auto dom = svgdom::load(R"qwertyuiop( 7 | 8 | 9 | 10 | 11 | )qwertyuiop"sv); 12 | 13 | std::cout << "dom->get_dimensions(96) = " << dom->get_dimensions(96) << std::endl; 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /build/vcpkg/test/vcpkg-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "default-registry": { 3 | "kind": "git", 4 | "baseline": "5e5d0e1cd7785623065e77eff011afdeec1a3574", 5 | "repository": "https://github.com/microsoft/vcpkg" 6 | }, 7 | "registries": [ 8 | { 9 | "kind": "git", 10 | "repository": "https://github.com/cppfw/vcpkg-repo/", 11 | "baseline": "c7ff7bc78fe617434cc09c52b5eb111d568197c1", 12 | "reference": "main", 13 | "packages": [ "myci", "utki", "papki", "mikroxml", "cssom", "r4" ] 14 | } 15 | ], 16 | "overlay-ports": [ 17 | "../overlay" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /build/vcpkg/test/vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | "svgdom" 4 | ] 5 | } -------------------------------------------------------------------------------- /build/vcpkg/usage: -------------------------------------------------------------------------------- 1 | svgdom provides CMake targets: 2 | 3 | find_package(utki CONFIG REQUIRED) 4 | find_package(ZLIB REQUIRED) 5 | find_package(papki CONFIG REQUIRED) 6 | find_package(cssom CONFIG REQUIRED) 7 | find_package(mikroxml CONFIG REQUIRED) 8 | find_package(r4 CONFIG REQUIRED) 9 | find_package(svgdom CONFIG REQUIRED) 10 | 11 | target_link_libraries(main PRIVATE svgdom::svgdom) 12 | -------------------------------------------------------------------------------- /build/vcpkg/vcpkg.json.in: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svgdom", 3 | "version": "$(version)", 4 | "homepage": "https://github.com/cppfw/svgdom", 5 | "description": "SVG document object model library in C++", 6 | "license": "MIT", 7 | "dependencies": [ 8 | { 9 | "name" : "vcpkg-cmake", 10 | "host" : true 11 | }, 12 | { 13 | "name" : "vcpkg-cmake-config", 14 | "host" : true 15 | }, 16 | { 17 | "name" : "myci", 18 | "host" : true 19 | }, 20 | "utki", 21 | "papki", 22 | "mikroxml", 23 | "cssom", 24 | "r4" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /cocoapods/svgdom.podspec.in: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "svgdom" 3 | s.version = "$(version)" 4 | s.summary = "C++ cross-platform SVG DOM library." 5 | s.homepage = "https://github.com/cppfw/#{s.name}" 6 | s.license = { :type => 'MIT', :file => 'LICENSE' } 7 | s.author = { "Ivan Gagis" => "igagis@gmail.com" } 8 | s.platform = :ios 9 | s.ios.deployment_target = '12.0' 10 | 11 | s.source = { :http => "http://gagis.hopto.org/repo/cppfw/cocoapods/#{s.name}-#{s.version}.zip" } 12 | 13 | s.source_files = "include/**/*.{hpp,h}" 14 | s.header_mappings_dir = "include" 15 | 16 | s.ios.vendored_framework = "lib/ios/#{s.name}.xcframework" 17 | 18 | s.dependency 'utki', '>= 1.1.164' 19 | s.dependency 'papki', '>= 1.0.93' 20 | s.dependency 'mikroxml', '>= 0.1.36' 21 | s.dependency 'cssom', '>= 0.1.19' 22 | s.dependency 'r4', '>= 1.0.53' 23 | end 24 | -------------------------------------------------------------------------------- /conan/conanfile.py: -------------------------------------------------------------------------------- 1 | import os 2 | from conan import ConanFile 3 | from conan.tools.scm import Git 4 | from conan.tools.files import load, update_conandata, copy 5 | from conan.tools.layout import basic_layout 6 | 7 | class SvgdomConan(ConanFile): 8 | name = "svgdom" 9 | license = "MIT" 10 | author = "Ivan Gagis " 11 | url = "http://github.com/cppfw/" + name 12 | description = "SVG document object model C++ library" 13 | topics = ("C++", "cross-platform") 14 | settings = "os", "compiler", "build_type", "arch" 15 | package_type = "library" 16 | options = {"shared": [True, False], "fPIC": [True, False]} 17 | default_options = {"shared": False, "fPIC": True} 18 | generators = "AutotoolsDeps" # this will set CXXFLAGS etc. env vars 19 | 20 | def requirements(self): 21 | self.requires("utki/[>=1.1.202]@cppfw/main", transitive_headers=True) 22 | self.requires("cssom/[>=0.0.0]@cppfw/main", transitive_headers=True) 23 | self.requires("r4/[>=0.0.0]@cppfw/main", transitive_headers=True) 24 | self.requires("mikroxml/[>=0.0.0]@cppfw/main", transitive_headers=False) 25 | 26 | def build_requirements(self): 27 | self.tool_requires("prorab/[>=2.0.27]@cppfw/main") 28 | self.tool_requires("prorab-extra/[>=0.2.57]@cppfw/main") 29 | 30 | if self.settings.os != "Emscripten": 31 | self.requires("tst/[>=0.3.29]@cppfw/main", visible=False) 32 | 33 | def config_options(self): 34 | if self.settings.os == "Windows": 35 | del self.options.fPIC 36 | 37 | # save commit and remote URL to conandata.yml for packaging 38 | def export(self): 39 | git = Git(self) 40 | scm_url = git.get_remote_url() 41 | # NOTE: Git.get_commit() doesn't work properly, 42 | # it gets latest commit of the folder in which conanfile.py resides. 43 | # So, we use "git rev-parse HEAD" instead as it gets the actual HEAD 44 | # commit regardless of the current working directory within the repo. 45 | scm_commit = git.run("rev-parse HEAD") # get current commit 46 | update_conandata(self, {"sources": {"commit": scm_commit, "url": scm_url}}) 47 | 48 | def source(self): 49 | git = Git(self) 50 | sources = self.conan_data["sources"] 51 | # shallow fetch commit 52 | git.fetch_commit(url=sources["url"], commit=sources['commit']) 53 | # shallow clone submodules 54 | git.run("submodule update --init --remote --depth 1") 55 | 56 | def build(self): 57 | if self.settings.os == "Emscripten": 58 | self.run("make $MAKE_INCLUDE_DIRS_ARG config=emsc --directory=src") 59 | else: 60 | self.run("make $MAKE_INCLUDE_DIRS_ARG lint=off") 61 | self.run("make $MAKE_INCLUDE_DIRS_ARG lint=off test") 62 | 63 | def package(self): 64 | if self.settings.os == "Emscripten": 65 | src_rel_dir = os.path.join(self.build_folder, "src/out/emsc") 66 | else: 67 | src_rel_dir = os.path.join(self.build_folder, "src/out/rel") 68 | 69 | src_dir = os.path.join(self.build_folder, "src") 70 | dst_include_dir = os.path.join(self.package_folder, "include") 71 | dst_lib_dir = os.path.join(self.package_folder, "lib") 72 | dst_bin_dir = os.path.join(self.package_folder, "bin") 73 | copy(conanfile=self, pattern="*.h", dst=dst_include_dir, src=src_dir, keep_path=True) 74 | copy(conanfile=self, pattern="*.hpp", dst=dst_include_dir, src=src_dir, keep_path=True) 75 | 76 | if self.options.shared: 77 | copy(conanfile=self, pattern="*" + self.name + ".lib", dst=dst_lib_dir, src="", keep_path=False) 78 | copy(conanfile=self, pattern="*.dll", dst=dst_bin_dir, src=src_rel_dir, keep_path=False) 79 | copy(conanfile=self, pattern="*.so", dst=dst_lib_dir, src=src_rel_dir, keep_path=False) 80 | copy(conanfile=self, pattern="*.so.*", dst=dst_lib_dir, src=src_rel_dir, keep_path=False) 81 | copy(conanfile=self, pattern="*.dylib", dst=dst_lib_dir, src=src_rel_dir, keep_path=False) 82 | else: 83 | copy(conanfile=self, pattern="*" + self.name + ".lib", dst=dst_lib_dir, src="", keep_path=False) 84 | copy(conanfile=self, pattern="*.a", dst=dst_lib_dir, src=src_rel_dir, keep_path=False) 85 | 86 | def package_info(self): 87 | self.cpp_info.libs = [self.name] 88 | 89 | def package_id(self): 90 | # change package id only when minor or major version changes, i.e. when ABI breaks 91 | self.info.requires.minor_mode() 92 | -------------------------------------------------------------------------------- /conan/test_package/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(PackageTest CXX) 3 | 4 | # set(CMAKE_VERBOSE_MAKEFILE on) 5 | 6 | find_package(svgdom CONFIG REQUIRED) 7 | 8 | add_executable(example example.cpp) 9 | target_link_libraries(example svgdom::svgdom) 10 | -------------------------------------------------------------------------------- /conan/test_package/conanfile.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from conan import ConanFile, tools 4 | from conan.tools.cmake import CMake, cmake_layout 5 | 6 | class TestConan(ConanFile): 7 | settings = "os", "compiler", "build_type", "arch" 8 | generators = "CMakeToolchain", "CMakeDeps" 9 | 10 | def requirements(self): 11 | self.requires(self.tested_reference_str) 12 | 13 | def build(self): 14 | cmake = CMake(self) 15 | cmake.configure() 16 | cmake.build() 17 | 18 | def layout(self): 19 | cmake_layout(self) 20 | 21 | def test(self): 22 | self.run(".%sexample" % os.sep, env="conanrun") # env sets LD_LIBRARY_PATH etc. to find dependency libs 23 | -------------------------------------------------------------------------------- /conan/test_package/example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main(int argc, const char** argv){ 6 | std::cout << "Hello svgdom!" << '\n'; 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /config/asan.mk: -------------------------------------------------------------------------------- 1 | include $(config_dir)rel.mk 2 | 3 | this_cxxflags += -fsanitize=address 4 | this_ldflags += -fsanitize=address 5 | -------------------------------------------------------------------------------- /config/base/base.mk: -------------------------------------------------------------------------------- 1 | this_cxxflags += -Wall # enable all warnings 2 | this_cxxflags += -Wnon-virtual-dtor # warn if base class has non-virtual destructor 3 | this_cxxflags += -Werror # treat warnings as errors 4 | # this_cxxflags += -Wfatal-errors # stop on first error encountered 5 | this_cxxflags += -fstrict-aliasing # in order to comply with the c++ standard more strictly 6 | this_cxxflags += -std=c++17 7 | this_cxxflags += -g 8 | this_cxxflags += -fPIC 9 | 10 | this_ldlibs += -lstdc++ 11 | 12 | ifeq ($(gprof), true) 13 | this_cxxflags += -pg 14 | this_ldflags += -pg 15 | endif 16 | -------------------------------------------------------------------------------- /config/dbg.mk: -------------------------------------------------------------------------------- 1 | include $(config_dir)base/base.mk 2 | 3 | this_cxxflags += -DDEBUG 4 | this_cxxflags += -O0 5 | -------------------------------------------------------------------------------- /config/default.mk: -------------------------------------------------------------------------------- 1 | $(eval $(call prorab-config-default, rel)) 2 | -------------------------------------------------------------------------------- /config/emsc.mk: -------------------------------------------------------------------------------- 1 | include $(config_dir)base/base.mk 2 | 3 | this_cxxflags += -O3 4 | 5 | this_cxx := em++ 6 | this_cc := emcc 7 | this_ar := emar 8 | 9 | this_static_lib_only := true 10 | 11 | # TODO: remove the warning suppression when the PR is merged 12 | # Suppress version-check warning due to https://github.com/conan-io/conan-center-index/pull/26247 13 | this_cxxflags += -Wno-version-check 14 | 15 | this_cxxflags += -fwasm-exceptions 16 | this_ldflags += -fwasm-exceptions 17 | 18 | this_cxxflags += -pthread 19 | this_ldflags += -pthread -------------------------------------------------------------------------------- /config/gcov.mk: -------------------------------------------------------------------------------- 1 | include $(config_dir)base/base.mk 2 | 3 | # no optimization to avoid mismamtch of actual code to source lines, 4 | # otherwise coverage report will not be accurate 5 | this_cxxflags += -O0 6 | 7 | this_cxxflags += -ftest-coverage 8 | this_cxxflags += -fprofile-arcs 9 | 10 | this_ldflags += --coverage 11 | -------------------------------------------------------------------------------- /config/rel.mk: -------------------------------------------------------------------------------- 1 | include $(config_dir)base/base.mk 2 | 3 | this_cxxflags += -O3 4 | 5 | this_lint_cmd = $(prorab_lint_cmd_clang_tidy) 6 | 7 | # WORKAROUND: on ubuntu jammy dpkg-buildpackage passes -ffat-lto-objects compilation flag 8 | # which is not supported by clang and clang-tidy complains about it: 9 | # error: optimization flag '-ffat-lto-objects' is not supported [clang-diagnostic-ignored-optimization-argument] 10 | # Thus, suppress this warning. 11 | this_cxxflags += -Wno-ignored-optimization-argument 12 | 13 | ifeq ($(os),macosx) 14 | # WORKAROUND: 15 | # clang-tidy on macos doesn't use /usr/local/include as default place to 16 | # search for header files, so we add it explicitly 17 | this_cxxflags += -I /usr/local/include 18 | endif 19 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /debian/control.in: -------------------------------------------------------------------------------- 1 | Source: libsvgdom 2 | Section: libs 3 | Priority: extra 4 | Maintainer: Ivan Gagis 5 | Build-Depends: 6 | debhelper (>= 9), 7 | prorab, 8 | prorab-extra, 9 | myci, 10 | clang-tidy, 11 | clang-format, 12 | libc6-dev, 13 | libutki-dev (>= 1.1.150), 14 | libpapki-dev, 15 | libmikroxml-dev, 16 | libcssom-dev (>= 0.1.19), 17 | libr4-dev, 18 | libtst-dev 19 | Build-Depends-Indep: doxygen 20 | Standards-Version: 3.9.2 21 | 22 | Package: libsvgdom$(soname) 23 | Section: libs 24 | Architecture: any 25 | Depends: ${shlibs:Depends}, ${misc:Depends} 26 | Description: cross-platform C++ library for reading SVG files. 27 | SVG document object model library. 28 | 29 | Package: libsvgdom$(soname)-dbgsrc 30 | Section: debug 31 | Architecture: all 32 | Depends: libsvgdom$(soname)-dbgsym (= ${binary:Version}), ${misc:Depends} 33 | Description: debugging sources for libsvgdom$(soname) package. 34 | 35 | Package: libsvgdom-dev 36 | Section: libdevel 37 | Architecture: any 38 | Depends: libsvgdom$(soname) (= ${binary:Version}), ${misc:Depends}, 39 | libutki-dev, libpapki-dev, libcssom-dev, libr4-dev 40 | Suggests: libsvgdom-doc 41 | Description: cross-platform C++ library for reading SVG files. 42 | SVG document object model library. 43 | 44 | Package: libsvgdom-doc 45 | Section: doc 46 | Architecture: all 47 | Depends: ${misc:Depends} 48 | Description: documentation for libsvgdom - SVG DOM library. 49 | For more details see description to libsvgdom-dev package. 50 | -------------------------------------------------------------------------------- /debian/libsvgdom$(soname)-dbgsrc.install.in: -------------------------------------------------------------------------------- 1 | usr/src/* 2 | -------------------------------------------------------------------------------- /debian/libsvgdom-dev.install: -------------------------------------------------------------------------------- 1 | usr/include 2 | usr/lib/pkgconfig 3 | usr/lib/lib*.so 4 | usr/lib/lib*.a 5 | 6 | -------------------------------------------------------------------------------- /debian/libsvgdom-doc.install: -------------------------------------------------------------------------------- 1 | usr/share/doc 2 | -------------------------------------------------------------------------------- /debian/libsvgdom.install.in: -------------------------------------------------------------------------------- 1 | usr/lib/lib*.so.* 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | export PREFIX := /usr 4 | 5 | dbgsrc_pkg_name := $(filter %-dbgsrc, $(shell awk '/^Package: /{print $2}' debian/control)) 6 | debug_prefix_map_arg := -fdebug-prefix-map=$(shell pwd)/src=$(PREFIX)/src/$(patsubst %-dbgsrc,%,$(dbgsrc_pkg_name)) 7 | 8 | export PRORAB_INSTALL_DBGSRC := true 9 | 10 | export DEB_CFLAGS_MAINT_APPEND := $(debug_prefix_map_arg) 11 | export DEB_CXXFLAGS_MAINT_APPEND := $(debug_prefix_map_arg) 12 | export DEB_OBJCFLAGS_MAINT_APPEND := $(debug_prefix_map_arg) 13 | export DEB_OBJCXXFLAGS_MAINT_APPEND := $(debug_prefix_map_arg) 14 | 15 | %: 16 | dh $@ 17 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /doc/makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | include prorab-doxygen.mk 3 | 4 | this_out_dir := out 5 | this_name := svgdom 6 | 7 | $(eval $(prorab-build-doxygen)) 8 | -------------------------------------------------------------------------------- /emscripten/conan.profile: -------------------------------------------------------------------------------- 1 | [settings] 2 | os=Emscripten 3 | arch=wasm 4 | compiler=clang 5 | compiler.version=15 6 | compiler.libcxx=libc++ 7 | build_type=Release 8 | 9 | [tool_requires] 10 | emsdk/[>=3.1.72] 11 | -------------------------------------------------------------------------------- /homebrew/libsvgdom.rb.in: -------------------------------------------------------------------------------- 1 | class Libsvgdom < Formula 2 | desc "C++ cross-platform SVG DOM library." 3 | homepage "https://github.com/cppfw/svgdom" 4 | url "https://github.com/cppfw/svgdom/archive/$(version).tar.gz" 5 | sha256 "$(sha256)" 6 | 7 | depends_on "prorab" => :build 8 | depends_on "prorab-extra" => :build 9 | depends_on "myci" => :build 10 | depends_on "pkg-config" => :build 11 | depends_on "libtst" => :build 12 | depends_on "libmikroxml" 13 | depends_on "libcssom" 14 | depends_on "libpapki" 15 | depends_on "libutki" 16 | depends_on "libr4" 17 | 18 | # use gmake here because otherwise homebrew uses default Mac's make which is of too old version 3.81 19 | def install 20 | ENV['PATH'] += ":#{ENV['HOMEBREW_PREFIX']}/bin" 21 | system "#{ENV['HOMEBREW_PREFIX']}/opt/make/libexec/gnubin/make", "--include-dir=#{ENV['HOMEBREW_PREFIX']}/include", "install", "PREFIX=#{prefix}", "lint=off" 22 | end 23 | 24 | test do 25 | system "#{ENV['HOMEBREW_PREFIX']}/opt/make/libexec/gnubin/make", "--include-dir=#{ENV['HOMEBREW_PREFIX']}/include", "test" 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | 3 | $(eval $(prorab-include-subdirs)) 4 | -------------------------------------------------------------------------------- /msvs_solution/libsvgdom/libsvgdom.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /msvs_solution/libsvgdom/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /msvs_solution/test_dom/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /msvs_solution/test_dom/test_dom.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /msys2/PKGBUILD.in: -------------------------------------------------------------------------------- 1 | # Maintainer: Ivan Gagis 2 | 3 | if [ "$MSYSTEM" == "MSYS" ]; then 4 | pkgPrefix= 5 | dirPrefix=/usr 6 | arch=('x86_64' 'i686') 7 | elif [ "$MSYSTEM" == "MINGW32" ]; then 8 | pkgPrefix=mingw-w64-i686- 9 | dirPrefix=/mingw32 10 | arch=('any') 11 | elif [ "$MSYSTEM" == "MINGW64" ]; then 12 | pkgPrefix=mingw-w64-x86_64- 13 | dirPrefix=/mingw64 14 | arch=('any') 15 | else 16 | echo "ERROR: unknown MSYS shell: $MSYSTEM" 17 | exit 1 18 | fi 19 | 20 | packageName=svgdom 21 | 22 | pkgname="${pkgPrefix}${packageName}" 23 | pkgver=$(version) 24 | pkgrel=1 25 | epoch= 26 | pkgdesc="SVG DOM library in C++" 27 | #arch=('any') #defined above 28 | url="http://github.com/cppfw/${packageName}" 29 | license=('MIT') 30 | groups=() 31 | 32 | depends=( 33 | "${pkgPrefix}utki" 34 | "${pkgPrefix}mikroxml" 35 | "${pkgPrefix}cssom" 36 | "${pkgPrefix}r4" 37 | ) 38 | 39 | makedepends=( 40 | 'myci' 41 | 'prorab' 42 | 'prorab-extra' 43 | 'doxygen' 44 | "${pkgPrefix}tst" 45 | "${pkgPrefix}clang-tools-extra" 46 | ) 47 | checkdepends=('myci') 48 | optdepends=() 49 | provides=() 50 | conflicts=() 51 | replaces=() 52 | backup=() 53 | options=() 54 | install= 55 | changelog= 56 | source=() # Do not download any sources 57 | noextract=() 58 | md5sums=() 59 | validpgpkeys=() 60 | 61 | rootDir=$(pwd)/.. # project root directory 62 | 63 | prepare() { 64 | cd "$rootDir" 65 | } 66 | 67 | build() { 68 | cd "$rootDir" 69 | CXX=clang++ make lint=off 70 | } 71 | 72 | check() { 73 | cd "$rootDir" 74 | CXX=clang++ make test 75 | } 76 | 77 | package() { 78 | cd "$rootDir" 79 | CXX=clang++ make DESTDIR="$pkgdir" PREFIX="$dirPrefix" install 80 | } 81 | -------------------------------------------------------------------------------- /nuget/nuget.autopkg.in: -------------------------------------------------------------------------------- 1 | configurations { 2 | UserPlatformToolset { 3 | // Needed because autopackage lacks VS2015+ support 4 | key = "PlatformToolset"; 5 | choices: "v140,v141,v142,v143"; 6 | }; 7 | 8 | RuntimeLibrary { 9 | key = "RuntimeLibrary"; // This is the key you can find in .vcxproj file 10 | choices: "MultiThreaded,MultiThreadedDebug,MultiThreadedDLL,MultiThreadedDebugDLL"; // these choices must be valid values for .vcxproj file 11 | }; 12 | } 13 | 14 | nuget{ 15 | nuspec{ 16 | id = libsvgdom; 17 | version : $(version); 18 | title: C++ SVG DOM library; 19 | authors: {Ivan Gagis}; 20 | owners: {Ivan Gagis}; 21 | licenseUrl: "https://raw.githubusercontent.com/cppfw/svgdom/main/LICENSE"; 22 | projectUrl: "https://github.com/cppfw/svgdom"; 23 | iconUrl: "https://github.com/cppfw/svgdom/blob/main/logo.svg"; 24 | requireLicenseAcceptance:false; 25 | summary: C++ SVG DOM library; 26 | 27 | description: @"C++ SVG DOM library"; 28 | releaseNotes: "Initial release"; 29 | copyright: Copyright 2020 Ivan Gagis; 30 | tags: { native}; 31 | } 32 | dependencies { 33 | packages : { 34 | libutki/1.1.150; 35 | libpapki/1.0.93; 36 | libmikroxml/0.1.34; 37 | libcssom/0.1.18; 38 | libr4/1.0.51; 39 | }; 40 | } 41 | files { 42 | //this is needed to put headers in the base folder 43 | nestedInclude: { 44 | #destination = ${d_include}svgdom; 45 | "..\src\svgdom\**\*.hpp" 46 | }; 47 | 48 | //==== v140 tools ==== 49 | /* 50 | [x86,v140,release] { 51 | lib: ..\msvs_solution\v140_Release\libsvgdom.lib; 52 | } 53 | [x86,v140,debug] { 54 | lib: ..\msvs_solution\v140_Debug\libsvgdom.lib; 55 | } 56 | [x64,v140,release] { 57 | lib: ..\msvs_solution\x64\v140_Release\libsvgdom.lib; 58 | } 59 | [x64,v140,debug] { 60 | lib: ..\msvs_solution\x64\v140_Debug\libsvgdom.lib; 61 | } 62 | */ 63 | //==== v141 tools ==== 64 | /* 65 | [x86,v141,release] { 66 | lib: ..\msvs_solution\v141_Release\libsvgdom.lib; 67 | } 68 | [x86,v141,debug] { 69 | lib: ..\msvs_solution\v141_Debug\libsvgdom.lib; 70 | } 71 | [x64,v141,release] { 72 | lib: ..\msvs_solution\x64\v141_Release\libsvgdom.lib; 73 | } 74 | [x64,v141,debug] { 75 | lib: ..\msvs_solution\x64\v141_Debug\libsvgdom.lib; 76 | } 77 | */ 78 | //==== v142 tools ==== 79 | /* 80 | [x86,v142,release,MultiThreaded] { 81 | lib: ..\msvs_solution\v142_Release_MT\libsvgdom.lib; 82 | } 83 | [x86,v142,debug,MultiThreadedDebug] { 84 | lib: ..\msvs_solution\v142_Debug_MT\libsvgdom.lib; 85 | } 86 | [x64,v142,release,MultiThreaded] { 87 | lib: ..\msvs_solution\x64\v142_Release_MT\libsvgdom.lib; 88 | } 89 | [x64,v142,debug,MultiThreadedDebug] { 90 | lib: ..\msvs_solution\x64\v142_Debug_MT\libsvgdom.lib; 91 | } 92 | [x86,v142,release,MultiThreadedDLL] { 93 | lib: ..\msvs_solution\v142_Release_MD\libsvgdom.lib; 94 | } 95 | [x86,v142,debug,MultiThreadedDebugDLL] { 96 | lib: ..\msvs_solution\v142_Debug_MD\libsvgdom.lib; 97 | } 98 | [x64,v142,release,MultiThreadedDLL] { 99 | lib: ..\msvs_solution\x64\v142_Release_MD\libsvgdom.lib; 100 | } 101 | [x64,v142,debug,MultiThreadedDebugDLL] { 102 | lib: ..\msvs_solution\x64\v142_Debug_MD\libsvgdom.lib; 103 | } 104 | */ 105 | //==== v143 tools ==== 106 | 107 | [x86,v143,release,MultiThreaded] { 108 | lib: ..\msvs_solution\v143_Release_MT\libsvgdom.lib; 109 | } 110 | [x86,v143,debug,MultiThreadedDebug] { 111 | lib: ..\msvs_solution\v143_Debug_MT\libsvgdom.lib; 112 | } 113 | [x64,v143,release,MultiThreaded] { 114 | lib: ..\msvs_solution\x64\v143_Release_MT\libsvgdom.lib; 115 | } 116 | [x64,v143,debug,MultiThreadedDebug] { 117 | lib: ..\msvs_solution\x64\v143_Debug_MT\libsvgdom.lib; 118 | } 119 | [x86,v143,release,MultiThreadedDLL] { 120 | lib: ..\msvs_solution\v143_Release_MD\libsvgdom.lib; 121 | } 122 | [x86,v143,debug,MultiThreadedDebugDLL] { 123 | lib: ..\msvs_solution\v143_Debug_MD\libsvgdom.lib; 124 | } 125 | [x64,v143,release,MultiThreadedDLL] { 126 | lib: ..\msvs_solution\x64\v143_Release_MD\libsvgdom.lib; 127 | } 128 | [x64,v143,debug,MultiThreadedDebugDLL] { 129 | lib: ..\msvs_solution\x64\v143_Debug_MD\libsvgdom.lib; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /pkg-config/makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | include prorab-pkg-config.mk 3 | 4 | $(eval $(prorab-pkg-config)) 5 | -------------------------------------------------------------------------------- /pkg-config/svgdom.pc.in: -------------------------------------------------------------------------------- 1 | Name: svgdom # human-readable name 2 | Description: C++ library for reading SVG files # human-readable description 3 | Version: $(version) 4 | URL: https://github.com/cppfw/svgdom 5 | Requires: 6 | Conflicts: 7 | Libs: -lsvgdom 8 | Libs.private: 9 | Cflags: 10 | -------------------------------------------------------------------------------- /src/.clang-tidy: -------------------------------------------------------------------------------- 1 | # TODO: remove when moved to C++20 2 | Checks: | 3 | -modernize-use-designated-initializers 4 | InheritParentConfig: true 5 | -------------------------------------------------------------------------------- /src/makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | include prorab-license.mk 3 | include prorab-clang-format.mk 4 | include prorab-install-dbgsrc.mk 5 | 6 | $(eval $(call prorab-try-simple-include, $(CONANBUILDINFO_DIR)conanbuildinfo.mak)) 7 | 8 | $(eval $(call prorab-config, ../config)) 9 | 10 | this_name := svgdom 11 | 12 | this_soname := $(shell cat $(d)soname.txt) 13 | 14 | this_srcs := $(call prorab-src-dir,.) 15 | 16 | this_cxxflags += $(addprefix -I,$(CONAN_INCLUDE_DIRS)) 17 | this_cxxflags_test += $(addprefix -I,$(CONAN_INCLUDE_DIRS)) 18 | this_ldflags += $(addprefix -L,$(CONAN_LIB_DIRS)) 19 | 20 | this_ldlibs += -lcssom -lpapki -lmikroxml -lutki -lstdc++ -lm 21 | 22 | $(eval $(prorab-build-lib)) 23 | 24 | $(eval $(prorab-clang-format)) 25 | 26 | this_src_dir := $(this_name) 27 | this_license_file := ../LICENSE 28 | $(eval $(prorab-license)) 29 | 30 | $(eval $(prorab-install-dbgsrc)) 31 | -------------------------------------------------------------------------------- /src/soname.txt: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /src/svgdom/config.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | namespace svgdom { 31 | 32 | using real = float; 33 | 34 | } // namespace svgdom 35 | -------------------------------------------------------------------------------- /src/svgdom/dom.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "dom.hpp" 29 | 30 | #include "config.hpp" 31 | #include "parser.hxx" 32 | 33 | using namespace svgdom; 34 | 35 | std::unique_ptr svgdom::load(const papki::file& f) 36 | { 37 | svgdom::parser parser; 38 | 39 | { 40 | papki::file::guard file_guard(f); 41 | 42 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) 43 | std::array buf; 44 | 45 | while (true) { 46 | auto res = f.read(utki::make_span(buf)); 47 | ASSERT(res <= buf.size()) 48 | if (res == 0) { 49 | break; 50 | } 51 | parser.feed(utki::make_span(buf.data(), res)); 52 | } 53 | parser.end(); 54 | } 55 | 56 | return parser.get_dom(); 57 | } 58 | 59 | std::unique_ptr svgdom::load(std::istream& s) 60 | { 61 | svgdom::parser parser; 62 | 63 | static const size_t chunk_size = 0x1000; // 4kb 64 | 65 | while (!s.eof()) { 66 | std::vector buf; 67 | buf.reserve(chunk_size); 68 | for (size_t i = 0; i != chunk_size; ++i) { 69 | auto c = char(s.get()); 70 | if (s.eof()) { 71 | break; 72 | } 73 | buf.push_back(c); 74 | } 75 | parser.feed(utki::make_span(buf)); 76 | } 77 | parser.end(); 78 | 79 | return parser.get_dom(); 80 | } 81 | 82 | std::unique_ptr svgdom::load(std::string_view s) 83 | { 84 | return load(utki::make_span(s)); 85 | } 86 | 87 | std::unique_ptr svgdom::load(utki::span buf) 88 | { 89 | return load(to_char(buf)); 90 | } 91 | 92 | std::unique_ptr svgdom::load(utki::span buf) 93 | { 94 | svgdom::parser parser; 95 | 96 | parser.feed(buf); 97 | parser.end(); 98 | 99 | return parser.get_dom(); 100 | } 101 | -------------------------------------------------------------------------------- /src/svgdom/dom.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | #include 32 | 33 | #include "elements/structurals.hpp" 34 | 35 | namespace svgdom { 36 | 37 | /** 38 | * @brief Load SVG document. 39 | * Load SVG document from XML file. 40 | * @param f - file interface to load SVG from. 41 | * @return unique pointer to the root of SVG document tree. 42 | */ 43 | std::unique_ptr load(const papki::file& f); 44 | 45 | /** 46 | * @brief Load SVG document. 47 | * Load SVG document from XML stream. 48 | * @param s - input stream to load SVG from. 49 | * @return unique pointer to the root of SVG document tree. 50 | */ 51 | std::unique_ptr load(std::istream& s); 52 | 53 | /** 54 | * @brief Load SVG document. 55 | * Load SVG document from std::string. 56 | * @param s - input string to load SVG from. 57 | * @return unique pointer to the root of SVG document tree. 58 | */ 59 | std::unique_ptr load(std::string_view s); 60 | 61 | /** 62 | * @brief Load SVG document from memory buffer. 63 | * @param buf - input buffer to load SVG from. 64 | * @return unique pointer to the root of SVG document tree. 65 | */ 66 | std::unique_ptr load(utki::span buf); 67 | 68 | /** 69 | * @brief Load SVG document from memory buffer. 70 | * @param buf - input buffer to load SVG from. 71 | * @return unique pointer to the root of SVG document tree. 72 | */ 73 | std::unique_ptr load(utki::span buf); 74 | 75 | } // namespace svgdom 76 | -------------------------------------------------------------------------------- /src/svgdom/elements/aspect_ratioed.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | namespace svgdom { 33 | struct aspect_ratioed { 34 | enum class aspect_ratio_preservation { 35 | none, 36 | x_min_y_min, 37 | x_mid_y_min, 38 | x_max_y_min, 39 | x_min_y_mid, 40 | x_mid_y_mid, 41 | x_max_y_mid, 42 | x_min_y_max, 43 | x_mid_y_max, 44 | x_max_y_max 45 | }; 46 | 47 | struct aspect_ratio_preservation_value { 48 | aspect_ratio_preservation preserve = aspect_ratio_preservation::none; 49 | bool defer = false; 50 | bool slice = false; 51 | 52 | std::string to_string() const; 53 | void parse(std::string_view str); 54 | } preserve_aspect_ratio; 55 | }; 56 | 57 | } // namespace svgdom 58 | -------------------------------------------------------------------------------- /src/svgdom/elements/container.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | #include 32 | 33 | #include "element.hpp" 34 | 35 | namespace svgdom { 36 | 37 | /** 38 | * @brief An element which can have child elements. 39 | */ 40 | struct container { 41 | std::vector> children; 42 | 43 | container() = default; 44 | 45 | /** 46 | * @brief Copy constructor. 47 | * This copy constructor does nothing because to make a deep copy of the children 48 | * one needs to clone every child by hand. 49 | */ 50 | // TODO: implement deep copying using cloner? 51 | container(const container&) {} 52 | 53 | container& operator=(const container&) = delete; 54 | 55 | container(container&&) = default; 56 | container& operator=(container&&) = default; 57 | 58 | virtual ~container() = default; 59 | }; 60 | 61 | } // namespace svgdom 62 | -------------------------------------------------------------------------------- /src/svgdom/elements/coordinate_units.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | namespace svgdom { 31 | enum class coordinate_units { 32 | unknown, 33 | user_space_on_use, 34 | object_bounding_box 35 | }; 36 | 37 | } // namespace svgdom 38 | -------------------------------------------------------------------------------- /src/svgdom/elements/element.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "element.hpp" 29 | 30 | #include 31 | #include 32 | 33 | #include "../util/stream_writer.hpp" 34 | #include "../visitor.hpp" 35 | 36 | #include "container.hpp" 37 | 38 | using namespace svgdom; 39 | 40 | std::string element::to_string() const 41 | { 42 | std::stringstream s; 43 | 44 | stream_writer visitor(s); 45 | this->accept(visitor); 46 | 47 | return s.str(); 48 | } 49 | -------------------------------------------------------------------------------- /src/svgdom/elements/element.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | #include 32 | 33 | namespace svgdom { 34 | 35 | class visitor; 36 | class const_visitor; 37 | 38 | /** 39 | * @brief Base class for all SVG document elements. 40 | */ 41 | // TODO: why lint complains here on macos? 42 | // NOLINTNEXTLINE(bugprone-exception-escape, "error: an exception may be thrown in function") 43 | struct element { 44 | std::string id; 45 | 46 | std::string to_string() const; 47 | 48 | /** 49 | * @brief Accept method for visitor pattern. 50 | * @param v - visitor to accept. 51 | */ 52 | virtual void accept(visitor& v) = 0; 53 | 54 | /** 55 | * @brief Accept method for visitor pattern. 56 | * @param v - constant visitor to accept. 57 | */ 58 | virtual void accept(const_visitor& v) const = 0; 59 | 60 | /** 61 | * @brief Get tag name of the element. 62 | * @return Tag name of the element. 63 | */ 64 | virtual std::string_view get_tag() const = 0; 65 | 66 | // TODO: why lint complains here on macos? 67 | // NOLINTNEXTLINE(bugprone-exception-escape, "error: an exception may be thrown in function") 68 | element() = default; 69 | 70 | element(const element&) = default; 71 | element& operator=(const element&) = default; 72 | 73 | element(element&&) = default; 74 | element& operator=(element&&) = default; 75 | 76 | virtual ~element() = default; 77 | }; 78 | 79 | } // namespace svgdom 80 | -------------------------------------------------------------------------------- /src/svgdom/elements/filter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "filter.hpp" 29 | 30 | #include "../visitor.hpp" 31 | 32 | using namespace svgdom; 33 | 34 | void filter_element::accept(visitor& visitor) 35 | { 36 | visitor.visit(*this); 37 | } 38 | 39 | void filter_element::accept(const_visitor& visitor) const 40 | { 41 | visitor.visit(*this); 42 | } 43 | 44 | void fe_gaussian_blur_element::accept(visitor& visitor) 45 | { 46 | visitor.visit(*this); 47 | } 48 | 49 | void fe_gaussian_blur_element::accept(const_visitor& visitor) const 50 | { 51 | visitor.visit(*this); 52 | } 53 | 54 | void fe_color_matrix_element::accept(visitor& visitor) 55 | { 56 | visitor.visit(*this); 57 | } 58 | 59 | void fe_blend_element::accept(visitor& visitor) 60 | { 61 | visitor.visit(*this); 62 | } 63 | 64 | void fe_composite_element::accept(visitor& visitor) 65 | { 66 | visitor.visit(*this); 67 | } 68 | 69 | void fe_color_matrix_element::accept(const_visitor& visitor) const 70 | { 71 | visitor.visit(*this); 72 | } 73 | 74 | void fe_blend_element::accept(const_visitor& visitor) const 75 | { 76 | visitor.visit(*this); 77 | } 78 | 79 | void fe_composite_element::accept(const_visitor& visitor) const 80 | { 81 | visitor.visit(*this); 82 | } 83 | 84 | r4::vector2 fe_gaussian_blur_element::get_std_deviation() const noexcept 85 | { 86 | if (!this->is_std_deviation_specified()) { 87 | return 0; 88 | } 89 | 90 | if (this->is_std_deviation_y_specified()) { 91 | return this->std_deviation; 92 | } 93 | 94 | return this->std_deviation.x(); 95 | } 96 | -------------------------------------------------------------------------------- /src/svgdom/elements/gradients.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "gradients.hpp" 29 | 30 | #include 31 | 32 | #include "../util.hxx" 33 | #include "../visitor.hpp" 34 | 35 | using namespace svgdom; 36 | 37 | void radial_gradient_element::accept(visitor& v) 38 | { 39 | v.visit(*this); 40 | } 41 | 42 | void radial_gradient_element::accept(const_visitor& v) const 43 | { 44 | v.visit(*this); 45 | } 46 | 47 | void linear_gradient_element::accept(visitor& v) 48 | { 49 | v.visit(*this); 50 | } 51 | 52 | void linear_gradient_element::accept(const_visitor& v) const 53 | { 54 | v.visit(*this); 55 | } 56 | 57 | void gradient::stop_element::accept(visitor& v) 58 | { 59 | v.visit(*this); 60 | } 61 | 62 | void gradient::stop_element::accept(const_visitor& v) const 63 | { 64 | v.visit(*this); 65 | } 66 | 67 | std::string gradient::spread_method_to_string() const 68 | { 69 | switch (this->spread_method_attribute) { 70 | default: 71 | case gradient::spread_method::default_method: 72 | return ""; 73 | case gradient::spread_method::pad: 74 | return "pad"; 75 | case gradient::spread_method::reflect: 76 | return "reflect"; 77 | case gradient::spread_method::repeat: 78 | return "repeat"; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/svgdom/elements/gradients.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | #include "container.hpp" 33 | #include "coordinate_units.hpp" 34 | #include "element.hpp" 35 | #include "referencing.hpp" 36 | #include "styleable.hpp" 37 | #include "transformable.hpp" 38 | 39 | namespace svgdom { 40 | 41 | using namespace std::string_view_literals; 42 | 43 | /** 44 | * @brief Common base for gradient elements. 45 | */ 46 | // TODO: why lint complains here on macos? 47 | // NOLINTNEXTLINE(bugprone-exception-escape, "error: an exception may be thrown in function") 48 | struct gradient : public element, public container, public referencing, public transformable, public styleable { 49 | enum class spread_method { 50 | default_method, 51 | pad, 52 | reflect, 53 | repeat 54 | }; 55 | 56 | spread_method spread_method_attribute = spread_method::default_method; 57 | 58 | coordinate_units units = coordinate_units::unknown; 59 | 60 | // TODO: why lint complains here on macos? 61 | // NOLINTNEXTLINE(bugprone-exception-escape, "error: an exception may be thrown in function") 62 | struct stop_element : public element, public styleable { 63 | real offset = 0; 64 | 65 | void accept(visitor& v) override; 66 | void accept(const_visitor& v) const override; 67 | 68 | std::string_view get_id() const override 69 | { 70 | return this->id; 71 | } 72 | 73 | constexpr static std::string_view tag = "stop"sv; 74 | 75 | std::string_view get_tag() const override 76 | { 77 | return tag; 78 | } 79 | }; 80 | 81 | std::string spread_method_to_string() const; 82 | 83 | std::string_view get_id() const override 84 | { 85 | return this->id; 86 | } 87 | }; 88 | 89 | struct linear_gradient_element : public gradient { 90 | // TODO: change default unit to percent? 91 | length x1 = length(0, length_unit::unknown); 92 | length y1 = length(0, length_unit::unknown); 93 | length x2 = length(std::centi::den, length_unit::unknown); 94 | length y2 = length(0, length_unit::unknown); 95 | 96 | void accept(visitor& v) override; 97 | void accept(const_visitor& v) const override; 98 | 99 | constexpr static std::string_view tag = "linearGradient"sv; 100 | 101 | std::string_view get_tag() const override 102 | { 103 | return tag; 104 | } 105 | }; 106 | 107 | struct radial_gradient_element : public gradient { 108 | // TODO: change default unit to percent? 109 | length cx = length(real(std::centi::den) / 2, length_unit::unknown); 110 | length cy = length(real(std::centi::den) / 2, length_unit::unknown); 111 | length r = length(real(std::centi::den) / 2, length_unit::unknown); 112 | length fx = length(real(std::centi::den) / 2, length_unit::unknown); 113 | length fy = length(real(std::centi::den) / 2, length_unit::unknown); 114 | 115 | void accept(visitor& v) override; 116 | void accept(const_visitor& v) const override; 117 | 118 | constexpr static std::string_view tag = "radialGradient"sv; 119 | 120 | std::string_view get_tag() const override 121 | { 122 | return tag; 123 | } 124 | }; 125 | 126 | } // namespace svgdom 127 | -------------------------------------------------------------------------------- /src/svgdom/elements/image_element.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "image_element.hpp" 29 | 30 | #include "../visitor.hpp" 31 | 32 | using namespace svgdom; 33 | 34 | void image_element::accept(visitor& v) 35 | { 36 | v.visit(*this); 37 | } 38 | 39 | void image_element::accept(const_visitor& v) const 40 | { 41 | v.visit(*this); 42 | } 43 | -------------------------------------------------------------------------------- /src/svgdom/elements/image_element.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include "aspect_ratioed.hpp" 31 | #include "element.hpp" 32 | #include "rectangle.hpp" 33 | #include "referencing.hpp" 34 | #include "styleable.hpp" 35 | #include "transformable.hpp" 36 | 37 | namespace svgdom { 38 | 39 | using namespace std::string_view_literals; 40 | 41 | struct image_element : 42 | public element, 43 | public styleable, 44 | public transformable, 45 | public rectangle, 46 | public referencing, 47 | public aspect_ratioed { 48 | void accept(visitor& v) override; 49 | void accept(const_visitor& v) const override; 50 | 51 | std::string_view get_id() const override 52 | { 53 | return this->id; 54 | } 55 | 56 | constexpr static std::string_view tag = "image"sv; 57 | 58 | std::string_view get_tag() const override 59 | { 60 | return tag; 61 | } 62 | }; 63 | 64 | } // namespace svgdom 65 | -------------------------------------------------------------------------------- /src/svgdom/elements/rectangle.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "rectangle.hpp" 29 | 30 | using namespace svgdom; 31 | -------------------------------------------------------------------------------- /src/svgdom/elements/rectangle.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include "../length.hpp" 31 | 32 | namespace svgdom { 33 | 34 | /** 35 | * @brief A rectangular element. 36 | */ 37 | struct rectangle { 38 | length x = length(0, length_unit::unknown); 39 | length y = length(0, length_unit::unknown); 40 | 41 | constexpr static auto default_dimension = 100; 42 | 43 | length width = length(default_dimension, length_unit::unknown); 44 | length height = length(default_dimension, length_unit::unknown); 45 | 46 | rectangle() = default; 47 | 48 | constexpr rectangle(length x, length y, length width, length height) : 49 | x(x), 50 | y(y), 51 | width(width), 52 | height(height) 53 | {} 54 | 55 | bool is_x_specified() const noexcept 56 | { 57 | return this->x.unit != length_unit::unknown; 58 | } 59 | 60 | bool is_y_specified() const noexcept 61 | { 62 | return this->y.unit != length_unit::unknown; 63 | } 64 | 65 | bool is_width_specified() const noexcept 66 | { 67 | return this->width.unit != length_unit::unknown; 68 | } 69 | 70 | bool is_height_specified() const noexcept 71 | { 72 | return this->height.unit != length_unit::unknown; 73 | } 74 | }; 75 | 76 | } // namespace svgdom 77 | -------------------------------------------------------------------------------- /src/svgdom/elements/referencing.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "referencing.hpp" 29 | 30 | #include "../util.hxx" 31 | 32 | using namespace svgdom; 33 | 34 | std::string referencing::get_local_id_from_iri() const 35 | { 36 | return iri_to_local_id(this->iri); 37 | } 38 | -------------------------------------------------------------------------------- /src/svgdom/elements/referencing.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | namespace svgdom { 33 | 34 | /** 35 | * @brief an element which can reference another element. 36 | */ 37 | // TODO: why lint complains here on macos? 38 | // NOLINTNEXTLINE(bugprone-exception-escape, "error: an exception may be thrown in function") 39 | struct referencing { 40 | /** 41 | * @brief IRI reference. 42 | * This variable holds the IRI string. 43 | */ 44 | std::string iri; 45 | 46 | /** 47 | * @brief Get ID of the locally referenced element. 48 | * @return ID of the locally referenced element. 49 | * @return Empty string if this Referencing does not refer to any element or the reference is not local IRI. 50 | */ 51 | std::string get_local_id_from_iri() const; 52 | }; 53 | 54 | } // namespace svgdom 55 | -------------------------------------------------------------------------------- /src/svgdom/elements/structurals.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "structurals.hpp" 29 | 30 | #include "../util.hxx" 31 | #include "../visitor.hpp" 32 | 33 | using namespace svgdom; 34 | 35 | r4::vector2 svg_element::get_dimensions(real dpi) const noexcept 36 | { 37 | constexpr auto default_svg_width = 300; 38 | constexpr auto default_svg_height = 150; 39 | 40 | real w = this->width.to_px(dpi); 41 | real h = this->height.to_px(dpi); 42 | 43 | if (w <= 0) { 44 | if (this->view_box[2] > 0) { 45 | w = this->view_box[2]; 46 | } else { 47 | w = default_svg_width; 48 | } 49 | } 50 | 51 | if (h <= 0) { 52 | if (this->view_box[3] > 0) { 53 | h = this->view_box[3]; 54 | } else { 55 | h = default_svg_height; 56 | } 57 | } 58 | 59 | return {w, h}; 60 | } 61 | 62 | real svg_element::aspect_ratio(real dpi) const 63 | { 64 | auto wh = this->get_dimensions(dpi); 65 | 66 | if (wh[0] <= 0 || wh[1] <= 0) { 67 | return 0; 68 | } 69 | 70 | return wh[0] / wh[1]; 71 | } 72 | 73 | void g_element::accept(visitor& v) 74 | { 75 | v.visit(*this); 76 | } 77 | 78 | void g_element::accept(const_visitor& v) const 79 | { 80 | v.visit(*this); 81 | } 82 | 83 | void svg_element::accept(visitor& v) 84 | { 85 | v.visit(*this); 86 | } 87 | 88 | void svg_element::accept(const_visitor& v) const 89 | { 90 | v.visit(*this); 91 | } 92 | 93 | void symbol_element::accept(visitor& v) 94 | { 95 | v.visit(*this); 96 | } 97 | 98 | void symbol_element::accept(const_visitor& v) const 99 | { 100 | v.visit(*this); 101 | } 102 | 103 | void defs_element::accept(visitor& v) 104 | { 105 | v.visit(*this); 106 | } 107 | 108 | void defs_element::accept(const_visitor& v) const 109 | { 110 | v.visit(*this); 111 | } 112 | 113 | void use_element::accept(visitor& v) 114 | { 115 | v.visit(*this); 116 | } 117 | 118 | void use_element::accept(const_visitor& v) const 119 | { 120 | v.visit(*this); 121 | } 122 | 123 | void mask_element::accept(visitor& v) 124 | { 125 | v.visit(*this); 126 | } 127 | 128 | void mask_element::accept(const_visitor& v) const 129 | { 130 | v.visit(*this); 131 | } 132 | -------------------------------------------------------------------------------- /src/svgdom/elements/style.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "style.hpp" 29 | 30 | #include "../visitor.hpp" 31 | 32 | using namespace svgdom; 33 | 34 | void style_element::accept(visitor& v) 35 | { 36 | v.visit(*this); 37 | } 38 | 39 | void style_element::accept(const_visitor& v) const 40 | { 41 | v.visit(*this); 42 | } 43 | -------------------------------------------------------------------------------- /src/svgdom/elements/style.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | #include 33 | 34 | #include "element.hpp" 35 | #include "styleable.hpp" 36 | 37 | namespace svgdom { 38 | 39 | using namespace std::string_view_literals; 40 | 41 | // TODO: why lint complains here on macos? 42 | // NOLINTNEXTLINE(bugprone-exception-escape, "error: an exception may be thrown in function") 43 | struct style_element : public element { 44 | cssom::sheet css; 45 | 46 | struct css_style_value : public cssom::property_value_base { 47 | style_value value; 48 | }; 49 | 50 | constexpr static std::string_view tag = "style"sv; 51 | 52 | std::string_view get_tag() const override 53 | { 54 | return tag; 55 | } 56 | 57 | void accept(visitor& v) override; 58 | void accept(const_visitor& v) const override; 59 | }; 60 | 61 | } // namespace svgdom 62 | -------------------------------------------------------------------------------- /src/svgdom/elements/text_element.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "text_element.hpp" 29 | 30 | #include "../visitor.hpp" 31 | 32 | using namespace svgdom; 33 | 34 | void text_element::accept(visitor& v) 35 | { 36 | v.visit(*this); 37 | } 38 | 39 | void text_element::accept(const_visitor& v) const 40 | { 41 | v.visit(*this); 42 | } 43 | -------------------------------------------------------------------------------- /src/svgdom/elements/text_element.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include "container.hpp" 31 | #include "element.hpp" 32 | #include "styleable.hpp" 33 | #include "transformable.hpp" 34 | 35 | namespace svgdom { 36 | 37 | using namespace std::string_view_literals; 38 | 39 | class text_positioning 40 | { 41 | public: 42 | // TODO: attributes x, y, dx, dy, rotate are not implemented yet. 43 | }; 44 | 45 | // TODO: why lint complains here on macos? 46 | // NOLINTNEXTLINE(bugprone-exception-escape, "error: an exception may be thrown in function") 47 | class text_element : public element, public container, public styleable, public transformable, public text_positioning 48 | { 49 | public: 50 | // TODO: attributes lengthAdjust, textLength are not implemented yet. 51 | 52 | void accept(visitor& v) override; 53 | void accept(const_visitor& v) const override; 54 | 55 | std::string_view get_id() const override 56 | { 57 | return this->id; 58 | } 59 | 60 | constexpr static std::string_view tag = "text"sv; 61 | 62 | std::string_view get_tag() const override 63 | { 64 | return tag; 65 | } 66 | }; 67 | 68 | } // namespace svgdom 69 | -------------------------------------------------------------------------------- /src/svgdom/elements/transformable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | #include 32 | 33 | #include "../config.hpp" 34 | 35 | namespace svgdom { 36 | 37 | /** 38 | * @brief An element which has 'transform' attribute or similar. 39 | */ 40 | struct transformable { 41 | struct transformation { 42 | enum class type { 43 | matrix, 44 | translate, 45 | scale, 46 | rotate, 47 | skewx, 48 | skewy 49 | }; 50 | 51 | type type_v; 52 | 53 | real a; 54 | 55 | real& angle() noexcept 56 | { 57 | return this->a; 58 | } 59 | 60 | const real& angle() const noexcept 61 | { 62 | return this->a; 63 | } 64 | 65 | real b; 66 | 67 | real& x() noexcept 68 | { 69 | return this->b; 70 | } 71 | 72 | const real& x() const noexcept 73 | { 74 | return this->b; 75 | } 76 | 77 | real c; 78 | 79 | real& y() noexcept 80 | { 81 | return this->c; 82 | } 83 | 84 | const real& y() const noexcept 85 | { 86 | return this->c; 87 | } 88 | 89 | real d, e, f; 90 | }; 91 | 92 | std::vector transformations; 93 | 94 | std::string transformations_to_string() const; 95 | 96 | static decltype(transformable::transformations) parse(std::string_view str); 97 | }; 98 | 99 | } // namespace svgdom 100 | -------------------------------------------------------------------------------- /src/svgdom/elements/view_boxed.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "view_boxed.hpp" 29 | 30 | #include 31 | 32 | #include "../util.hxx" 33 | 34 | using namespace svgdom; 35 | 36 | decltype(view_boxed::view_box) view_boxed::parse_view_box(std::string_view str) 37 | { 38 | decltype(view_boxed::view_box) ret; 39 | 40 | try { 41 | utki::string_parser p(str); 42 | 43 | for (auto& r : ret) { 44 | p.skip_whitespaces_and_comma(); 45 | r = p.read_number(); 46 | } 47 | } catch (std::invalid_argument&) { 48 | return { 49 | {-1, -1, -1, -1} 50 | }; 51 | } 52 | 53 | return ret; 54 | } 55 | 56 | std::string view_boxed::view_box_to_string() const 57 | { 58 | std::stringstream s; 59 | bool is_first = true; 60 | for (const auto& e : this->view_box) { 61 | if (is_first) { 62 | is_first = false; 63 | } else { 64 | s << " "; 65 | } 66 | s << e; 67 | } 68 | return s.str(); 69 | } 70 | -------------------------------------------------------------------------------- /src/svgdom/elements/view_boxed.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | #include 32 | 33 | #include "../config.hpp" 34 | 35 | namespace svgdom { 36 | 37 | /** 38 | * @brief SVG element which has viewBox attribute. 39 | * Provides handling of viewBox and preserveAspectRatio attributes. 40 | */ 41 | struct view_boxed { 42 | std::array view_box{ 43 | {-1, -1, -1, -1} 44 | }; 45 | 46 | std::string view_box_to_string() const; 47 | 48 | static decltype(view_box) parse_view_box(std::string_view str); 49 | 50 | bool is_view_box_specified() const 51 | { 52 | return this->view_box[2] >= 0; // width is not negative 53 | } 54 | }; 55 | 56 | } // namespace svgdom 57 | -------------------------------------------------------------------------------- /src/svgdom/length.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "length.hpp" 29 | 30 | #include 31 | #include 32 | 33 | #include "util.hxx" 34 | 35 | using namespace svgdom; 36 | 37 | length length::parse(std::string_view str) 38 | { 39 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) 40 | length ret; 41 | 42 | utki::string_parser p(str); 43 | 44 | ret.value = p.read_number(); 45 | 46 | auto unit = p.read_word(); 47 | 48 | if (unit.empty()) { 49 | ret.unit = length_unit::number; 50 | } else if (unit == "%") { 51 | ret.unit = length_unit::percent; 52 | } else if (unit == "em") { 53 | ret.unit = length_unit::em; 54 | } else if (unit == "ex") { 55 | ret.unit = length_unit::ex; 56 | } else if (unit == "px") { 57 | ret.unit = length_unit::px; 58 | } else if (unit == "cm") { 59 | ret.unit = length_unit::cm; 60 | } else if (unit == "mm") { 61 | ret.unit = length_unit::mm; 62 | } else if (unit == "in") { 63 | ret.unit = length_unit::in; 64 | } else if (unit == "pt") { 65 | ret.unit = length_unit::pt; 66 | } else if (unit == "pc") { 67 | ret.unit = length_unit::pc; 68 | } else { 69 | ret.unit = length_unit::unknown; 70 | } 71 | 72 | return ret; 73 | } 74 | 75 | real length::to_px(real dpi) const noexcept 76 | { 77 | constexpr auto pt_per_inch = 72; 78 | constexpr auto pc_per_inch = 6; 79 | 80 | switch (this->unit) { 81 | default: 82 | return 0; 83 | case svgdom::length_unit::number: 84 | case svgdom::length_unit::px: 85 | return this->value; 86 | case svgdom::length_unit::in: 87 | return std::ceil(this->value * dpi); 88 | case svgdom::length_unit::cm: 89 | return std::ceil(this->value * (dpi / real(utki::cm_per_inch))); 90 | case svgdom::length_unit::mm: 91 | return std::ceil(this->value * (dpi / real(utki::mm_per_inch))); 92 | case svgdom::length_unit::pt: 93 | return std::ceil(this->value * (dpi / real(pt_per_inch))); 94 | case svgdom::length_unit::pc: 95 | return std::ceil(this->value * (dpi / real(pc_per_inch))); 96 | case svgdom::length_unit::em: 97 | case svgdom::length_unit::ex: 98 | // em and ex depend on the font size. Text is not supported by svgdom, so return 0 size. 99 | return 0; 100 | } 101 | } 102 | 103 | std::ostream& operator<<(std::ostream& s, const length& l) 104 | { 105 | s << l.value; 106 | 107 | switch (l.unit) { 108 | case length_unit::unknown: 109 | case length_unit::number: 110 | default: 111 | break; 112 | case length_unit::percent: 113 | s << "%"; 114 | break; 115 | case length_unit::em: 116 | s << "em"; 117 | break; 118 | case length_unit::ex: 119 | s << "ex"; 120 | break; 121 | case length_unit::px: 122 | s << "px"; 123 | break; 124 | case length_unit::cm: 125 | s << "cm"; 126 | break; 127 | case length_unit::mm: 128 | s << "mm"; 129 | break; 130 | case length_unit::in: 131 | s << "in"; 132 | break; 133 | case length_unit::pt: 134 | s << "pt"; 135 | break; 136 | case length_unit::pc: 137 | s << "pc"; 138 | break; 139 | } 140 | 141 | return s; 142 | } 143 | -------------------------------------------------------------------------------- /src/svgdom/length.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | #include "config.hpp" 33 | 34 | #ifdef IN 35 | # undef IN 36 | #endif 37 | 38 | namespace svgdom { 39 | 40 | enum class length_unit { 41 | unknown, 42 | number, 43 | percent, 44 | em, 45 | ex, 46 | px, 47 | cm, 48 | in, 49 | pt, 50 | pc, 51 | mm 52 | }; 53 | 54 | /** 55 | * @brief SVG attribute value of type 'length'. 56 | */ 57 | struct length { 58 | real value; 59 | length_unit unit; 60 | 61 | static length parse(std::string_view str); 62 | 63 | length() = default; 64 | 65 | constexpr length(real value, length_unit unit = length_unit::number) : 66 | value(value), 67 | unit(unit) 68 | {} 69 | 70 | bool is_valid() const noexcept 71 | { 72 | return this->unit != length_unit::unknown; 73 | } 74 | 75 | bool is_percent() const noexcept 76 | { 77 | return this->unit == length_unit::percent; 78 | } 79 | 80 | real to_px(real dpi) const noexcept; 81 | 82 | bool operator!=(const length& l) const 83 | { 84 | return this->value != l.value || (this->unit != l.unit && this->value != real(0)); 85 | } 86 | }; 87 | 88 | } // namespace svgdom 89 | 90 | std::ostream& operator<<(std::ostream& s, const svgdom::length& l); 91 | -------------------------------------------------------------------------------- /src/svgdom/malformed_svg_error.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | namespace svgdom { 33 | 34 | class malformed_svg_error : public std::invalid_argument 35 | { 36 | public: 37 | malformed_svg_error(const std::string& message) : 38 | std::invalid_argument(message) 39 | {} 40 | }; 41 | 42 | } // namespace svgdom 43 | -------------------------------------------------------------------------------- /src/svgdom/util.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "util.hxx" 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | using namespace svgdom; 38 | 39 | std::string svgdom::trim_tail(std::string_view s) 40 | { 41 | const auto t = s.find_last_not_of(" \t\n\r"); 42 | if (t == std::string::npos) { 43 | return std::string(s); 44 | } 45 | 46 | return std::string(s.substr(0, t + 1)); 47 | } 48 | 49 | std::string svgdom::iri_to_local_id(std::string_view iri) 50 | { 51 | if (iri.size() != 0 && iri[0] == '#') { 52 | return std::string(iri.substr(1)); 53 | } 54 | return {}; 55 | } 56 | 57 | coordinate_units svgdom::parse_coordinate_units(std::string_view s) 58 | { 59 | if (s == "userSpaceOnUse") { 60 | return coordinate_units::user_space_on_use; 61 | } else if (s == "objectBoundingBox") { 62 | return coordinate_units::object_bounding_box; 63 | } 64 | return coordinate_units::unknown; 65 | } 66 | 67 | std::string svgdom::coordinate_units_to_string(coordinate_units u) 68 | { 69 | switch (u) { 70 | default: 71 | return {}; 72 | case coordinate_units::object_bounding_box: 73 | return "objectBoundingBox"; 74 | case coordinate_units::user_space_on_use: 75 | return "userSpaceOnUse"; 76 | } 77 | } 78 | 79 | r4::vector2 svgdom::parse_number_and_optional_number(std::string_view s, r4::vector2 defaults) 80 | { 81 | r4::vector2 ret; 82 | 83 | utki::string_parser p(s); 84 | 85 | try { 86 | ret[0] = p.read_number(); 87 | } catch (std::invalid_argument&) { 88 | return defaults; 89 | } 90 | 91 | p.skip_whitespaces_and_comma(); 92 | 93 | try { 94 | ret[1] = p.read_number(); 95 | } catch (std::invalid_argument&) { 96 | ret[1] = defaults[1]; 97 | } 98 | 99 | return ret; 100 | } 101 | 102 | std::string svgdom::number_and_optional_number_to_string(std::array non, real optional_number_default) 103 | { 104 | std::stringstream ss; 105 | 106 | ss << non[0]; 107 | 108 | if (non[1] != optional_number_default) { 109 | ss << " " << non[1]; 110 | } 111 | 112 | return ss.str(); 113 | } 114 | -------------------------------------------------------------------------------- /src/svgdom/util.hxx: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | 37 | #include "elements/coordinate_units.hpp" 38 | 39 | #include "config.hpp" 40 | 41 | namespace svgdom { 42 | 43 | std::string trim_tail(std::string_view s); 44 | 45 | std::string iri_to_local_id(std::string_view iri); 46 | 47 | coordinate_units parse_coordinate_units(std::string_view s); 48 | 49 | std::string coordinate_units_to_string(coordinate_units u); 50 | 51 | r4::vector2 parse_number_and_optional_number(std::string_view s, r4::vector2 defaults); 52 | 53 | std::string number_and_optional_number_to_string(std::array non, real optional_number_default); 54 | 55 | } // namespace svgdom 56 | -------------------------------------------------------------------------------- /src/svgdom/util/cloner.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include "../visitor.hpp" 31 | 32 | namespace svgdom { 33 | /** 34 | * @brief clone visitor. 35 | * A visitor which allows cloning of Elements (and their children). 36 | */ 37 | class cloner : virtual public svgdom::const_visitor 38 | { 39 | svgdom::container root; 40 | svgdom::container* cur_parent = &root; 41 | 42 | void clone_children(const svgdom::container& e, svgdom::container& clone); 43 | 44 | public: 45 | /** 46 | * @brief Clone root element as element_type. 47 | * @return std::unique where element_type is element type of root. 48 | */ 49 | template 50 | std::unique_ptr get_clone_as() 51 | { 52 | if (root.children.size() != 1) { 53 | return nullptr; 54 | } 55 | auto ret = std::unique_ptr(dynamic_cast(root.children.back().get())); 56 | if (ret) { 57 | [[maybe_unused]] auto ptr = root.children.back().release(); 58 | } 59 | root.children.clear(); 60 | return ret; 61 | } 62 | 63 | void visit(const svgdom::path_element& e) override; 64 | void visit(const svgdom::rect_element& e) override; 65 | void visit(const svgdom::circle_element& e) override; 66 | void visit(const svgdom::ellipse_element& e) override; 67 | void visit(const svgdom::line_element& e) override; 68 | void visit(const svgdom::polyline_element& e) override; 69 | void visit(const svgdom::polygon_element& e) override; 70 | void visit(const svgdom::g_element& e) override; 71 | void visit(const svgdom::svg_element& e) override; 72 | void visit(const svgdom::symbol_element& e) override; 73 | void visit(const svgdom::use_element& e) override; 74 | void visit(const svgdom::defs_element& e) override; 75 | void visit(const svgdom::gradient::stop_element& e) override; 76 | void visit(const svgdom::linear_gradient_element& e) override; 77 | void visit(const svgdom::radial_gradient_element& e) override; 78 | void visit(const svgdom::filter_element& e) override; 79 | void visit(const svgdom::fe_gaussian_blur_element& e) override; 80 | void visit(const svgdom::image_element& e) override; 81 | void visit(const svgdom::style_element& e) override; 82 | }; 83 | 84 | } // namespace svgdom 85 | -------------------------------------------------------------------------------- /src/svgdom/util/finder_by_class.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | #include 33 | 34 | #include "../elements/element.hpp" 35 | 36 | #include "style_stack.hpp" 37 | 38 | namespace svgdom { 39 | 40 | class finder_by_class 41 | { 42 | public: 43 | finder_by_class(const svgdom::element& root); 44 | 45 | utki::span find(const std::string& cls) const noexcept; 46 | 47 | /** 48 | * @brief Get elements-by-class-name cache size. 49 | * @return number of cached elements. 50 | */ 51 | size_t size() const noexcept 52 | { 53 | return this->cache.size(); 54 | } 55 | 56 | private: 57 | std::unordered_map> cache; 58 | }; 59 | 60 | } // namespace svgdom 61 | -------------------------------------------------------------------------------- /src/svgdom/util/finder_by_id.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "finder_by_id.hpp" 29 | 30 | #include 31 | 32 | #include "../visitor.hpp" 33 | 34 | using namespace svgdom; 35 | 36 | namespace { 37 | class cache_creator : virtual public svgdom::const_visitor 38 | { 39 | private: 40 | void add_to_cache(const svgdom::element& e) 41 | { 42 | if (!e.id.empty()) { 43 | this->cache.insert(std::make_pair(e.id, &e)); 44 | } 45 | } 46 | 47 | public: 48 | std::unordered_map cache; 49 | 50 | void default_visit(const element& e) override 51 | { 52 | this->add_to_cache(e); 53 | } 54 | }; 55 | } // namespace 56 | 57 | finder_by_id::finder_by_id(const svgdom::element& root) : 58 | cache([&root]() { 59 | cache_creator cc; 60 | 61 | root.accept(cc); 62 | 63 | return std::move(cc.cache); 64 | }()) 65 | {} 66 | 67 | const svgdom::element* finder_by_id::find(const std::string& id) const noexcept 68 | { 69 | if (id.length() == 0) { 70 | return nullptr; 71 | } 72 | 73 | auto i = this->cache.find(id); 74 | if (i == this->cache.end()) { 75 | return nullptr; 76 | } 77 | 78 | return i->second; 79 | } 80 | -------------------------------------------------------------------------------- /src/svgdom/util/finder_by_id.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | #include "../elements/element.hpp" 33 | 34 | #include "style_stack.hpp" 35 | 36 | namespace svgdom { 37 | 38 | class finder_by_id 39 | { 40 | public: 41 | finder_by_id(const svgdom::element& root); 42 | 43 | const element* find(const std::string& id) const noexcept; 44 | 45 | /** 46 | * @brief Get element-by-id cache size. 47 | * @return number of cached elements. 48 | */ 49 | size_t size() const noexcept 50 | { 51 | return this->cache.size(); 52 | } 53 | 54 | private: 55 | std::unordered_map cache; 56 | }; 57 | 58 | } // namespace svgdom 59 | -------------------------------------------------------------------------------- /src/svgdom/util/finder_by_tag.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #include "finder_by_tag.hpp" 29 | 30 | #include 31 | 32 | #include 33 | 34 | #include "../visitor.hpp" 35 | 36 | using namespace svgdom; 37 | 38 | namespace { 39 | class cache_creator : virtual public svgdom::const_visitor 40 | { 41 | private: 42 | void add_to_cache(const svgdom::element& e) 43 | { 44 | if (!e.get_tag().empty()) { 45 | auto it = this->cache.find(e.get_tag()); 46 | 47 | if (it != this->cache.end()) { 48 | it->second.push_back(&e); 49 | } else { 50 | std::vector elements = {&e}; 51 | this->cache.insert(std::make_pair(e.get_tag(), std::move(elements))); 52 | } 53 | } 54 | } 55 | 56 | public: 57 | std::unordered_map> cache; 58 | 59 | void default_visit(const element& e) override 60 | { 61 | this->add_to_cache(e); 62 | } 63 | }; 64 | } // namespace 65 | 66 | finder_by_tag::finder_by_tag(const svgdom::element& root) : 67 | cache([&root]() { 68 | cache_creator cc; 69 | 70 | root.accept(cc); 71 | 72 | return std::move(cc.cache); 73 | }()) 74 | {} 75 | 76 | utki::span finder_by_tag::find(std::string_view tag_name) const noexcept 77 | { 78 | if (tag_name.length() == 0) { 79 | return {}; 80 | } 81 | 82 | auto i = this->cache.find(tag_name); 83 | if (i == this->cache.end()) { 84 | return {}; 85 | } 86 | 87 | return utki::make_span(i->second); 88 | } 89 | -------------------------------------------------------------------------------- /src/svgdom/util/finder_by_tag.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | #include 33 | 34 | #include "../elements/element.hpp" 35 | 36 | #include "style_stack.hpp" 37 | 38 | namespace svgdom { 39 | 40 | class finder_by_tag 41 | { 42 | public: 43 | finder_by_tag(const svgdom::element& root); 44 | 45 | utki::span find(std::string_view tag_name) const noexcept; 46 | 47 | /** 48 | * @brief Get elements-by-tag-name cache size. 49 | * @return number of cached elements. 50 | */ 51 | size_t size() const noexcept 52 | { 53 | return this->cache.size(); 54 | } 55 | 56 | private: 57 | std::unordered_map> cache; 58 | }; 59 | 60 | } // namespace svgdom 61 | -------------------------------------------------------------------------------- /src/svgdom/util/style_stack.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | #include 33 | 34 | #include "../elements/container.hpp" 35 | #include "../elements/styleable.hpp" 36 | 37 | namespace svgdom { 38 | class style_stack 39 | { 40 | public: 41 | std::vector> stack; 42 | 43 | private: 44 | std::vector> css; 45 | 46 | class crawler : public cssom::xml_dom_crawler 47 | { 48 | utki::span stack; 49 | 50 | decltype(stack)::reverse_iterator iter; 51 | 52 | public: 53 | crawler(decltype(stack) stack); 54 | 55 | const cssom::styleable& get() override; 56 | 57 | bool move_up() override; 58 | bool move_left() override; 59 | void reset() override; 60 | }; 61 | 62 | const svgdom::style_value* get_css_style_property(size_t stack_depth, svgdom::style_property p) const; 63 | 64 | public: 65 | const svgdom::style_value* get_style_property(svgdom::style_property p) const; 66 | 67 | void add_css(const cssom::sheet& css_doc); 68 | 69 | class push 70 | { 71 | style_stack& ss; 72 | 73 | public: 74 | push(style_stack& ss, const svgdom::styleable& s); 75 | 76 | push(const push&) = delete; 77 | push& operator=(const push&) = delete; 78 | 79 | push(push&&) = delete; 80 | push& operator=(push&&) = delete; 81 | 82 | ~push() noexcept; 83 | }; 84 | }; 85 | 86 | } // namespace svgdom 87 | -------------------------------------------------------------------------------- /src/svgdom/util/style_stack_cache.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2015-2025 Ivan Gagis 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | */ 25 | 26 | /* ================ LICENSE END ================ */ 27 | 28 | #pragma once 29 | 30 | #include 31 | 32 | #include "../elements/element.hpp" 33 | 34 | #include "style_stack.hpp" 35 | 36 | namespace svgdom { 37 | 38 | class style_stack_cache 39 | { 40 | public: 41 | style_stack_cache(const svgdom::element& root); 42 | 43 | const style_stack* find(const std::string& id) const noexcept; 44 | 45 | /** 46 | * @brief Get style-stack-by-id cache size. 47 | * @return number of cached elements. 48 | */ 49 | size_t size() const noexcept 50 | { 51 | return this->cache.size(); 52 | } 53 | 54 | private: 55 | std::unordered_map cache; 56 | }; 57 | 58 | } // namespace svgdom 59 | -------------------------------------------------------------------------------- /tests/.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: | 2 | -cppcoreguidelines-avoid-magic-numbers 3 | InheritParentConfig: true 4 | -------------------------------------------------------------------------------- /tests/makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | 3 | $(eval $(prorab-include-subdirs)) 4 | -------------------------------------------------------------------------------- /tests/unit/cloner.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../../src/svgdom/util/cloner.hpp" 5 | 6 | namespace{ 7 | const tst::set set("cloner", [](auto& suite){ 8 | suite.add("basic_test", [](){ 9 | auto dom_original = std::make_unique(); 10 | 11 | auto path = std::make_unique(); 12 | 13 | svgdom::path_element::step step{}; 14 | 15 | step.type_v = svgdom::path_element::step::type::move_abs; 16 | step.x = 0; 17 | step.y = 0; 18 | path->path.push_back(step); 19 | 20 | step.type_v = svgdom::path_element::step::type::line_abs; 21 | step.x = 0; 22 | step.y = 300; 23 | path->path.push_back(step); 24 | 25 | step.type_v = svgdom::path_element::step::type::line_abs; 26 | step.x = 300; 27 | step.y = 300; 28 | path->path.push_back(step); 29 | 30 | step.type_v = svgdom::path_element::step::type::line_abs; 31 | step.x = 300; 32 | step.y = 0; 33 | path->path.push_back(step); 34 | 35 | dom_original->children.push_back(std::move(path)); 36 | 37 | svgdom::cloner cloner; 38 | 39 | dom_original->accept(cloner); 40 | 41 | std::unique_ptr dom_clone = cloner.get_clone_as(); 42 | 43 | std::string dom_original_str = dom_original->to_string(); 44 | 45 | std::string dom_clone_str = dom_clone->to_string(); 46 | 47 | tst::check_eq(dom_original_str, dom_clone_str, SL); 48 | }); 49 | }); 50 | } 51 | -------------------------------------------------------------------------------- /tests/unit/custom_element.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../../src/svgdom/visitor.hpp" 5 | #include "../../src/svgdom/util/stream_writer.hpp" 6 | 7 | using namespace std::string_view_literals; 8 | 9 | // TODO: why lint complains here on macos? 10 | // NOLINTNEXTLINE(bugprone-exception-escape, "error: an exception may be thrown in function") 11 | struct custom_element : public svgdom::element{ 12 | void accept(svgdom::const_visitor& visitor) const override; 13 | void accept(svgdom::visitor& visitor) override; 14 | 15 | constexpr static std::string_view tag = "custom_element"sv; 16 | 17 | std::string_view get_tag()const override{ 18 | return tag; 19 | } 20 | }; 21 | 22 | class custom_visitor : virtual public svgdom::const_visitor{ 23 | public: 24 | using svgdom::const_visitor::visit; 25 | 26 | virtual void visit(const custom_element& e){ 27 | this->default_visit(e); 28 | } 29 | }; 30 | 31 | void custom_element::accept(svgdom::const_visitor& visitor) const{ 32 | if(auto v = dynamic_cast(&visitor)){ 33 | v->visit(*this); 34 | }else{ 35 | visitor.default_visit(*this); 36 | } 37 | } 38 | 39 | void custom_element::accept(svgdom::visitor& visitor){ 40 | visitor.default_visit(*this); 41 | } 42 | 43 | class custom_stream_writer : 44 | public svgdom::stream_writer, 45 | public custom_visitor 46 | { 47 | public: 48 | custom_stream_writer(std::ostream& s) : 49 | svgdom::stream_writer(s) 50 | {} 51 | 52 | using svgdom::stream_writer::visit; 53 | 54 | void visit(const custom_element& e)override{ 55 | this->set_name("custom"); 56 | this->add_attribute("customAttrib1", "value1"); 57 | this->add_attribute("customAttrib2", "value2"); 58 | this->write(); 59 | } 60 | }; 61 | 62 | namespace{ 63 | const tst::set set("custom_element", [](auto& suite){ 64 | suite.add("basic_test", [](){ 65 | auto dom = std::make_unique(); 66 | 67 | svgdom::path_element path; 68 | 69 | svgdom::path_element::step step{}; 70 | 71 | step.type_v = svgdom::path_element::step::type::move_abs; 72 | step.x = 0; 73 | step.y = 0; 74 | path.path.push_back(step); 75 | 76 | step.type_v = svgdom::path_element::step::type::line_abs; 77 | step.x = 0; 78 | step.y = 300; 79 | path.path.push_back(step); 80 | 81 | step.type_v = svgdom::path_element::step::type::line_abs; 82 | step.x = 300; 83 | step.y = 300; 84 | path.path.push_back(step); 85 | 86 | step.type_v = svgdom::path_element::step::type::line_abs; 87 | step.x = 300; 88 | step.y = 0; 89 | path.path.push_back(step); 90 | 91 | dom->children.push_back(std::make_unique(path)); 92 | 93 | dom->children.push_back(std::make_unique()); 94 | 95 | std::stringstream ss; 96 | custom_stream_writer writer(ss); 97 | 98 | dom->accept(writer); 99 | 100 | auto str = ss.str(); 101 | 102 | utki::log([&](auto&o){o << str << std::endl;}); 103 | 104 | tst::check(str.find(R"(xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1")") != std::string::npos, SL); 105 | tst::check(str.find(R"()") != std::string::npos, SL); 106 | }); 107 | }); 108 | } 109 | -------------------------------------------------------------------------------- /tests/unit/edit_dom_visitor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../../src/svgdom/visitor.hpp" 5 | 6 | // visitor to remove all 'line' elements 7 | class editing_visitor : public svgdom::visitor{ 8 | std::vector> elementsToRemove; 9 | 10 | void add_to_remove(){ 11 | if(!this->cur_parent()){ 12 | // root element does not have parent, nowhere to remove it from 13 | return; 14 | } 15 | this->elementsToRemove.emplace_back(this->cur_parent(), this->cur_iter()); 16 | } 17 | 18 | public: 19 | void visit(svgdom::svg_element& e) override{ 20 | this->relay_accept(e); 21 | } 22 | 23 | void visit(svgdom::g_element& e) override{ 24 | this->relay_accept(e); 25 | } 26 | 27 | void visit(svgdom::path_element& e) override{ 28 | e.id = "new id for path"; 29 | } 30 | 31 | void visit(svgdom::line_element& e) override{ 32 | this->add_to_remove(); 33 | } 34 | 35 | void remove_lines(){ 36 | for(auto& p : this->elementsToRemove){ 37 | tst::check(p.first, SL); 38 | p.first->children.erase(p.second); 39 | } 40 | } 41 | }; 42 | 43 | namespace{ 44 | const tst::set set("edit_dom_visitor", [](auto& suite){ 45 | suite.add("basic_test", [](){ 46 | auto dom = std::make_unique(); 47 | 48 | svgdom::path_element path; 49 | 50 | svgdom::path_element::step step{}; 51 | 52 | step.type_v = svgdom::path_element::step::type::move_abs; 53 | step.x = 0; 54 | step.y = 0; 55 | path.path.push_back(step); 56 | 57 | step.type_v = svgdom::path_element::step::type::line_abs; 58 | step.x = 0; 59 | step.y = 300; 60 | path.path.push_back(step); 61 | 62 | dom->children.push_back(std::make_unique(path)); 63 | 64 | dom->children.push_back(std::make_unique()); 65 | 66 | { 67 | auto g = std::make_unique(); 68 | g->children.push_back(std::make_unique()); 69 | 70 | dom->children.push_back(std::move(g)); 71 | } 72 | 73 | editing_visitor visitor; 74 | 75 | dom->accept(visitor); 76 | 77 | tst::check_eq(dom->children.size(), size_t(3), SL); 78 | tst::check(dynamic_cast(dom->children.begin()->get()), SL); 79 | tst::check(dynamic_cast((++dom->children.begin())->get()), SL); 80 | tst::check(dynamic_cast((++++dom->children.begin())->get()), SL); 81 | tst::check_eq(dynamic_cast((++++dom->children.begin())->get())->children.size(), size_t(1), SL); 82 | tst::check( 83 | dynamic_cast(dynamic_cast((++++dom->children.begin())->get())->children.front().get()), 84 | SL 85 | ); 86 | 87 | visitor.remove_lines(); 88 | 89 | tst::check_eq(dom->children.size(), size_t(2), [&](auto&o){o << "dom->children.size() = " << dom->children.size();}, SL); 90 | tst::check(dynamic_cast(dom->children.begin()->get()), SL); 91 | tst::check(dynamic_cast((++dom->children.begin())->get()), SL); 92 | tst::check_eq(dynamic_cast((++dom->children.begin())->get())->children.size(), size_t(0), SL); 93 | }); 94 | }); 95 | } 96 | -------------------------------------------------------------------------------- /tests/unit/finders.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "../../src/svgdom/dom.hpp" 7 | #include "../../src/svgdom/util/finder_by_id.hpp" 8 | #include "../../src/svgdom/util/finder_by_class.hpp" 9 | #include "../../src/svgdom/util/finder_by_tag.hpp" 10 | #include "../../src/svgdom/util/casters.hpp" 11 | 12 | struct fixture{ 13 | std::unique_ptr dom; 14 | fixture(){ 15 | // NOLINTNEXTLINE(bugprone-unused-return-value, "false positive") 16 | this->dom = svgdom::load(papki::fs_file("samples_data/finders.svg")); 17 | tst::check(this->dom != nullptr, SL); 18 | tst::check(this->dom->children.size() != 0, SL); 19 | } 20 | }; 21 | namespace{ 22 | const tst::set set("finders", [](auto& suite){ 23 | suite.add("finder_by_id",[](){ 24 | fixture f; 25 | 26 | svgdom::finder_by_id finder_by_id(*f.dom); 27 | 28 | tst::check(finder_by_id.size() == 2, [&](auto&o){o << "finder_by_id size = " << finder_by_id.size();}, SL); 29 | 30 | for(const auto& id : {"id1", "id2"}){ 31 | auto element_by_id = finder_by_id.find(id); 32 | tst::check(element_by_id != nullptr, [&](auto&o){o << "element-by-id not found, searched id = " << id;}, SL); 33 | tst::check(element_by_id->id == id, SL); // NOLINT(clang-analyzer-core.NonNullParamChecker): element_by_id is not nullptr as per previous check 34 | } 35 | 36 | tst::check(finder_by_id.find("non_existing_id") == nullptr, SL); 37 | }); 38 | 39 | suite.add("finder_by_class", [](){ 40 | fixture f; 41 | 42 | svgdom::finder_by_class finder_by_class_name(*f.dom); 43 | tst::check(finder_by_class_name.size() == 2, [&](auto&o){o << "finder_by_class_name size = " << finder_by_class_name.size();}, SL); 44 | 45 | for(const auto& cls : {"class1", "class2"}){ 46 | auto elements_by_class_name = finder_by_class_name.find(cls); 47 | tst::check(!elements_by_class_name.empty(), [&](auto&o){o << "elements-by-class not found, searched class = " << cls;}, SL); 48 | tst::check(elements_by_class_name.size() == 1, SL); 49 | 50 | // check that found element is styleable and it has the searched class 51 | auto s = svgdom::cast_to_styleable(elements_by_class_name.front()); 52 | tst::check(s, SL); 53 | auto& c = s->classes; 54 | tst::check(std::find(c.begin(), c.end(), cls) != c.end(), SL); 55 | } 56 | 57 | tst::check(finder_by_class_name.find("non_existent_class").empty(), SL); 58 | }); 59 | 60 | suite.add("finder_by_tag", [](){ 61 | fixture f; 62 | 63 | svgdom::finder_by_tag finder_by_tag_name(*f.dom); 64 | tst::check(finder_by_tag_name.size() == 3, [&](auto&o){o << "finder_by_tag_name size = " << finder_by_tag_name.size();}, SL); 65 | 66 | for(const auto& t : {"circle", "svg", "rect"}){ 67 | auto elements_by_tag_name = finder_by_tag_name.find(t); 68 | tst::check(!elements_by_tag_name.empty(), [&](auto&o){o << "elements-by-tag not found";}, SL); 69 | tst::check(elements_by_tag_name.size() == 1, SL); 70 | tst::check(elements_by_tag_name.front()->get_tag() == t, SL); 71 | } 72 | 73 | tst::check(finder_by_tag_name.find("non_existent_tag").empty(), SL); 74 | }); 75 | }); 76 | } 77 | -------------------------------------------------------------------------------- /tests/unit/makefile: -------------------------------------------------------------------------------- 1 | include prorab.mk 2 | include prorab-test.mk 3 | 4 | $(eval $(call prorab-config, ../../config)) 5 | 6 | this_no_install := true 7 | 8 | this_name := tests 9 | 10 | this_srcs := $(call prorab-src-dir, .) 11 | 12 | this_ldflags += -L ../../src/out/$(c) 13 | this_ldlibs += -ltst -lutki -lsvgdom -lpapki 14 | 15 | this_cxxflags += -isystem ../../src 16 | 17 | $(eval $(prorab-build-app)) 18 | 19 | $(eval $(call prorab-depend, $(prorab_this_name), ../../src/out/$(c)/libsvgdom$(dot_so))) 20 | 21 | this_test_cmd := $(prorab_this_name) --jobs=$(prorab_nproc) --junit-out=out/$(c)/junit.xml 22 | this_test_deps := $(prorab_this_name) 23 | this_test_ld_path := ../../src/out/$(c) 24 | 25 | $(eval $(prorab-test)) 26 | 27 | $(eval $(call prorab-include, ../../src/makefile)) 28 | -------------------------------------------------------------------------------- /tests/unit/misc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std::string_literals; 14 | using namespace std::string_view_literals; 15 | 16 | namespace{ 17 | // NOLINTNEXTLINE(cppcoreguidelines-interfaces-global-init) 18 | const tst::set set("misc", [](tst::suite& suite){ 19 | suite.add( 20 | "read_from_istream", 21 | [](){ 22 | std::ifstream ist; 23 | ist.open("samples_data/tiger.svg"); 24 | auto dom = svgdom::load(ist); 25 | tst::check(dom, SL); 26 | } 27 | ); 28 | 29 | suite.add( 30 | "read_from_fs_file", 31 | [](){ 32 | auto dom = svgdom::load(papki::fs_file("samples_data/tiger.svg")); 33 | tst::check(dom, SL); 34 | } 35 | ); 36 | 37 | suite.add( 38 | "read_svg_with_unclosed_svg_tag_should_fail", 39 | [](){ 40 | auto str = R"qwertyuiop( 41 | 42 | 43 | 44 | 45 | 46 | 47 | )qwertyuiop"sv; 48 | 49 | bool thrown = false; 50 | try{ 51 | auto dom = svgdom::load(str); 52 | tst::check(false, SL); 53 | }catch(std::invalid_argument& e){ 54 | thrown = true; 55 | } 56 | tst::check(thrown, SL); 57 | } 58 | ); 59 | 60 | suite.add("issue_test_1", [](){ 61 | auto svg_str = R"qwertyuiop( 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | )qwertyuiop"sv; 78 | 79 | auto dom = svgdom::load(utki::make_span(svg_str)); 80 | tst::check(dom, SL); 81 | 82 | svgdom::style_stack style_stack; 83 | 84 | svgdom::finder_by_id finder(*dom); 85 | 86 | { 87 | auto elem = finder.find("css"); 88 | tst::check(elem, SL); 89 | 90 | auto style_elem = dynamic_cast(elem); 91 | tst::check(style_elem, SL); 92 | 93 | style_stack.add_css(style_elem->css); 94 | } 95 | 96 | auto elem = finder.find("rect-2"); 97 | tst::check(elem, SL); 98 | 99 | auto styleable = dynamic_cast(elem); 100 | tst::check(styleable, SL); 101 | 102 | svgdom::style_stack::push style_push(style_stack, *styleable); 103 | 104 | auto fill = style_stack.get_style_property(svgdom::style_property::fill); 105 | tst::check(fill, SL); 106 | tst::check(std::holds_alternative(*fill), SL); 107 | tst::check_eq(std::get(*fill), 0x6a5047U, SL); 108 | }); 109 | }); 110 | } 111 | -------------------------------------------------------------------------------- /tests/unit/performance.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include "../../src/svgdom/dom.hpp" 8 | 9 | namespace{ 10 | const tst::set set("performance", [](auto& suite){ 11 | suite.add("basic_test", [](){ 12 | auto load_start = utki::get_ticks_ms(); 13 | 14 | auto buf = papki::fs_file("samples_data/back.svg").load(); 15 | 16 | utki::log([&](auto&o){o << "SVG loaded in " << float(utki::get_ticks_ms() - load_start) / 1000.0f << " sec." << std::endl;}); 17 | 18 | for(unsigned i = 0; i != 5; ++i){ 19 | auto parse_start = utki::get_ticks_ms(); 20 | auto dom = svgdom::load(utki::make_span(buf)); 21 | tst::check(dom != nullptr, SL); 22 | utki::log([&](auto&o){o << "SVG parsed in " << float(utki::get_ticks_ms() - parse_start) / 1000.0f << " sec." << std::endl;}); 23 | } 24 | }); 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /tests/unit/samples.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if CFG_COMPILER != CFG_COMPILER_MSVC 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include "../../src/svgdom/dom.hpp" 17 | 18 | namespace{ 19 | const std::string data_dir = "samples_data/"; 20 | } 21 | 22 | namespace{ 23 | // NOLINTNEXTLINE(cppcoreguidelines-interfaces-global-init) 24 | const tst::set set("samples", [](tst::suite& suite){ 25 | // make sure the locale does not affect parsing (decimal delimiter can be "." or "," in different locales) 26 | // so, set DE locale which has "," to make sure it does not affect the parsing 27 | if(!std::setlocale(LC_ALL, "de_DE.UTF-8")){ 28 | utki::log([](auto& o){o << "WARNING: failed to set locale de_DE.UTF-8, perhaps the locale is not installed. Testing that locale does not affect parsing will not be done." << std::endl;}); 29 | } 30 | 31 | std::vector files = utki::linq(papki::fs_file(data_dir).list_dir()) 32 | .where( 33 | [&](const auto& f){ 34 | static const std::regex suffix_regex("^.*\\.svg$"); 35 | return std::regex_match(f, suffix_regex); 36 | } 37 | ) 38 | .get(); 39 | 40 | suite.add( 41 | "sample", 42 | std::move(files), 43 | [](auto& p){ 44 | auto in_file_name = data_dir + p; 45 | 46 | auto dom = svgdom::load(papki::fs_file(in_file_name)); 47 | tst::check(dom, SL); 48 | 49 | auto str = dom->to_string(); 50 | 51 | papki::vector_file out_file; 52 | { 53 | papki::file::guard file_guard(out_file, papki::mode::create); 54 | out_file.write(utki::make_span(str)); 55 | } 56 | 57 | auto out_data = out_file.reset_data(); 58 | 59 | papki::fs_file cmp_file(in_file_name + ".cmp"); 60 | 61 | decltype(out_data) cmp_data; 62 | 63 | try{ 64 | cmp_data = cmp_file.load(); 65 | }catch(std::system_error&){ 66 | std::cout << "Failed to load '" << cmp_file.path() << "' file" << std::endl; 67 | } 68 | 69 | if(out_data != cmp_data){ 70 | papki::fs_file failed_file(in_file_name + ".out"); 71 | 72 | { 73 | papki::file::guard file_guard(failed_file, papki::mode::create); 74 | failed_file.write(out_data); 75 | } 76 | 77 | tst::check(false, SL) << "parsed file is not as expected: " << in_file_name; 78 | } 79 | } 80 | ); 81 | }); 82 | } 83 | 84 | #endif // ~ non-MSVC compiler or MSVC tools is v142+ 85 | -------------------------------------------------------------------------------- /tests/unit/samples_data/background_test.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/unit/samples_data/background_test.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/unit/samples_data/cubic_smooth.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 15 | 16 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tests/unit/samples_data/cubic_smooth.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/unit/samples_data/dasharray1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/unit/samples_data/dasharray1.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/unit/samples_data/dashoffset1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 11 | 12 | 15 | 16 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/unit/samples_data/dashoffset1.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tests/unit/samples_data/defs_style_2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/unit/samples_data/defs_style_2.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/unit/samples_data/finders.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/unit/samples_data/finders.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/unit/samples_data/gauge_arrow_shadow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 29 | 33 | 34 | 35 | 58 | 60 | 61 | 63 | image/svg+xml 64 | 66 | 67 | 68 | 69 | 70 | 75 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /tests/unit/samples_data/gauge_arrow_shadow.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /tests/unit/samples_data/gradient-transform-rotate-compare.svg: -------------------------------------------------------------------------------- 1 | 4 | Rotating Gradients in User Space vs Bounding Box 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 22 | 23 | 24 | 26 | 28 | 30 | 31 | 33 | 35 | 36 | -------------------------------------------------------------------------------- /tests/unit/samples_data/gradient-transform-rotate-compare.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/unit/samples_data/interface-ethernet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/unit/samples_data/interface-ethernet.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /tests/unit/samples_data/masking.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/unit/samples_data/masking.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/unit/samples_data/mouse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /tests/unit/samples_data/mouse.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /tests/unit/samples_data/rect_no_width_height.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 14 | 15 | -------------------------------------------------------------------------------- /tests/unit/samples_data/rect_no_width_height.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/unit/samples_data/rgb_percent.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 10 | 16 | 17 | -------------------------------------------------------------------------------- /tests/unit/samples_data/rgb_percent.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/unit/samples_data/simple_css.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /tests/unit/samples_data/simple_css.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/unit/samples_data/six_ball.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /tests/unit/samples_data/six_ball.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tests/unit/samples_data/symbol.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/unit/samples_data/symbol.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/unit/samples_data/text.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | Example tspan01 - using tspan to change visual attributes 7 | 8 | 9 | 10 | You are 11 | not 12 | a banana. 13 | 14 | 15 | 16 | 17 | 19 | 20 | -------------------------------------------------------------------------------- /tests/unit/samples_data/text.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /tests/unit/samples_data/use.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/unit/samples_data/use.svg.cmp: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/unit/style_stack_cache.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include "../../src/svgdom/dom.hpp" 8 | #include "../../src/svgdom/visitor.hpp" 9 | #include "../../src/svgdom/util/style_stack_cache.hpp" 10 | 11 | namespace{ 12 | const tst::set set("style_stack_cache", [](auto& suite){ 13 | suite.add( 14 | "basic_test", 15 | [](){ 16 | auto load_start = utki::get_ticks_ms(); 17 | 18 | auto dom = svgdom::load(papki::fs_file("samples_data/back.svg")); 19 | 20 | tst::check(dom != nullptr, SL); 21 | tst::check(dom->children.size() != 0, SL); 22 | 23 | utki::log([&](auto&o){o << "SVG loaded in " << float(utki::get_ticks_ms() - load_start) / 1000.0f << " sec." << std::endl;}); 24 | 25 | auto search_start = utki::get_ticks_ms(); 26 | 27 | class traverse_visitor : public svgdom::const_visitor{ 28 | public: 29 | svgdom::style_stack_cache style_stack_cache; 30 | 31 | traverse_visitor(const svgdom::element& root) : style_stack_cache(root){} 32 | 33 | void visit(const svgdom::use_element& e)override{ 34 | tst::check(this->style_stack_cache.find(e.get_local_id_from_iri()), [&](auto&o){o << "element not found for id = " << e.get_local_id_from_iri();}, SL); 35 | } 36 | } visitor(*dom); 37 | 38 | dom->accept(visitor); 39 | 40 | auto search_duration = utki::get_ticks_ms() - search_start; 41 | 42 | tst::check(search_duration < 5000, [&](auto&o){o << "search duration was longer than 5 seconds, actual duration = " << search_duration;}, SL); 43 | 44 | utki::log([&](auto&o){o << "SVG searched in " << float(search_duration) / 1000.0f << " sec." << std::endl;}); 45 | 46 | tst::check(visitor.style_stack_cache.size() == 17763, [&](auto&o){o << "visitor.style_stack_cache.size() = " << visitor.style_stack_cache.size();}, SL); 47 | } 48 | ); 49 | }); 50 | } 51 | -------------------------------------------------------------------------------- /tests/unit/to_string.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../../src/svgdom/elements/structurals.hpp" 5 | #include "../../src/svgdom/elements/shapes.hpp" 6 | 7 | const tst::set to_string_tests("to_string", [](auto& suite){ 8 | suite.add( 9 | "path_element_is_converted_to_string", 10 | [](){ 11 | auto dom = std::make_unique(); 12 | 13 | svgdom::path_element path; 14 | 15 | svgdom::path_element::step step{}; 16 | 17 | path.styles[svgdom::style_property::fill] = svgdom::make_style_value(0x42, 0x13, 0xfe); 18 | 19 | step.type_v = svgdom::path_element::step::type::move_abs; 20 | step.x = 0; 21 | step.y = 0; 22 | path.path.push_back(step); 23 | 24 | step.type_v = svgdom::path_element::step::type::line_abs; 25 | step.x = 0; 26 | step.y = 300; 27 | path.path.push_back(step); 28 | 29 | step.type_v = svgdom::path_element::step::type::line_abs; 30 | step.x = 300; 31 | step.y = 300; 32 | path.path.push_back(step); 33 | 34 | step.type_v = svgdom::path_element::step::type::line_abs; 35 | step.x = 300; 36 | step.y = 0; 37 | path.path.push_back(step); 38 | 39 | dom->children.push_back(std::make_unique(path)); 40 | 41 | auto str = dom->to_string(); 42 | 43 | LOG([&](auto&o){o << str << '\n';}) 44 | 45 | tst::check(str.find(R"(xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1")") != std::string::npos, SL); 46 | 47 | tst::check(str.find("fill:#4213fe") != std::string::npos, SL); 48 | } 49 | ); 50 | 51 | }); 52 | -------------------------------------------------------------------------------- /wiki/Main.adoc: -------------------------------------------------------------------------------- 1 | = WiKi main page 2 | 3 | == Istallation 4 | :package_name: svgdom 5 | 6 | . Setup your OS-preferred package system repo following link:https://github.com/cppfw/wiki/blob/main/enable_repo/enable_repo.adoc[this manual] 7 | . Install package 8 | + 9 | - **vcpkg** (multi-OS): `{package_name}` 10 | - **conan** (multi-OS): `{package_name}` 11 | - **deb** (Linux): `lib{package_name}-dev` 12 | - **homebrew** (MacOS X): `lib{package_name}` 13 | - **Android**: `io.github.cppfw:{package_name}` 14 | - **cocoapods** (iOS): `{package_name}` 15 | - **Msys2** (Windows): `mingw-w64-i686-{package_name}`, `mingw-w64-x86_64-{package_name}` 16 | - **Nuget** (Windows, Visual Studio): `lib{package_name}` 17 | -------------------------------------------------------------------------------- /xcode/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/cppfw/cocoapods-repo.git' 2 | 3 | project 'svgdom/svgdom.xcodeproj' 4 | 5 | platform :ios, '12.0' 6 | 7 | target "svgdom" do 8 | pod 'utki', '>= 1.1.164' 9 | pod 'papki', '>= 1.0.93' 10 | pod 'mikroxml', '>= 0.1.36' 11 | pod 'cssom', '>= 0.1.19' 12 | pod 'r4', '>= 1.0.53' 13 | end 14 | -------------------------------------------------------------------------------- /xcode/svgdom/svgdom.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /xcode/svgdom/svgdom.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /xcode/svgdom/svgdom.xcodeproj/project.xcworkspace/xcuserdata/ivan.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cppfw/svgdom/86a25a04f6fac1949c09d3a0ecfe871a9859a555/xcode/svgdom/svgdom.xcodeproj/project.xcworkspace/xcuserdata/ivan.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /xcode/svgdom/svgdom.xcodeproj/xcuserdata/ivan.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | svgdom.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /xcode/svgdom/svgdom/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | --------------------------------------------------------------------------------