From b9e900cb70c920f3444520c36896270201314730 Mon Sep 17 00:00:00 2001 From: Vasilito Date: Mon, 11 May 2026 10:09:48 +0100 Subject: [PATCH] fix: update KF6 cross-compile build configurations Patch CMakeLists.txt across 15 KF6 packages for Redox cross-compile. Add kf6-ksvg recipe for KWin dependency chain. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../kde/kf6-attica/source/CMakeLists.txt | 2 +- .../kde/kf6-kcmutils/source/CMakeLists.txt | 2 + .../kf6-kcolorscheme/source/CMakeLists.txt | 2 + .../kde/kf6-kcompletion/source/CMakeLists.txt | 2 + .../kf6-kconfigwidgets/source/CMakeLists.txt | 2 + .../kf6-kdeclarative/source/CMakeLists.txt | 2 +- .../kde/kf6-kiconthemes/source/CMakeLists.txt | 2 + .../kde/kf6-kitemmodels/source/CMakeLists.txt | 2 +- .../kf6-kitemmodels/source/src/CMakeLists.txt | 2 +- .../kde/kf6-kitemviews/source/CMakeLists.txt | 2 + .../kde/kf6-kjobwidgets/source/CMakeLists.txt | 2 + .../kf6-ksvg/source/.git-blame-ignore-revs | 6 + local/recipes/kde/kf6-ksvg/source/.gitignore | 28 + .../kde/kf6-ksvg/source/.gitlab-ci.yml | 10 + local/recipes/kde/kf6-ksvg/source/.kde-ci.yml | 15 + .../kde/kf6-ksvg/source/CMakeLists.txt | 128 ++ .../kde/kf6-ksvg/source/KF6SvgConfig.cmake.in | 17 + .../kf6-ksvg/source/LICENSES/BSD-2-Clause.txt | 22 + .../kf6-ksvg/source/LICENSES/BSD-3-Clause.txt | 26 + .../kde/kf6-ksvg/source/LICENSES/CC0-1.0.txt | 121 ++ .../kf6-ksvg/source/LICENSES/GPL-2.0-only.txt | 319 +++++ .../source/LICENSES/GPL-2.0-or-later.txt | 319 +++++ .../kf6-ksvg/source/LICENSES/GPL-3.0-only.txt | 625 +++++++++ .../source/LICENSES/LGPL-2.0-or-later.txt | 446 +++++++ .../source/LICENSES/LGPL-2.1-only.txt | 467 +++++++ .../source/LICENSES/LGPL-2.1-or-later.txt | 468 +++++++ .../source/LICENSES/LGPL-3.0-only.txt | 163 +++ .../LICENSES/LicenseRef-KDE-Accepted-GPL.txt | 12 + .../LICENSES/LicenseRef-KDE-Accepted-LGPL.txt | 12 + .../LICENSES/LicenseRef-Qt-Commercial.txt | 7 + .../source/LICENSES/Qt-LGPL-exception-1.1.txt | 21 + .../recipes/kde/kf6-ksvg/source/Mainpage.dox | 67 + local/recipes/kde/kf6-ksvg/source/README.md | 43 + .../kf6-ksvg/source/autotests/CMakeLists.txt | 29 + .../source/autotests/data/background.svgz | Bin 0 -> 2879 bytes .../metadata.desktop | 19 + .../data/plasma/desktoptheme/testtheme/colors | 120 ++ .../plasma/desktoptheme/testtheme/element.svg | 1 + .../desktoptheme/testtheme/metadata.json | 18 + .../desktoptheme/testtheme/opaque/element.svg | 1 + .../plasma/desktoptheme/testtheme/plasmarc | 5 + .../source/autotests/framesvgtest.cpp | 131 ++ .../kf6-ksvg/source/autotests/framesvgtest.h | 35 + .../kde/kf6-ksvg/source/docs/Doxyfile.local | 7 + .../recipes/kde/kf6-ksvg/source/metainfo.yaml | 19 + .../kde/kf6-ksvg/source/po/ar/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/ast/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/bg/libksvg6.po | 30 + .../kde/kf6-ksvg/source/po/ca/libksvg6.po | 30 + .../source/po/ca@valencia/libksvg6.po | 30 + .../kde/kf6-ksvg/source/po/cs/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/de/libksvg6.po | 30 + .../kde/kf6-ksvg/source/po/en_GB/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/eo/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/es/libksvg6.po | 30 + .../kde/kf6-ksvg/source/po/eu/libksvg6.po | 31 + .../kde/kf6-ksvg/source/po/fi/libksvg6.po | 27 + .../kde/kf6-ksvg/source/po/fr/libksvg6.po | 26 + .../kde/kf6-ksvg/source/po/gl/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/he/libksvg6.po | 29 + .../kde/kf6-ksvg/source/po/hi/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/hu/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/ia/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/is/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/it/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/ja/libksvg6.po | 25 + .../kde/kf6-ksvg/source/po/ka/libksvg6.po | 29 + .../kde/kf6-ksvg/source/po/ko/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/lt/libksvg6.po | 29 + .../kde/kf6-ksvg/source/po/nl/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/nn/libksvg6.po | 30 + .../kde/kf6-ksvg/source/po/pl/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/pt_BR/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/ro/libksvg6.po | 29 + .../kde/kf6-ksvg/source/po/ru/libksvg6.po | 29 + .../kde/kf6-ksvg/source/po/sa/libksvg6.po | 29 + .../kde/kf6-ksvg/source/po/sk/libksvg6.po | 26 + .../kde/kf6-ksvg/source/po/sl/libksvg6.po | 29 + .../kde/kf6-ksvg/source/po/sv/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/tr/libksvg6.po | 28 + .../kde/kf6-ksvg/source/po/uk/libksvg6.po | 29 + .../kde/kf6-ksvg/source/po/zh_CN/libksvg6.po | 28 + .../kde/kf6-ksvg/source/src/CMakeLists.txt | 12 + .../kde/kf6-ksvg/source/src/Messages.sh | 11 + .../src/declarativeimports/CMakeLists.txt | 27 + .../src/declarativeimports/framesvgitem.cpp | 782 +++++++++++ .../src/declarativeimports/framesvgitem.h | 328 +++++ .../declarativeimports/imagetexturescache.cpp | 58 + .../declarativeimports/imagetexturescache.h | 48 + .../declarativeimports/managedtexturenode.cpp | 17 + .../declarativeimports/managedtexturenode.h | 27 + .../source/src/declarativeimports/svgitem.cpp | 292 +++++ .../source/src/declarativeimports/svgitem.h | 139 ++ .../source/src/declarativeimports/types.h | 45 + .../kde/kf6-ksvg/source/src/ksvg/.krazy | 2 + .../kf6-ksvg/source/src/ksvg/CMakeLists.txt | 119 ++ .../kde/kf6-ksvg/source/src/ksvg/README | 22 + .../kde/kf6-ksvg/source/src/ksvg/framesvg.cpp | 1043 +++++++++++++++ .../kde/kf6-ksvg/source/src/ksvg/framesvg.h | 420 ++++++ .../kde/kf6-ksvg/source/src/ksvg/imageset.cpp | 263 ++++ .../kde/kf6-ksvg/source/src/ksvg/imageset.h | 209 +++ .../src/ksvg/private/framesvg_helpers.h | 83 ++ .../source/src/ksvg/private/framesvg_p.h | 202 +++ .../source/src/ksvg/private/imageset_p.cpp | 774 +++++++++++ .../source/src/ksvg/private/imageset_p.h | 179 +++ .../kf6-ksvg/source/src/ksvg/private/svg_p.h | 176 +++ .../kde/kf6-ksvg/source/src/ksvg/svg.cpp | 1159 +++++++++++++++++ .../kde/kf6-ksvg/source/src/ksvg/svg.h | 567 ++++++++ .../kf6-ksvg/source/src/tools/CMakeLists.txt | 1 + .../source/src/tools/apply-stylesheet.sh | 287 ++++ .../source/src/tools/currentColorFillFix.sh | 23 + .../inkscape extensions/plasmarename.inx | 15 + .../tools/inkscape extensions/plasmarename.py | 65 + .../tools/split-plasma-svgs/CMakeLists.txt | 16 + .../split-plasma-svgs/split-plasma-svgs.cpp | 304 +++++ .../kde/kf6-ksvg/source/tests/frames.qml | 40 + .../kf6-ksvg/source/tests/selected_svg.qml | 35 + .../kde/kf6-ksvg/source/tests/shadows.qml | 44 + .../kde/kf6-ksvg/source/tests/testborders.qml | 93 ++ .../kf6-ktextwidgets/source/CMakeLists.txt | 2 + .../source/src/kswitchlanguagedialog_p.cpp | 6 +- .../recipes/kde/kf6-pty/source/CMakeLists.txt | 6 +- .../kde/kf6-solid/source/CMakeLists.txt | 2 +- recipes/kde/kf6-ksvg | 1 + 124 files changed, 12733 insertions(+), 11 deletions(-) create mode 100644 local/recipes/kde/kf6-ksvg/source/.git-blame-ignore-revs create mode 100644 local/recipes/kde/kf6-ksvg/source/.gitignore create mode 100644 local/recipes/kde/kf6-ksvg/source/.gitlab-ci.yml create mode 100644 local/recipes/kde/kf6-ksvg/source/.kde-ci.yml create mode 100644 local/recipes/kde/kf6-ksvg/source/CMakeLists.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/KF6SvgConfig.cmake.in create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/BSD-2-Clause.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/BSD-3-Clause.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/CC0-1.0.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/GPL-2.0-only.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/GPL-2.0-or-later.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/GPL-3.0-only.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-2.0-or-later.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-2.1-only.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-2.1-or-later.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-3.0-only.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/LicenseRef-KDE-Accepted-GPL.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/LicenseRef-KDE-Accepted-LGPL.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/LicenseRef-Qt-Commercial.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/LICENSES/Qt-LGPL-exception-1.1.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/Mainpage.dox create mode 100644 local/recipes/kde/kf6-ksvg/source/README.md create mode 100644 local/recipes/kde/kf6-ksvg/source/autotests/CMakeLists.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/autotests/data/background.svgz create mode 100644 local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/test_old_metadata_format_theme/metadata.desktop create mode 100644 local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/colors create mode 100644 local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/element.svg create mode 100644 local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/metadata.json create mode 100644 local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/opaque/element.svg create mode 100644 local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/plasmarc create mode 100644 local/recipes/kde/kf6-ksvg/source/autotests/framesvgtest.cpp create mode 100644 local/recipes/kde/kf6-ksvg/source/autotests/framesvgtest.h create mode 100644 local/recipes/kde/kf6-ksvg/source/docs/Doxyfile.local create mode 100644 local/recipes/kde/kf6-ksvg/source/metainfo.yaml create mode 100644 local/recipes/kde/kf6-ksvg/source/po/ar/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/ast/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/bg/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/ca/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/ca@valencia/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/cs/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/de/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/en_GB/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/eo/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/es/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/eu/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/fi/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/fr/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/gl/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/he/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/hi/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/hu/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/ia/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/is/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/it/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/ja/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/ka/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/ko/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/lt/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/nl/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/nn/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/pl/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/pt_BR/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/ro/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/ru/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/sa/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/sk/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/sl/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/sv/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/tr/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/uk/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/po/zh_CN/libksvg6.po create mode 100644 local/recipes/kde/kf6-ksvg/source/src/CMakeLists.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/src/Messages.sh create mode 100644 local/recipes/kde/kf6-ksvg/source/src/declarativeimports/CMakeLists.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/src/declarativeimports/framesvgitem.cpp create mode 100644 local/recipes/kde/kf6-ksvg/source/src/declarativeimports/framesvgitem.h create mode 100644 local/recipes/kde/kf6-ksvg/source/src/declarativeimports/imagetexturescache.cpp create mode 100644 local/recipes/kde/kf6-ksvg/source/src/declarativeimports/imagetexturescache.h create mode 100644 local/recipes/kde/kf6-ksvg/source/src/declarativeimports/managedtexturenode.cpp create mode 100644 local/recipes/kde/kf6-ksvg/source/src/declarativeimports/managedtexturenode.h create mode 100644 local/recipes/kde/kf6-ksvg/source/src/declarativeimports/svgitem.cpp create mode 100644 local/recipes/kde/kf6-ksvg/source/src/declarativeimports/svgitem.h create mode 100644 local/recipes/kde/kf6-ksvg/source/src/declarativeimports/types.h create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/.krazy create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/CMakeLists.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/README create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/framesvg.cpp create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/framesvg.h create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/imageset.cpp create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/imageset.h create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/private/framesvg_helpers.h create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/private/framesvg_p.h create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/private/imageset_p.cpp create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/private/imageset_p.h create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/private/svg_p.h create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/svg.cpp create mode 100644 local/recipes/kde/kf6-ksvg/source/src/ksvg/svg.h create mode 100644 local/recipes/kde/kf6-ksvg/source/src/tools/CMakeLists.txt create mode 100755 local/recipes/kde/kf6-ksvg/source/src/tools/apply-stylesheet.sh create mode 100755 local/recipes/kde/kf6-ksvg/source/src/tools/currentColorFillFix.sh create mode 100644 local/recipes/kde/kf6-ksvg/source/src/tools/inkscape extensions/plasmarename.inx create mode 100644 local/recipes/kde/kf6-ksvg/source/src/tools/inkscape extensions/plasmarename.py create mode 100644 local/recipes/kde/kf6-ksvg/source/src/tools/split-plasma-svgs/CMakeLists.txt create mode 100644 local/recipes/kde/kf6-ksvg/source/src/tools/split-plasma-svgs/split-plasma-svgs.cpp create mode 100644 local/recipes/kde/kf6-ksvg/source/tests/frames.qml create mode 100644 local/recipes/kde/kf6-ksvg/source/tests/selected_svg.qml create mode 100644 local/recipes/kde/kf6-ksvg/source/tests/shadows.qml create mode 100644 local/recipes/kde/kf6-ksvg/source/tests/testborders.qml create mode 120000 recipes/kde/kf6-ksvg diff --git a/local/recipes/kde/kf6-attica/source/CMakeLists.txt b/local/recipes/kde/kf6-attica/source/CMakeLists.txt index 45aea38cf0..9b4fe40855 100644 --- a/local/recipes/kde/kf6-attica/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-attica/source/CMakeLists.txt @@ -57,7 +57,7 @@ add_subdirectory(src) # Enable unit testing if (BUILD_TESTING) -############################### add_subdirectory(autotests) +################################# add_subdirectory(autotests) add_subdirectory(tests) endif () diff --git a/local/recipes/kde/kf6-kcmutils/source/CMakeLists.txt b/local/recipes/kde/kf6-kcmutils/source/CMakeLists.txt index d66e73e229..b553483ede 100644 --- a/local/recipes/kde/kf6-kcmutils/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kcmutils/source/CMakeLists.txt @@ -115,6 +115,8 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) # shall we use DBus? # enabled per default on Linux & BSD systems diff --git a/local/recipes/kde/kf6-kcolorscheme/source/CMakeLists.txt b/local/recipes/kde/kf6-kcolorscheme/source/CMakeLists.txt index 305fdfc398..936720cf9e 100644 --- a/local/recipes/kde/kf6-kcolorscheme/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kcolorscheme/source/CMakeLists.txt @@ -93,6 +93,8 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].") diff --git a/local/recipes/kde/kf6-kcompletion/source/CMakeLists.txt b/local/recipes/kde/kf6-kcompletion/source/CMakeLists.txt index baea985662..d1d4881da0 100644 --- a/local/recipes/kde/kf6-kcompletion/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kcompletion/source/CMakeLists.txt @@ -84,6 +84,8 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(KF6Codecs ${KF_DEP_VERSION} REQUIRED) find_package(KF6Config ${KF_DEP_VERSION} REQUIRED) diff --git a/local/recipes/kde/kf6-kconfigwidgets/source/CMakeLists.txt b/local/recipes/kde/kf6-kconfigwidgets/source/CMakeLists.txt index 9c22de8b2e..ffa4f2adbf 100644 --- a/local/recipes/kde/kf6-kconfigwidgets/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kconfigwidgets/source/CMakeLists.txt @@ -87,6 +87,8 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) # shall we use DBus? # enabled per default on Linux & BSD systems diff --git a/local/recipes/kde/kf6-kdeclarative/source/CMakeLists.txt b/local/recipes/kde/kf6-kdeclarative/source/CMakeLists.txt index b21e024a54..47458d1663 100644 --- a/local/recipes/kde/kf6-kdeclarative/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kdeclarative/source/CMakeLists.txt @@ -32,7 +32,7 @@ find_package(KF6GuiAddons ${KF_DEP_VERSION} REQUIRED) if(NOT WIN32 AND NOT APPLE AND NOT ANDROID AND NOT REDOX) -###################################################### find_package(KF6GlobalAccel ${KF_DEP_VERSION} REQUIRED) +######################################################## find_package(KF6GlobalAccel ${KF_DEP_VERSION} REQUIRED) set(HAVE_KGLOBALACCEL TRUE) else() set(HAVE_KGLOBALACCEL FALSE) diff --git a/local/recipes/kde/kf6-kiconthemes/source/CMakeLists.txt b/local/recipes/kde/kf6-kiconthemes/source/CMakeLists.txt index c9511dc8f8..9b516742e0 100644 --- a/local/recipes/kde/kf6-kiconthemes/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kiconthemes/source/CMakeLists.txt @@ -106,6 +106,8 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6Svg ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) # shall we use DBus? diff --git a/local/recipes/kde/kf6-kitemmodels/source/CMakeLists.txt b/local/recipes/kde/kf6-kitemmodels/source/CMakeLists.txt index 205cc057de..85c7a57350 100644 --- a/local/recipes/kde/kf6-kitemmodels/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kitemmodels/source/CMakeLists.txt @@ -38,7 +38,7 @@ set_package_properties(Qt6Qml PROPERTIES ) if (TARGET Qt6::Qml) -################################# include(ECMQmlModule) +################################### include(ECMQmlModule) endif() set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].") diff --git a/local/recipes/kde/kf6-kitemmodels/source/src/CMakeLists.txt b/local/recipes/kde/kf6-kitemmodels/source/src/CMakeLists.txt index 2dbf94d3d8..3cebee1172 100644 --- a/local/recipes/kde/kf6-kitemmodels/source/src/CMakeLists.txt +++ b/local/recipes/kde/kf6-kitemmodels/source/src/CMakeLists.txt @@ -1,6 +1,6 @@ add_subdirectory(core) if (TARGET Qt6::Qml) -################################ add_subdirectory(qml) +################################## add_subdirectory(qml) endif() ecm_qt_install_logging_categories( diff --git a/local/recipes/kde/kf6-kitemviews/source/CMakeLists.txt b/local/recipes/kde/kf6-kitemviews/source/CMakeLists.txt index a6ca6c1f7f..710a2b073b 100644 --- a/local/recipes/kde/kf6-kitemviews/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kitemviews/source/CMakeLists.txt @@ -71,6 +71,8 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].") diff --git a/local/recipes/kde/kf6-kjobwidgets/source/CMakeLists.txt b/local/recipes/kde/kf6-kjobwidgets/source/CMakeLists.txt index 813b0afba5..f3d8f2dacb 100644 --- a/local/recipes/kde/kf6-kjobwidgets/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-kjobwidgets/source/CMakeLists.txt @@ -73,6 +73,8 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) if(NOT WIN32 AND NOT APPLE AND NOT ANDROID AND NOT HAIKU) option(WITH_X11 "Build with support for QX11Info::appUserTime()" ON) diff --git a/local/recipes/kde/kf6-ksvg/source/.git-blame-ignore-revs b/local/recipes/kde/kf6-ksvg/source/.git-blame-ignore-revs new file mode 100644 index 0000000000..cc102c7e78 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/.git-blame-ignore-revs @@ -0,0 +1,6 @@ +#clang-format +08d4f6335bcd60306b243f4fd53d1ea60a995a06 +#clang-tidy +3120de70f25378cad1faf0ee4e96ac506006b953 +# re-run of clang-format +30f46ade664d7a9492817befa838297aecc44506 diff --git a/local/recipes/kde/kf6-ksvg/source/.gitignore b/local/recipes/kde/kf6-ksvg/source/.gitignore new file mode 100644 index 0000000000..31ded7dc90 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/.gitignore @@ -0,0 +1,28 @@ +# Ignore the following files +*~ +*.[oa] +*.diff +*.kate-swp +*.kdev4 +.kdev_include_paths +*.kdevelop.pcs +*.moc +*.moc.cpp +*.orig +*.user +.*.swp +.swp.* +Doxyfile +Makefile +avail +random_seed +/build*/ +CMakeLists.txt.user* +*.unc-backup* +.cmake/ +cmake-build-debug* +.idea +/.clang-format +/compile_commands.json +.clangd +.cache diff --git a/local/recipes/kde/kf6-ksvg/source/.gitlab-ci.yml b/local/recipes/kde/kf6-ksvg/source/.gitlab-ci.yml new file mode 100644 index 0000000000..f8f72dc5af --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/.gitlab-ci.yml @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: 2020 Volker Krause +# SPDX-License-Identifier: CC0-1.0 + +include: + - project: sysadmin/ci-utilities + file: + - /gitlab-templates/linux-qt6.yml + - /gitlab-templates/freebsd-qt6.yml + - /gitlab-templates/windows-qt6.yml + - /gitlab-templates/android-qt6.yml diff --git a/local/recipes/kde/kf6-ksvg/source/.kde-ci.yml b/local/recipes/kde/kf6-ksvg/source/.kde-ci.yml new file mode 100644 index 0000000000..6e679e3346 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/.kde-ci.yml @@ -0,0 +1,15 @@ +Dependencies: +- 'on': ['Linux', 'FreeBSD', 'Windows', 'macOS', 'Android'] + 'require': + 'frameworks/extra-cmake-modules': '@same' + 'frameworks/karchive' : '@same' + 'frameworks/kconfig' : '@same' + 'frameworks/kcoreaddons' : '@same' + 'frameworks/kguiaddons' : '@same' + 'frameworks/kirigami' : '@same' + 'frameworks/kcolorscheme' : '@same' + +Options: + test-before-installing: True + cppcheck-ignore-files: ['templates/'] + require-passing-tests-on: ['Linux', 'FreeBSD', 'Windows', 'macOS'] diff --git a/local/recipes/kde/kf6-ksvg/source/CMakeLists.txt b/local/recipes/kde/kf6-ksvg/source/CMakeLists.txt new file mode 100644 index 0000000000..4fc0c45011 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/CMakeLists.txt @@ -0,0 +1,128 @@ +cmake_minimum_required(VERSION 3.16) + +set(KF_VERSION "6.10.0") # handled by release scripts +set(KF_DEP_VERSION "6.10.0") # handled by release scripts +project(KSvg VERSION ${KF_VERSION}) + +# ECM setup +include(FeatureSummary) +find_package(ECM 6.10.0 NO_MODULE) +set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://commits.kde.org/extra-cmake-modules") +feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) + +set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) + +include(KDEInstallDirs) +include(KDECMakeSettings) +include(KDEGitCommitHooks) +include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) + +include(ECMGenerateExportHeader) +include(ECMGenerateHeaders) +include(CMakePackageConfigHelpers) +include(ECMSetupVersion) +include(ECMQtDeclareLoggingCategory) +include(ECMAddQch) +include(KDEPackageAppTemplates) +include(ECMGenerateQmlTypes) +include(ECMMarkNonGuiExecutable) +include(ECMDeprecationSettings) +include(ECMQmlModule) + +option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) +add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") + +ecm_setup_version(PROJECT + VARIABLE_PREFIX KSVG + VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/ksvg_version.h" + PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF6SvgConfigVersion.cmake" + SOVERSION 6) + +################# now find all used packages ################# + +set (REQUIRED_QT_VERSION 6.6.0) + +find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE COMPONENTS Gui Svg) + +find_package(KF6 ${KF_DEP_VERSION} REQUIRED + COMPONENTS + Archive # svgz + Config # rects cache + ColorScheme + CoreAddons + GuiAddons # KImageCache +) + +######################################################################### + +ecm_set_disabled_deprecation_versions( + QT 6.8.0 + KF 6.8.0 +) + +#add_definitions(-Wno-deprecated) + +######################################################################### + +option(BUILD_TOOLS "Build and install KSVG tools." OFF) + +option(BUILD_COVERAGE "Build Plasma Frameworks with gcov support" OFF) + +if(BUILD_COVERAGE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov") +endif() + +# make ksvg_version.h available +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +################# list the subdirectories ################# +add_subdirectory(src) + +if (BUILD_TESTING) + add_subdirectory(autotests) +endif() + +################ create PlasmaConfig.cmake and install it ########################### + +# create a Config.cmake and a ConfigVersion.cmake file and install them + +set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF6Svg") + +if (BUILD_QCH) + ecm_install_qch_export( + TARGETS KF6Svg_QCH + FILE KF6SvgQchTargets.cmake + DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + COMPONENT Devel + ) + set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF6SvgQchTargets.cmake\")") +endif() + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/KF6SvgConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/KF6SvgConfig.cmake" + INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} + PATH_VARS CMAKE_INSTALL_PREFIX +) + +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/KF6SvgConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/KF6SvgConfigVersion.cmake" + DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + COMPONENT Devel +) + +install(EXPORT KF6SvgTargets + DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + FILE KF6SvgTargets.cmake + NAMESPACE KF6:: + COMPONENT Devel) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ksvg_version.h + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KSvg COMPONENT Devel ) + +include(ECMFeatureSummary) +ecm_feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) + +kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT) diff --git a/local/recipes/kde/kf6-ksvg/source/KF6SvgConfig.cmake.in b/local/recipes/kde/kf6-ksvg/source/KF6SvgConfig.cmake.in new file mode 100644 index 0000000000..d2d29afab5 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/KF6SvgConfig.cmake.in @@ -0,0 +1,17 @@ +@PACKAGE_INIT@ + +# Any changes in this ".cmake" file will be overwritten by CMake, the source is the ".cmake.in" file. + +include("${CMAKE_CURRENT_LIST_DIR}/KF6SvgTargets.cmake") +@PACKAGE_INCLUDE_QCHTARGETS@ + +set(KSvg_INSTALL_PREFIX "@PACKAGE_CMAKE_INSTALL_PREFIX@") + +set(KSvg_LIBRARIES KF6::Svg) + +include(CMakeFindDependencyMacro) +find_dependency(Qt6Gui "@REQUIRED_QT_VERSION@") + +include("${CMAKE_CURRENT_LIST_DIR}/KF6SvgTargets.cmake") + +@PACKAGE_SETUP_AUTOMOC_VARIABLES@ diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/BSD-2-Clause.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/BSD-2-Clause.txt new file mode 100644 index 0000000000..2d2bab1127 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/BSD-2-Clause.txt @@ -0,0 +1,22 @@ +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/BSD-3-Clause.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/BSD-3-Clause.txt new file mode 100644 index 0000000000..0741db789e --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/BSD-3-Clause.txt @@ -0,0 +1,26 @@ +Copyright (c) . All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/CC0-1.0.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/CC0-1.0.txt new file mode 100644 index 0000000000..0e259d42c9 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/CC0-1.0.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/GPL-2.0-only.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/GPL-2.0-only.txt new file mode 100644 index 0000000000..0f3d6411da --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/GPL-2.0-only.txt @@ -0,0 +1,319 @@ +GNU GENERAL PUBLIC LICENSE + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. + +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to +most of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software +is covered by the GNU Lesser General Public License instead.) You can apply +it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish), that you receive source code or can get it if you want it, that you +can change the software or use pieces of it in new free programs; and that +you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of +the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or +for a fee, you must give the recipients all the rights that you have. You +must make sure that they, too, receive or can get the source code. And you +must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) +offer you this license which gives you legal permission to copy, distribute +and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If +the software is modified by someone else and passed on, we want its recipients +to know that what they have is not the original, so that any problems introduced +by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that redistributors of a free program will individually +obtain patent licenses, in effect making the program proprietary. To prevent +this, we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms +of this General Public License. The "Program", below, refers to any such program +or work, and a "work based on the Program" means either the Program or any +derivative work under copyright law: that is to say, a work containing the +Program or a portion of it, either verbatim or with modifications and/or translated +into another language. (Hereinafter, translation is included without limitation +in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered +by this License; they are outside its scope. The act of running the Program +is not restricted, and the output from the Program is covered only if its +contents constitute a work based on the Program (independent of having been +made by running the Program). Whether that is true depends on what the Program +does. + +1. You may copy and distribute verbatim copies of the Program's source code +as you receive it, in any medium, provided that you conspicuously and appropriately +publish on each copy an appropriate copyright notice and disclaimer of warranty; +keep intact all the notices that refer to this License and to the absence +of any warranty; and give any other recipients of the Program a copy of this +License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you +may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, +thus forming a work based on the Program, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all +of these conditions: + +a) You must cause the modified files to carry prominent notices stating that +you changed the files and the date of any change. + +b) You must cause any work that you distribute or publish, that in whole or +in part contains or is derived from the Program or any part thereof, to be +licensed as a whole at no charge to all third parties under the terms of this +License. + +c) If the modified program normally reads commands interactively when run, +you must cause it, when started running for such interactive use in the most +ordinary way, to print or display an announcement including an appropriate +copyright notice and a notice that there is no warranty (or else, saying that +you provide a warranty) and that users may redistribute the program under +these conditions, and telling the user how to view a copy of this License. +(Exception: if the Program itself is interactive but does not normally print +such an announcement, your work based on the Program is not required to print +an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, +and its terms, do not apply to those sections when you distribute them as +separate works. But when you distribute the same sections as part of a whole +which is a work based on the Program, the distribution of the whole must be +on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise +the right to control the distribution of derivative or collective works based +on the Program. + +In addition, mere aggregation of another work not based on the Program with +the Program (or with a work based on the Program) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. + +3. You may copy and distribute the Program (or a work based on it, under Section +2) in object code or executable form under the terms of Sections 1 and 2 above +provided that you also do one of the following: + +a) Accompany it with the complete corresponding machine-readable source code, +which must be distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or, + +b) Accompany it with a written offer, valid for at least three years, to give +any third party, for a charge no more than your cost of physically performing +source distribution, a complete machine-readable copy of the corresponding +source code, to be distributed under the terms of Sections 1 and 2 above on +a medium customarily used for software interchange; or, + +c) Accompany it with the information you received as to the offer to distribute +corresponding source code. (This alternative is allowed only for noncommercial +distribution and only if you received the program in object code or executable +form with such an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all +the source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and installation +of the executable. However, as a special exception, the source code distributed +need not include anything that is normally distributed (in either source or +binary form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component itself +accompanies the executable. + +If distribution of executable or object code is made by offering access to +copy from a designated place, then offering equivalent access to copy the +source code from the same place counts as distribution of the source code, +even though third parties are not compelled to copy the source along with +the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except +as expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses terminated +so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Program or its derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or distributing the Program +(or any work based on the Program), you indicate your acceptance of this License +to do so, and all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), +the recipient automatically receives a license from the original licensor +to copy, distribute or modify the Program subject to these terms and conditions. +You may not impose any further restrictions on the recipients' exercise of +the rights granted herein. You are not responsible for enforcing compliance +by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement +or for any other reason (not limited to patent issues), conditions are imposed +on you (whether by court order, agreement or otherwise) that contradict the +conditions of this License, they do not excuse you from the conditions of +this License. If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, then as +a consequence you may not distribute the Program at all. For example, if a +patent license would not permit royalty-free redistribution of the Program +by all those who receive copies directly or indirectly through you, then the +only way you could satisfy both it and this License would be to refrain entirely +from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and +the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents +or other property right claims or to contest validity of any such claims; +this section has the sole purpose of protecting the integrity of the free +software distribution system, which is implemented by public license practices. +Many people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose +that choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Program under this License may add an explicit geographical +distribution limitation excluding those countries, so that distribution is +permitted only in or among countries not thus excluded. In such case, this +License incorporates the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of +the General Public License from time to time. Such new versions will be similar +in spirit to the present version, but may differ in detail to address new +problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Program does not specify a version number of this License, you may choose +any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing and reuse +of software generally. + + NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE +OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA +OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES +OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH +HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible +use to the public, the best way to achieve this is to make it free software +which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach +them to the start of each source file to most effectively convey the exclusion +of warranty; and each file should have at least the "copyright" line and a +pointer to where the full notice is found. + + + +Copyright (C)< yyyy> + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 51 Franklin +Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when +it starts in an interactive mode: + +Gnomovision version 69, Copyright (C) year name of author Gnomovision comes +with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, +and you are welcome to redistribute it under certain conditions; type `show +c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may be +called something other than `show w' and `show c'; they could even be mouse-clicks +or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the program, if necessary. Here +is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' +(which makes passes at compilers) written by James Hacker. + +, 1 April 1989 Ty Coon, President of Vice This General +Public License does not permit incorporating your program into proprietary +programs. If your program is a subroutine library, you may consider it more +useful to permit linking proprietary applications with the library. If this +is what you want to do, use the GNU Lesser General Public License instead +of this License. diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/GPL-2.0-or-later.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/GPL-2.0-or-later.txt new file mode 100644 index 0000000000..1d80ac3653 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/GPL-2.0-or-later.txt @@ -0,0 +1,319 @@ +GNU GENERAL PUBLIC LICENSE + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. + +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public License is intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to +most of the Free Software Foundation's software and to any other program whose +authors commit to using it. (Some other Free Software Foundation software +is covered by the GNU Lesser General Public License instead.) You can apply +it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish), that you receive source code or can get it if you want it, that you +can change the software or use pieces of it in new free programs; and that +you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of +the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or +for a fee, you must give the recipients all the rights that you have. You +must make sure that they, too, receive or can get the source code. And you +must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) +offer you this license which gives you legal permission to copy, distribute +and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that +everyone understands that there is no warranty for this free software. If +the software is modified by someone else and passed on, we want its recipients +to know that what they have is not the original, so that any problems introduced +by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that redistributors of a free program will individually +obtain patent licenses, in effect making the program proprietary. To prevent +this, we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice +placed by the copyright holder saying it may be distributed under the terms +of this General Public License. The "Program", below, refers to any such program +or work, and a "work based on the Program" means either the Program or any +derivative work under copyright law: that is to say, a work containing the +Program or a portion of it, either verbatim or with modifications and/or translated +into another language. (Hereinafter, translation is included without limitation +in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered +by this License; they are outside its scope. The act of running the Program +is not restricted, and the output from the Program is covered only if its +contents constitute a work based on the Program (independent of having been +made by running the Program). Whether that is true depends on what the Program +does. + +1. You may copy and distribute verbatim copies of the Program's source code +as you receive it, in any medium, provided that you conspicuously and appropriately +publish on each copy an appropriate copyright notice and disclaimer of warranty; +keep intact all the notices that refer to this License and to the absence +of any warranty; and give any other recipients of the Program a copy of this +License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you +may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, +thus forming a work based on the Program, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all +of these conditions: + +a) You must cause the modified files to carry prominent notices stating that +you changed the files and the date of any change. + +b) You must cause any work that you distribute or publish, that in whole or +in part contains or is derived from the Program or any part thereof, to be +licensed as a whole at no charge to all third parties under the terms of this +License. + +c) If the modified program normally reads commands interactively when run, +you must cause it, when started running for such interactive use in the most +ordinary way, to print or display an announcement including an appropriate +copyright notice and a notice that there is no warranty (or else, saying that +you provide a warranty) and that users may redistribute the program under +these conditions, and telling the user how to view a copy of this License. +(Exception: if the Program itself is interactive but does not normally print +such an announcement, your work based on the Program is not required to print +an announcement.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Program, and can be reasonably +considered independent and separate works in themselves, then this License, +and its terms, do not apply to those sections when you distribute them as +separate works. But when you distribute the same sections as part of a whole +which is a work based on the Program, the distribution of the whole must be +on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise +the right to control the distribution of derivative or collective works based +on the Program. + +In addition, mere aggregation of another work not based on the Program with +the Program (or with a work based on the Program) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. + +3. You may copy and distribute the Program (or a work based on it, under Section +2) in object code or executable form under the terms of Sections 1 and 2 above +provided that you also do one of the following: + +a) Accompany it with the complete corresponding machine-readable source code, +which must be distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or, + +b) Accompany it with a written offer, valid for at least three years, to give +any third party, for a charge no more than your cost of physically performing +source distribution, a complete machine-readable copy of the corresponding +source code, to be distributed under the terms of Sections 1 and 2 above on +a medium customarily used for software interchange; or, + +c) Accompany it with the information you received as to the offer to distribute +corresponding source code. (This alternative is allowed only for noncommercial +distribution and only if you received the program in object code or executable +form with such an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making +modifications to it. For an executable work, complete source code means all +the source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and installation +of the executable. However, as a special exception, the source code distributed +need not include anything that is normally distributed (in either source or +binary form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component itself +accompanies the executable. + +If distribution of executable or object code is made by offering access to +copy from a designated place, then offering equivalent access to copy the +source code from the same place counts as distribution of the source code, +even though third parties are not compelled to copy the source along with +the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except +as expressly provided under this License. Any attempt otherwise to copy, modify, +sublicense or distribute the Program is void, and will automatically terminate +your rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses terminated +so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Program or its derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or distributing the Program +(or any work based on the Program), you indicate your acceptance of this License +to do so, and all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), +the recipient automatically receives a license from the original licensor +to copy, distribute or modify the Program subject to these terms and conditions. +You may not impose any further restrictions on the recipients' exercise of +the rights granted herein. You are not responsible for enforcing compliance +by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement +or for any other reason (not limited to patent issues), conditions are imposed +on you (whether by court order, agreement or otherwise) that contradict the +conditions of this License, they do not excuse you from the conditions of +this License. If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, then as +a consequence you may not distribute the Program at all. For example, if a +patent license would not permit royalty-free redistribution of the Program +by all those who receive copies directly or indirectly through you, then the +only way you could satisfy both it and this License would be to refrain entirely +from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply and +the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents +or other property right claims or to contest validity of any such claims; +this section has the sole purpose of protecting the integrity of the free +software distribution system, which is implemented by public license practices. +Many people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose +that choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Program under this License may add an explicit geographical +distribution limitation excluding those countries, so that distribution is +permitted only in or among countries not thus excluded. In such case, this +License incorporates the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of +the General Public License from time to time. Such new versions will be similar +in spirit to the present version, but may differ in detail to address new +problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Program does not specify a version number of this License, you may choose +any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs +whose distribution conditions are different, write to the author to ask for +permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. +Our decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing and reuse +of software generally. + + NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE +OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA +OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES +OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH +HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible +use to the public, the best way to achieve this is to make it free software +which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach +them to the start of each source file to most effectively convey the exclusion +of warranty; and each file should have at least the "copyright" line and a +pointer to where the full notice is found. + + + +Copyright (C) + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 51 Franklin +Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this when +it starts in an interactive mode: + +Gnomovision version 69, Copyright (C) year name of author Gnomovision comes +with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, +and you are welcome to redistribute it under certain conditions; type `show +c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may be +called something other than `show w' and `show c'; they could even be mouse-clicks +or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the program, if necessary. Here +is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' +(which makes passes at compilers) written by James Hacker. + +, 1 April 1989 Ty Coon, President of Vice This General +Public License does not permit incorporating your program into proprietary +programs. If your program is a subroutine library, you may consider it more +useful to permit linking proprietary applications with the library. If this +is what you want to do, use the GNU Lesser General Public License instead +of this License. diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/GPL-3.0-only.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/GPL-3.0-only.txt new file mode 100644 index 0000000000..e142a525bd --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/GPL-3.0-only.txt @@ -0,0 +1,625 @@ +GNU GENERAL PUBLIC LICENSE + +Version 3, 29 June 2007 + +Copyright © 2007 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +Preamble + +The GNU General Public License is a free, copyleft license for software and +other kinds of works. + +The licenses for most software and other practical works are designed to take +away your freedom to share and change the works. By contrast, the GNU General +Public License is intended to guarantee your freedom to share and change all +versions of a program--to make sure it remains free software for all its users. +We, the Free Software Foundation, use the GNU General Public License for most +of our software; it applies also to any other work released this way by its +authors. You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for them if you wish), that +you receive source code or can get it if you want it, that you can change +the software or use pieces of it in new free programs, and that you know you +can do these things. + +To protect your rights, we need to prevent others from denying you these rights +or asking you to surrender the rights. Therefore, you have certain responsibilities +if you distribute copies of the software, or if you modify it: responsibilities +to respect the freedom of others. + +For example, if you distribute copies of such a program, whether gratis or +for a fee, you must pass on to the recipients the same freedoms that you received. +You must make sure that they, too, receive or can get the source code. And +you must show them these terms so they know their rights. + +Developers that use the GNU GPL protect your rights with two steps: (1) assert +copyright on the software, and (2) offer you this License giving you legal +permission to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains that +there is no warranty for this free software. For both users' and authors' +sake, the GPL requires that modified versions be marked as changed, so that +their problems will not be attributed erroneously to authors of previous versions. + +Some devices are designed to deny users access to install or run modified +versions of the software inside them, although the manufacturer can do so. +This is fundamentally incompatible with the aim of protecting users' freedom +to change the software. The systematic pattern of such abuse occurs in the +area of products for individuals to use, which is precisely where it is most +unacceptable. Therefore, we have designed this version of the GPL to prohibit +the practice for those products. If such problems arise substantially in other +domains, we stand ready to extend this provision to those domains in future +versions of the GPL, as needed to protect the freedom of users. + +Finally, every program is threatened constantly by software patents. States +should not allow patents to restrict development and use of software on general-purpose +computers, but in those that do, we wish to avoid the special danger that +patents applied to a free program could make it effectively proprietary. To +prevent this, the GPL assures that patents cannot be used to render the program +non-free. + +The precise terms and conditions for copying, distribution and modification +follow. + +TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds of works, +such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this License. +Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals +or organizations. + +To "modify" a work means to copy from or adapt all or part of the work in +a fashion requiring copyright permission, other than the making of an exact +copy. The resulting work is called a "modified version" of the earlier work +or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based on the +Program. + +To "propagate" a work means to do anything with it that, without permission, +would make you directly or secondarily liable for infringement under applicable +copyright law, except executing it on a computer or modifying a private copy. +Propagation includes copying, distribution (with or without modification), +making available to the public, and in some countries other activities as +well. + +To "convey" a work means any kind of propagation that enables other parties +to make or receive copies. Mere interaction with a user through a computer +network, with no transfer of a copy, is not conveying. + +An interactive user interface displays "Appropriate Legal Notices" to the +extent that it includes a convenient and prominently visible feature that +(1) displays an appropriate copyright notice, and (2) tells the user that +there is no warranty for the work (except to the extent that warranties are +provided), that licensees may convey the work under this License, and how +to view a copy of this License. If the interface presents a list of user commands +or options, such as a menu, a prominent item in the list meets this criterion. + + 1. Source Code. + +The "source code" for a work means the preferred form of the work for making +modifications to it. "Object code" means any non-source form of a work. + +A "Standard Interface" means an interface that either is an official standard +defined by a recognized standards body, or, in the case of interfaces specified +for a particular programming language, one that is widely used among developers +working in that language. + +The "System Libraries" of an executable work include anything, other than +the work as a whole, that (a) is included in the normal form of packaging +a Major Component, but which is not part of that Major Component, and (b) +serves only to enable use of the work with that Major Component, or to implement +a Standard Interface for which an implementation is available to the public +in source code form. A "Major Component", in this context, means a major essential +component (kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to produce +the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all the source +code needed to generate, install, and (for an executable work) run the object +code and to modify the work, including scripts to control those activities. +However, it does not include the work's System Libraries, or general-purpose +tools or generally available free programs which are used unmodified in performing +those activities but which are not part of the work. For example, Corresponding +Source includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically linked +subprograms that the work is specifically designed to require, such as by +intimate data communication or control flow between those subprograms and +other parts of the work. + +The Corresponding Source need not include anything that users can regenerate +automatically from other parts of the Corresponding Source. + + The Corresponding Source for a work in source code form is that same work. + + 2. Basic Permissions. + +All rights granted under this License are granted for the term of copyright +on the Program, and are irrevocable provided the stated conditions are met. +This License explicitly affirms your unlimited permission to run the unmodified +Program. The output from running a covered work is covered by this License +only if the output, given its content, constitutes a covered work. This License +acknowledges your rights of fair use or other equivalent, as provided by copyright +law. + +You may make, run and propagate covered works that you do not convey, without +conditions so long as your license otherwise remains in force. You may convey +covered works to others for the sole purpose of having them make modifications +exclusively for you, or provide you with facilities for running those works, +provided that you comply with the terms of this License in conveying all material +for which you do not control copyright. Those thus making or running the covered +works for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of your copyrighted +material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the conditions +stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological measure +under any applicable law fulfilling obligations under article 11 of the WIPO +copyright treaty adopted on 20 December 1996, or similar laws prohibiting +or restricting circumvention of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention +of technological measures to the extent such circumvention is effected by +exercising rights under this License with respect to the covered work, and +you disclaim any intention to limit operation or modification of the work +as a means of enforcing, against the work's users, your or third parties' +legal rights to forbid circumvention of technological measures. + + 4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you receive +it, in any medium, provided that you conspicuously and appropriately publish +on each copy an appropriate copyright notice; keep intact all notices stating +that this License and any non-permissive terms added in accord with section +7 apply to the code; keep intact all notices of the absence of any warranty; +and give all recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you +may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to produce +it from the Program, in the form of source code under the terms of section +4, provided that you also meet all of these conditions: + +a) The work must carry prominent notices stating that you modified it, and +giving a relevant date. + +b) The work must carry prominent notices stating that it is released under +this License and any conditions added under section 7. This requirement modifies +the requirement in section 4 to "keep intact all notices". + +c) You must license the entire work, as a whole, under this License to anyone +who comes into possession of a copy. This License will therefore apply, along +with any applicable section 7 additional terms, to the whole of the work, +and all its parts, regardless of how they are packaged. This License gives +no permission to license the work in any other way, but it does not invalidate +such permission if you have separately received it. + +d) If the work has interactive user interfaces, each must display Appropriate +Legal Notices; however, if the Program has interactive interfaces that do +not display Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, +which are not by their nature extensions of the covered work, and which are +not combined with it such as to form a larger program, in or on a volume of +a storage or distribution medium, is called an "aggregate" if the compilation +and its resulting copyright are not used to limit the access or legal rights +of the compilation's users beyond what the individual works permit. Inclusion +of a covered work in an aggregate does not cause this License to apply to +the other parts of the aggregate. + + 6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms of sections +4 and 5, provided that you also convey the machine-readable Corresponding +Source under the terms of this License, in one of these ways: + +a) Convey the object code in, or embodied in, a physical product (including +a physical distribution medium), accompanied by the Corresponding Source fixed +on a durable physical medium customarily used for software interchange. + +b) Convey the object code in, or embodied in, a physical product (including +a physical distribution medium), accompanied by a written offer, valid for +at least three years and valid for as long as you offer spare parts or customer +support for that product model, to give anyone who possesses the object code +either (1) a copy of the Corresponding Source for all the software in the +product that is covered by this License, on a durable physical medium customarily +used for software interchange, for a price no more than your reasonable cost +of physically performing this conveying of source, or (2) access to copy the +Corresponding Source from a network server at no charge. + +c) Convey individual copies of the object code with a copy of the written +offer to provide the Corresponding Source. This alternative is allowed only +occasionally and noncommercially, and only if you received the object code +with such an offer, in accord with subsection 6b. + +d) Convey the object code by offering access from a designated place (gratis +or for a charge), and offer equivalent access to the Corresponding Source +in the same way through the same place at no further charge. You need not +require recipients to copy the Corresponding Source along with the object +code. If the place to copy the object code is a network server, the Corresponding +Source may be on a different server (operated by you or a third party) that +supports equivalent copying facilities, provided you maintain clear directions +next to the object code saying where to find the Corresponding Source. Regardless +of what server hosts the Corresponding Source, you remain obligated to ensure +that it is available for as long as needed to satisfy these requirements. + +e) Convey the object code using peer-to-peer transmission, provided you inform +other peers where the object code and Corresponding Source of the work are +being offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from +the Corresponding Source as a System Library, need not be included in conveying +the object code work. + +A "User Product" is either (1) a "consumer product", which means any tangible +personal property which is normally used for personal, family, or household +purposes, or (2) anything designed or sold for incorporation into a dwelling. +In determining whether a product is a consumer product, doubtful cases shall +be resolved in favor of coverage. For a particular product received by a particular +user, "normally used" refers to a typical or common use of that class of product, +regardless of the status of the particular user or of the way in which the +particular user actually uses, or expects or is expected to use, the product. +A product is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent the +only significant mode of use of the product. + +"Installation Information" for a User Product means any methods, procedures, +authorization keys, or other information required to install and execute modified +versions of a covered work in that User Product from a modified version of +its Corresponding Source. The information must suffice to ensure that the +continued functioning of the modified object code is in no case prevented +or interfered with solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically +for use in, a User Product, and the conveying occurs as part of a transaction +in which the right of possession and use of the User Product is transferred +to the recipient in perpetuity or for a fixed term (regardless of how the +transaction is characterized), the Corresponding Source conveyed under this +section must be accompanied by the Installation Information. But this requirement +does not apply if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has been installed +in ROM). + +The requirement to provide Installation Information does not include a requirement +to continue to provide support service, warranty, or updates for a work that +has been modified or installed by the recipient, or for the User Product in +which it has been modified or installed. Access to a network may be denied +when the modification itself materially and adversely affects the operation +of the network or violates the rules and protocols for communication across +the network. + +Corresponding Source conveyed, and Installation Information provided, in accord +with this section must be in a format that is publicly documented (and with +an implementation available to the public in source code form), and must require +no special password or key for unpacking, reading or copying. + + 7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this License +by making exceptions from one or more of its conditions. Additional permissions +that are applicable to the entire Program shall be treated as though they +were included in this License, to the extent that they are valid under applicable +law. If additional permissions apply only to part of the Program, that part +may be used separately under those permissions, but the entire Program remains +governed by this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any +additional permissions from that copy, or from any part of it. (Additional +permissions may be written to require their own removal in certain cases when +you modify the work.) You may place additional permissions on material, added +by you to a covered work, for which you have or can give appropriate copyright +permission. + +Notwithstanding any other provision of this License, for material you add +to a covered work, you may (if authorized by the copyright holders of that +material) supplement the terms of this License with terms: + +a) Disclaiming warranty or limiting liability differently from the terms of +sections 15 and 16 of this License; or + +b) Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices displayed +by works containing it; or + +c) Prohibiting misrepresentation of the origin of that material, or requiring +that modified versions of such material be marked in reasonable ways as different +from the original version; or + +d) Limiting the use for publicity purposes of names of licensors or authors +of the material; or + +e) Declining to grant rights under trademark law for use of some trade names, +trademarks, or service marks; or + +f) Requiring indemnification of licensors and authors of that material by +anyone who conveys the material (or modified versions of it) with contractual +assumptions of liability to the recipient, for any liability that these contractual +assumptions directly impose on those licensors and authors. + +All other non-permissive additional terms are considered "further restrictions" +within the meaning of section 10. If the Program as you received it, or any +part of it, contains a notice stating that it is governed by this License +along with a term that is a further restriction, you may remove that term. +If a license document contains a further restriction but permits relicensing +or conveying under this License, you may add to a covered work material governed +by the terms of that license document, provided that the further restriction +does not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, +in the relevant source files, a statement of the additional terms that apply +to those files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form +of a separately written license, or stated as exceptions; the above requirements +apply either way. + + 8. Termination. + +You may not propagate or modify a covered work except as expressly provided +under this License. Any attempt otherwise to propagate or modify it is void, +and will automatically terminate your rights under this License (including +any patent licenses granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from +a particular copyright holder is reinstated (a) provisionally, unless and +until the copyright holder explicitly and finally terminates your license, +and (b) permanently, if the copyright holder fails to notify you of the violation +by some reasonable means prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently +if the copyright holder notifies you of the violation by some reasonable means, +this is the first time you have received notice of violation of this License +(for any work) from that copyright holder, and you cure the violation prior +to 30 days after your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses +of parties who have received copies or rights from you under this License. +If your rights have been terminated and not permanently reinstated, you do +not qualify to receive new licenses for the same material under section 10. + + 9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run a copy +of the Program. Ancillary propagation of a covered work occurring solely as +a consequence of using peer-to-peer transmission to receive a copy likewise +does not require acceptance. However, nothing other than this License grants +you permission to propagate or modify any covered work. These actions infringe +copyright if you do not accept this License. Therefore, by modifying or propagating +a covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically receives +a license from the original licensors, to run, modify and propagate that work, +subject to this License. You are not responsible for enforcing compliance +by third parties with this License. + +An "entity transaction" is a transaction transferring control of an organization, +or substantially all assets of one, or subdividing an organization, or merging +organizations. If propagation of a covered work results from an entity transaction, +each party to that transaction who receives a copy of the work also receives +whatever licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the Corresponding +Source of the work from the predecessor in interest, if the predecessor has +it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights +granted or affirmed under this License. For example, you may not impose a +license fee, royalty, or other charge for exercise of rights granted under +this License, and you may not initiate litigation (including a cross-claim +or counterclaim in a lawsuit) alleging that any patent claim is infringed +by making, using, selling, offering for sale, or importing the Program or +any portion of it. + + 11. Patents. + +A "contributor" is a copyright holder who authorizes use under this License +of the Program or a work on which the Program is based. The work thus licensed +is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned or controlled +by the contributor, whether already acquired or hereafter acquired, that would +be infringed by some manner, permitted by this License, of making, using, +or selling its contributor version, but do not include claims that would be +infringed only as a consequence of further modification of the contributor +version. For purposes of this definition, "control" includes the right to +grant patent sublicenses in a manner consistent with the requirements of this +License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent +license under the contributor's essential patent claims, to make, use, sell, +offer for sale, import and otherwise run, modify and propagate the contents +of its contributor version. + +In the following three paragraphs, a "patent license" is any express agreement +or commitment, however denominated, not to enforce a patent (such as an express +permission to practice a patent or covenant not to sue for patent infringement). +To "grant" such a patent license to a party means to make such an agreement +or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the +Corresponding Source of the work is not available for anyone to copy, free +of charge and under the terms of this License, through a publicly available +network server or other readily accessible means, then you must either (1) +cause the Corresponding Source to be so available, or (2) arrange to deprive +yourself of the benefit of the patent license for this particular work, or +(3) arrange, in a manner consistent with the requirements of this License, +to extend the patent license to downstream recipients. "Knowingly relying" +means you have actual knowledge that, but for the patent license, your conveying +the covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that country +that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, +you convey, or propagate by procuring conveyance of, a covered work, and grant +a patent license to some of the parties receiving the covered work authorizing +them to use, propagate, modify or convey a specific copy of the covered work, +then the patent license you grant is automatically extended to all recipients +of the covered work and works based on it. + +A patent license is "discriminatory" if it does not include within the scope +of its coverage, prohibits the exercise of, or is conditioned on the non-exercise +of one or more of the rights that are specifically granted under this License. +You may not convey a covered work if you are a party to an arrangement with +a third party that is in the business of distributing software, under which +you make payment to the third party based on the extent of your activity of +conveying the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory patent +license (a) in connection with copies of the covered work conveyed by you +(or copies made from those copies), or (b) primarily for and in connection +with specific products or compilations that contain the covered work, unless +you entered into that arrangement, or that patent license was granted, prior +to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied +license or other defenses to infringement that may otherwise be available +to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or otherwise) +that contradict the conditions of this License, they do not excuse you from +the conditions of this License. If you cannot convey a covered work so as +to satisfy simultaneously your obligations under this License and any other +pertinent obligations, then as a consequence you may not convey it at all. +For example, if you agree to terms that obligate you to collect a royalty +for further conveying from those to whom you convey the Program, the only +way you could satisfy both those terms and this License would be to refrain +entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + +Notwithstanding any other provision of this License, you have permission to +link or combine any covered work with a work licensed under version 3 of the +GNU Affero General Public License into a single combined work, and to convey +the resulting work. The terms of this License will continue to apply to the +part which is the covered work, but the special requirements of the GNU Affero +General Public License, section 13, concerning interaction through a network +will apply to the combination as such. + + 14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions of the +GNU General Public License from time to time. Such new versions will be similar +in spirit to the present version, but may differ in detail to address new +problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies +that a certain numbered version of the GNU General Public License "or any +later version" applies to it, you have the option of following the terms and +conditions either of that numbered version or of any later version published +by the Free Software Foundation. If the Program does not specify a version +number of the GNU General Public License, you may choose any version ever +published by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future versions of +the GNU General Public License can be used, that proxy's public statement +of acceptance of a version permanently authorizes you to choose that version +for the Program. + +Later license versions may give you additional or different permissions. However, +no additional obligations are imposed on any author or copyright holder as +a result of your choosing to follow a later version. + + 15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE +LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM +PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + + 16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL +ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM +AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, +INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO +USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED +INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE +PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER +PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided above cannot +be given local legal effect according to their terms, reviewing courts shall +apply local law that most closely approximates an absolute waiver of all civil +liability in connection with the Program, unless a warranty or assumption +of liability accompanies a copy of the Program in return for a fee. END OF +TERMS AND CONDITIONS + +How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible +use to the public, the best way to achieve this is to make it free software +which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach +them to the start of each source file to most effectively state the exclusion +of warranty; and each file should have at least the "copyright" line and a +pointer to where the full notice is found. + + + +Copyright (C) + +This program is free software: you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If the program does terminal interaction, make it output a short notice like +this when it starts in an interactive mode: + + Copyright (C) + +This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + +This is free software, and you are welcome to redistribute it under certain +conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands might +be different; for a GUI interface, you would use an "about box". + +You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. For +more information on this, and how to apply and follow the GNU GPL, see . + +The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General Public +License instead of this License. But first, please read . diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-2.0-or-later.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-2.0-or-later.txt new file mode 100644 index 0000000000..5c96471aaf --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-2.0-or-later.txt @@ -0,0 +1,446 @@ +GNU LIBRARY GENERAL PUBLIC LICENSE + +Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. + +51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is numbered 2 because +it goes with version 2 of the ordinary GPL.] + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public Licenses are intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. + +This license, the Library General Public License, applies to some specially +designated Free Software Foundation software, and to any other libraries whose +authors decide to use it. You can use it for your libraries, too. + +When we speak of free software, we are referring to freedom, not price. Our +General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish), that you receive source code or can get it if you want it, that you +can change the software or use pieces of it in new free programs; and that +you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to +deny you these rights or to ask you to surrender the rights. These restrictions +translate to certain responsibilities for you if you distribute copies of +the library, or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for +a fee, you must give the recipients all the rights that we gave you. You must +make sure that they, too, receive or can get the source code. If you link +a program with the library, you must provide complete object files to the +recipients so that they can relink them with the library, after making changes +to the library and recompiling it. And you must show them these terms so they +know their rights. + +Our method of protecting your rights has two steps: (1) copyright the library, +and (2) offer you this license which gives you legal permission to copy, distribute +and/or modify the library. + +Also, for each distributor's protection, we want to make certain that everyone +understands that there is no warranty for this free library. If the library +is modified by someone else and passed on, we want its recipients to know +that what they have is not the original version, so that any problems introduced +by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We +wish to avoid the danger that companies distributing free software will individually +obtain patent licenses, thus in effect transforming the program into proprietary +software. To prevent this, we have made it clear that any patent must be licensed +for everyone's free use or not licensed at all. + +Most GNU software, including some libraries, is covered by the ordinary GNU +General Public License, which was designed for utility programs. This license, +the GNU Library General Public License, applies to certain designated libraries. +This license is quite different from the ordinary one; be sure to read it +in full, and don't assume that anything in it is the same as in the ordinary +license. + +The reason we have a separate public license for some libraries is that they +blur the distinction we usually make between modifying or adding to a program +and simply using it. Linking a program with a library, without changing the +library, is in some sense simply using the library, and is analogous to running +a utility program or application program. However, in a textual and legal +sense, the linked executable is a combined work, a derivative of the original +library, and the ordinary General Public License treats it as such. + +Because of this blurred distinction, using the ordinary General Public License +for libraries did not effectively promote software sharing, because most developers +did not use the libraries. We concluded that weaker conditions might promote +sharing better. + +However, unrestricted linking of non-free programs would deprive the users +of those programs of all benefit from the free status of the libraries themselves. +This Library General Public License is intended to permit developers of non-free +programs to use free libraries, while preserving your freedom as a user of +such programs to change the free libraries that are incorporated in them. +(We have not seen how to achieve this as regards changes in header files, +but we have achieved it as regards changes in the actual functions of the +Library.) The hope is that this will lead to faster development of free libraries. + +The precise terms and conditions for copying, distribution and modification +follow. Pay close attention to the difference between a "work based on the +library" and a "work that uses the library". The former contains code derived +from the library, while the latter only works together with the library. + +Note that it is possible for a library to be covered by the ordinary General +Public License rather than by this special one. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library which contains a +notice placed by the copyright holder or other authorized party saying it +may be distributed under the terms of this Library General Public License +(also called "this License"). Each licensee is addressed as "you". + +A "library" means a collection of software functions and/or data prepared +so as to be conveniently linked with application programs (which use some +of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has +been distributed under these terms. A "work based on the Library" means either +the Library or any derivative work under copyright law: that is to say, a +work containing the Library or a portion of it, either verbatim or with modifications +and/or translated straightforwardly into another language. (Hereinafter, translation +is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications +to it. For a library, complete source code means all the source code for all +modules it contains, plus any associated interface definition files, plus +the scripts used to control compilation and installation of the library. + +Activities other than copying, distribution and modification are not covered +by this License; they are outside its scope. The act of running a program +using the Library is not restricted, and output from such a program is covered +only if its contents constitute a work based on the Library (independent of +the use of the Library in a tool for writing it). Whether that is true depends +on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and disclaimer +of warranty; keep intact all the notices that refer to this License and to +the absence of any warranty; and distribute a copy of this License along with +the Library. + +You may charge a fee for the physical act of transferring a copy, and you +may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, +thus forming a work based on the Library, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all +of these conditions: + + a) The modified work must itself be a software library. + +b) You must cause the files modified to carry prominent notices stating that +you changed the files and the date of any change. + +c) You must cause the whole of the work to be licensed at no charge to all +third parties under the terms of this License. + +d) If a facility in the modified Library refers to a function or a table of +data to be supplied by an application program that uses the facility, other +than as an argument passed when the facility is invoked, then you must make +a good faith effort to ensure that, in the event an application does not supply +such function or table, the facility still operates, and performs whatever +part of its purpose remains meaningful. + +(For example, a function in a library to compute square roots has a purpose +that is entirely well-defined independent of the application. Therefore, Subsection +2d requires that any application-supplied function or table used by this function +must be optional: if the application does not supply it, the square root function +must still compute square roots.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Library, and can be reasonably +considered independent and separate works in themselves, then this License, +and its terms, do not apply to those sections when you distribute them as +separate works. But when you distribute the same sections as part of a whole +which is a work based on the Library, the distribution of the whole must be +on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise +the right to control the distribution of derivative or collective works based +on the Library. + +In addition, mere aggregation of another work not based on the Library with +the Library (or with a work based on the Library) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. + +3. You may opt to apply the terms of the ordinary GNU General Public License +instead of this License to a given copy of the Library. To do this, you must +alter all the notices that refer to this License, so that they refer to the +ordinary GNU General Public License, version 2, instead of to this License. +(If a newer version than version 2 of the ordinary GNU General Public License +has appeared, then you can specify that version instead if you wish.) Do not +make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, +so the ordinary GNU General Public License applies to all subsequent copies +and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library +into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of +it, under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you accompany it with the complete corresponding +machine-readable source code, which must be distributed under the terms of +Sections 1 and 2 above on a medium customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a designated +place, then offering equivalent access to copy the source code from the same +place satisfies the requirement to distribute the source code, even though +third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but +is designed to work with the Library by being compiled or linked with it, +is called a "work that uses the Library". Such a work, in isolation, is not +a derivative work of the Library, and therefore falls outside the scope of +this License. + +However, linking a "work that uses the Library" with the Library creates an +executable that is a derivative of the Library (because it contains portions +of the Library), rather than a "work that uses the library". The executable +is therefore covered by this License. Section 6 states terms for distribution +of such executables. + +When a "work that uses the Library" uses material from a header file that +is part of the Library, the object code for the work may be a derivative work +of the Library even though the source code is not. Whether this is true is +especially significant if the work can be linked without the Library, or if +the work is itself a library. The threshold for this to be true is not precisely +defined by law. + +If such an object file uses only numerical parameters, data structure layouts +and accessors, and small macros and small inline functions (ten lines or less +in length), then the use of the object file is unrestricted, regardless of +whether it is legally a derivative work. (Executables containing this object +code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute +the object code for the work under the terms of Section 6. Any executables +containing that work also fall under Section 6, whether or not they are linked +directly with the Library itself. + +6. As an exception to the Sections above, you may also compile or link a "work +that uses the Library" with the Library to produce a work containing portions +of the Library, and distribute that work under terms of your choice, provided +that the terms permit modification of the work for the customer's own use +and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library +is used in it and that the Library and its use are covered by this License. +You must supply a copy of this License. If the work during execution displays +copyright notices, you must include the copyright notice for the Library among +them, as well as a reference directing the user to the copy of this License. +Also, you must do one of these things: + +a) Accompany the work with the complete corresponding machine-readable source +code for the Library including whatever changes were used in the work (which +must be distributed under Sections 1 and 2 above); and, if the work is an +executable linked with the Library, with the complete machine-readable "work +that uses the Library", as object code and/or source code, so that the user +can modify the Library and then relink to produce a modified executable containing +the modified Library. (It is understood that the user who changes the contents +of definitions files in the Library will not necessarily be able to recompile +the application to use the modified definitions.) + +b) Accompany the work with a written offer, valid for at least three years, +to give the same user the materials specified in Subsection 6a, above, for +a charge no more than the cost of performing this distribution. + +c) If distribution of the work is made by offering access to copy from a designated +place, offer equivalent access to copy the above specified materials from +the same place. + +d) Verify that the user has already received a copy of these materials or +that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" must +include any data and utility programs needed for reproducing the executable +from it. However, as a special exception, the source code distributed need +not include anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the operating +system on which the executable runs, unless that component itself accompanies +the executable. + +It may happen that this requirement contradicts the license restrictions of +other proprietary libraries that do not normally accompany the operating system. +Such a contradiction means you cannot use both them and the Library together +in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library side-by-side +in a single library together with other library facilities not covered by +this License, and distribute such a combined library, provided that the separate +distribution of the work based on the Library and of the other library facilities +is otherwise permitted, and provided that you do these two things: + +a) Accompany the combined library with a copy of the same work based on the +Library, uncombined with any other library facilities. This must be distributed +under the terms of the Sections above. + +b) Give prominent notice with the combined library of the fact that part of +it is a work based on the Library, and explaining where to find the accompanying +uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the Library +except as expressly provided under this License. Any attempt otherwise to +copy, modify, sublicense, link with, or distribute the Library is void, and +will automatically terminate your rights under this License. However, parties +who have received copies, or rights, from you under this License will not +have their licenses terminated so long as such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Library or its derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or distributing the Library +(or any work based on the Library), you indicate your acceptance of this License +to do so, and all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), +the recipient automatically receives a license from the original licensor +to copy, distribute, link with or modify the Library subject to these terms +and conditions. You may not impose any further restrictions on the recipients' +exercise of the rights granted herein. You are not responsible for enforcing +compliance by third parties to this License. + +11. If, as a consequence of a court judgment or allegation of patent infringement +or for any other reason (not limited to patent issues), conditions are imposed +on you (whether by court order, agreement or otherwise) that contradict the +conditions of this License, they do not excuse you from the conditions of +this License. If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, then as +a consequence you may not distribute the Library at all. For example, if a +patent license would not permit royalty-free redistribution of the Library +by all those who receive copies directly or indirectly through you, then the +only way you could satisfy both it and this License would be to refrain entirely +from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents +or other property right claims or to contest validity of any such claims; +this section has the sole purpose of protecting the integrity of the free +software distribution system which is implemented by public license practices. +Many people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose +that choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Library under this License may add an explicit geographical +distribution limitation excluding those countries, so that distribution is +permitted only in or among countries not thus excluded. In such case, this +License incorporates the limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of +the Library General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to address +new problems or concerns. + +Each version is given a distinguishing version number. If the Library specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Library does not specify a license version number, you may choose any version +ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs +whose distribution conditions are incompatible with these, write to the author +to ask for permission. For software which is copyrighted by the Free Software +Foundation, write to the Free Software Foundation; we sometimes make exceptions +for this. Our decision will be guided by the two goals of preserving the free +status of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE +OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA +OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES +OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH +HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest possible +use to the public, we recommend making it free software that everyone can +redistribute and change. You can do so by permitting redistribution under +these terms (or, alternatively, under the terms of the ordinary General Public +License). + +To apply these terms, attach the following notices to the library. It is safest +to attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the "copyright" +line and a pointer to where the full notice is found. + +one line to give the library's name and an idea of what it does. + +Copyright (C) year name of author + +This library is free software; you can redistribute it and/or modify it under +the terms of the GNU Library General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more +details. + +You should have received a copy of the GNU Library General Public License +along with this library; if not, write to the Free Software Foundation, Inc., +51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the library, if necessary. Here +is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in + +the library `Frob' (a library for tweaking knobs) written + +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 + +Ty Coon, President of Vice + +That's all there is to it! diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-2.1-only.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-2.1-only.txt new file mode 100644 index 0000000000..130dffb311 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-2.1-only.txt @@ -0,0 +1,467 @@ +GNU LESSER GENERAL PUBLIC LICENSE + +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. + +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts as the +successor of the GNU Library Public License, version 2, hence the version +number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public Licenses are intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. + +This license, the Lesser General Public License, applies to some specially +designated software packages--typically libraries--of the Free Software Foundation +and other authors who decide to use it. You can use it too, but we suggest +you first think carefully about whether this license or the ordinary General +Public License is the better strategy to use in any particular case, based +on the explanations below. + +When we speak of free software, we are referring to freedom of use, not price. +Our General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish); that you receive source code or can get it if you want it; that you +can change the software and use pieces of it in new free programs; and that +you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid distributors +to deny you these rights or to ask you to surrender these rights. These restrictions +translate to certain responsibilities for you if you distribute copies of +the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for +a fee, you must give the recipients all the rights that we gave you. You must +make sure that they, too, receive or can get the source code. If you link +other code with the library, you must provide complete object files to the +recipients, so that they can relink them with the library after making changes +to the library and recompiling it. And you must show them these terms so they +know their rights. + +We protect your rights with a two-step method: (1) we copyright the library, +and (2) we offer you this license, which gives you legal permission to copy, +distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no +warranty for the free library. Also, if the library is modified by someone +else and passed on, the recipients should know that what they have is not +the original version, so that the original author's reputation will not be +affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any free +program. We wish to make sure that a company cannot effectively restrict the +users of a free program by obtaining a restrictive license from a patent holder. +Therefore, we insist that any patent license obtained for a version of the +library must be consistent with the full freedom of use specified in this +license. + +Most GNU software, including some libraries, is covered by the ordinary GNU +General Public License. This license, the GNU Lesser General Public License, +applies to certain designated libraries, and is quite different from the ordinary +General Public License. We use this license for certain libraries in order +to permit linking those libraries into non-free programs. + +When a program is linked with a library, whether statically or using a shared +library, the combination of the two is legally speaking a combined work, a +derivative of the original library. The ordinary General Public License therefore +permits such linking only if the entire combination fits its criteria of freedom. +The Lesser General Public License permits more lax criteria for linking other +code with the library. + +We call this license the "Lesser" General Public License because it does Less +to protect the user's freedom than the ordinary General Public License. It +also provides other free software developers Less of an advantage over competing +non-free programs. These disadvantages are the reason we use the ordinary +General Public License for many libraries. However, the Lesser license provides +advantages in certain special circumstances. + +For example, on rare occasions, there may be a special need to encourage the +widest possible use of a certain library, so that it becomes a de-facto standard. +To achieve this, non-free programs must be allowed to use the library. A more +frequent case is that a free library does the same job as widely used non-free +libraries. In this case, there is little to gain by limiting the free library +to free software only, so we use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free programs +enables a greater number of people to use a large body of free software. For +example, permission to use the GNU C Library in non-free programs enables +many more people to use the whole GNU operating system, as well as its variant, +the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' +freedom, it does ensure that the user of a program that is linked with the +Library has the freedom and the wherewithal to run that program using a modified +version of the Library. + +The precise terms and conditions for copying, distribution and modification +follow. Pay close attention to the difference between a "work based on the +library" and a "work that uses the library". The former contains code derived +from the library, whereas the latter must be combined with the library in +order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program +which contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Lesser General +Public License (also called "this License"). Each licensee is addressed as +"you". + +A "library" means a collection of software functions and/or data prepared +so as to be conveniently linked with application programs (which use some +of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has +been distributed under these terms. A "work based on the Library" means either +the Library or any derivative work under copyright law: that is to say, a +work containing the Library or a portion of it, either verbatim or with modifications +and/or translated straightforwardly into another language. (Hereinafter, translation +is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications +to it. For a library, complete source code means all the source code for all +modules it contains, plus any associated interface definition files, plus +the scripts used to control compilation and installation of the library. + +Activities other than copying, distribution and modification are not covered +by this License; they are outside its scope. The act of running a program +using the Library is not restricted, and output from such a program is covered +only if its contents constitute a work based on the Library (independent of +the use of the Library in a tool for writing it). Whether that is true depends +on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and disclaimer +of warranty; keep intact all the notices that refer to this License and to +the absence of any warranty; and distribute a copy of this License along with +the Library. + +You may charge a fee for the physical act of transferring a copy, and you +may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, +thus forming a work based on the Library, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all +of these conditions: + + a) The modified work must itself be a software library. + +b) You must cause the files modified to carry prominent notices stating that +you changed the files and the date of any change. + +c) You must cause the whole of the work to be licensed at no charge to all +third parties under the terms of this License. + +d) If a facility in the modified Library refers to a function or a table of +data to be supplied by an application program that uses the facility, other +than as an argument passed when the facility is invoked, then you must make +a good faith effort to ensure that, in the event an application does not supply +such function or table, the facility still operates, and performs whatever +part of its purpose remains meaningful. + +(For example, a function in a library to compute square roots has a purpose +that is entirely well-defined independent of the application. Therefore, Subsection +2d requires that any application-supplied function or table used by this function +must be optional: if the application does not supply it, the square root function +must still compute square roots.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Library, and can be reasonably +considered independent and separate works in themselves, then this License, +and its terms, do not apply to those sections when you distribute them as +separate works. But when you distribute the same sections as part of a whole +which is a work based on the Library, the distribution of the whole must be +on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise +the right to control the distribution of derivative or collective works based +on the Library. + +In addition, mere aggregation of another work not based on the Library with +the Library (or with a work based on the Library) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. + +3. You may opt to apply the terms of the ordinary GNU General Public License +instead of this License to a given copy of the Library. To do this, you must +alter all the notices that refer to this License, so that they refer to the +ordinary GNU General Public License, version 2, instead of to this License. +(If a newer version than version 2 of the ordinary GNU General Public License +has appeared, then you can specify that version instead if you wish.) Do not +make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, +so the ordinary GNU General Public License applies to all subsequent copies +and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library +into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of +it, under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you accompany it with the complete corresponding +machine-readable source code, which must be distributed under the terms of +Sections 1 and 2 above on a medium customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a designated +place, then offering equivalent access to copy the source code from the same +place satisfies the requirement to distribute the source code, even though +third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but +is designed to work with the Library by being compiled or linked with it, +is called a "work that uses the Library". Such a work, in isolation, is not +a derivative work of the Library, and therefore falls outside the scope of +this License. + +However, linking a "work that uses the Library" with the Library creates an +executable that is a derivative of the Library (because it contains portions +of the Library), rather than a "work that uses the library". The executable +is therefore covered by this License. Section 6 states terms for distribution +of such executables. + +When a "work that uses the Library" uses material from a header file that +is part of the Library, the object code for the work may be a derivative work +of the Library even though the source code is not. Whether this is true is +especially significant if the work can be linked without the Library, or if +the work is itself a library. The threshold for this to be true is not precisely +defined by law. + +If such an object file uses only numerical parameters, data structure layouts +and accessors, and small macros and small inline functions (ten lines or less +in length), then the use of the object file is unrestricted, regardless of +whether it is legally a derivative work. (Executables containing this object +code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute +the object code for the work under the terms of Section 6. Any executables +containing that work also fall under Section 6, whether or not they are linked +directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a "work +that uses the Library" with the Library to produce a work containing portions +of the Library, and distribute that work under terms of your choice, provided +that the terms permit modification of the work for the customer's own use +and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library +is used in it and that the Library and its use are covered by this License. +You must supply a copy of this License. If the work during execution displays +copyright notices, you must include the copyright notice for the Library among +them, as well as a reference directing the user to the copy of this License. +Also, you must do one of these things: + +a) Accompany the work with the complete corresponding machine-readable source +code for the Library including whatever changes were used in the work (which +must be distributed under Sections 1 and 2 above); and, if the work is an +executable linked with the Library, with the complete machine-readable "work +that uses the Library", as object code and/or source code, so that the user +can modify the Library and then relink to produce a modified executable containing +the modified Library. (It is understood that the user who changes the contents +of definitions files in the Library will not necessarily be able to recompile +the application to use the modified definitions.) + +b) Use a suitable shared library mechanism for linking with the Library. A +suitable mechanism is one that (1) uses at run time a copy of the library +already present on the user's computer system, rather than copying library +functions into the executable, and (2) will operate properly with a modified +version of the library, if the user installs one, as long as the modified +version is interface-compatible with the version that the work was made with. + +c) Accompany the work with a written offer, valid for at least three years, +to give the same user the materials specified in Subsection 6a, above, for +a charge no more than the cost of performing this distribution. + +d) If distribution of the work is made by offering access to copy from a designated +place, offer equivalent access to copy the above specified materials from +the same place. + +e) Verify that the user has already received a copy of these materials or +that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" must +include any data and utility programs needed for reproducing the executable +from it. However, as a special exception, the materials to be distributed +need not include anything that is normally distributed (in either source or +binary form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component itself +accompanies the executable. + +It may happen that this requirement contradicts the license restrictions of +other proprietary libraries that do not normally accompany the operating system. +Such a contradiction means you cannot use both them and the Library together +in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library side-by-side +in a single library together with other library facilities not covered by +this License, and distribute such a combined library, provided that the separate +distribution of the work based on the Library and of the other library facilities +is otherwise permitted, and provided that you do these two things: + +a) Accompany the combined library with a copy of the same work based on the +Library, uncombined with any other library facilities. This must be distributed +under the terms of the Sections above. + +b) Give prominent notice with the combined library of the fact that part of +it is a work based on the Library, and explaining where to find the accompanying +uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the Library +except as expressly provided under this License. Any attempt otherwise to +copy, modify, sublicense, link with, or distribute the Library is void, and +will automatically terminate your rights under this License. However, parties +who have received copies, or rights, from you under this License will not +have their licenses terminated so long as such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Library or its derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or distributing the Library +(or any work based on the Library), you indicate your acceptance of this License +to do so, and all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), +the recipient automatically receives a license from the original licensor +to copy, distribute, link with or modify the Library subject to these terms +and conditions. You may not impose any further restrictions on the recipients' +exercise of the rights granted herein. You are not responsible for enforcing +compliance by third parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent infringement +or for any other reason (not limited to patent issues), conditions are imposed +on you (whether by court order, agreement or otherwise) that contradict the +conditions of this License, they do not excuse you from the conditions of +this License. If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, then as +a consequence you may not distribute the Library at all. For example, if a +patent license would not permit royalty-free redistribution of the Library +by all those who receive copies directly or indirectly through you, then the +only way you could satisfy both it and this License would be to refrain entirely +from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents +or other property right claims or to contest validity of any such claims; +this section has the sole purpose of protecting the integrity of the free +software distribution system which is implemented by public license practices. +Many people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose +that choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Library under this License may add an explicit geographical +distribution limitation excluding those countries, so that distribution is +permitted only in or among countries not thus excluded. In such case, this +License incorporates the limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of +the Lesser General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to address +new problems or concerns. + +Each version is given a distinguishing version number. If the Library specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Library does not specify a license version number, you may choose any version +ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs +whose distribution conditions are incompatible with these, write to the author +to ask for permission. For software which is copyrighted by the Free Software +Foundation, write to the Free Software Foundation; we sometimes make exceptions +for this. Our decision will be guided by the two goals of preserving the free +status of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE +OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA +OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES +OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH +HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest possible +use to the public, we recommend making it free software that everyone can +redistribute and change. You can do so by permitting redistribution under +these terms (or, alternatively, under the terms of the ordinary General Public +License). + +To apply these terms, attach the following notices to the library. It is safest +to attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the "copyright" +line and a pointer to where the full notice is found. + +< one line to give the library's name and an idea of what it does. > + +Copyright (C) < year > < name of author > + +This library is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the Free +Software Foundation; either version 2.1 of the License, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. + +You should have received a copy of the GNU Lesser General Public License along +with this library; if not, write to the Free Software Foundation, Inc., 51 +Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information +on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the library, if necessary. Here +is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in + +the library `Frob' (a library for tweaking knobs) written + +by James Random Hacker. + +< signature of Ty Coon > , 1 April 1990 + +Ty Coon, President of Vice + +That's all there is to it! diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-2.1-or-later.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-2.1-or-later.txt new file mode 100644 index 0000000000..04bb156e77 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-2.1-or-later.txt @@ -0,0 +1,468 @@ +GNU LESSER GENERAL PUBLIC LICENSE + +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. + +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts as the +successor of the GNU Library Public License, version 2, hence the version +number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to share +and change it. By contrast, the GNU General Public Licenses are intended to +guarantee your freedom to share and change free software--to make sure the +software is free for all its users. + +This license, the Lesser General Public License, applies to some specially +designated software packages--typically libraries--of the Free Software Foundation +and other authors who decide to use it. You can use it too, but we suggest +you first think carefully about whether this license or the ordinary General +Public License is the better strategy to use in any particular case, based +on the explanations below. + +When we speak of free software, we are referring to freedom of use, not price. +Our General Public Licenses are designed to make sure that you have the freedom +to distribute copies of free software (and charge for this service if you +wish); that you receive source code or can get it if you want it; that you +can change the software and use pieces of it in new free programs; and that +you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid distributors +to deny you these rights or to ask you to surrender these rights. These restrictions +translate to certain responsibilities for you if you distribute copies of +the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for +a fee, you must give the recipients all the rights that we gave you. You must +make sure that they, too, receive or can get the source code. If you link +other code with the library, you must provide complete object files to the +recipients, so that they can relink them with the library after making changes +to the library and recompiling it. And you must show them these terms so they +know their rights. + +We protect your rights with a two-step method: (1) we copyright the library, +and (2) we offer you this license, which gives you legal permission to copy, +distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no +warranty for the free library. Also, if the library is modified by someone +else and passed on, the recipients should know that what they have is not +the original version, so that the original author's reputation will not be +affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any free +program. We wish to make sure that a company cannot effectively restrict the +users of a free program by obtaining a restrictive license from a patent holder. +Therefore, we insist that any patent license obtained for a version of the +library must be consistent with the full freedom of use specified in this +license. + +Most GNU software, including some libraries, is covered by the ordinary GNU +General Public License. This license, the GNU Lesser General Public License, +applies to certain designated libraries, and is quite different from the ordinary +General Public License. We use this license for certain libraries in order +to permit linking those libraries into non-free programs. + +When a program is linked with a library, whether statically or using a shared +library, the combination of the two is legally speaking a combined work, a +derivative of the original library. The ordinary General Public License therefore +permits such linking only if the entire combination fits its criteria of freedom. +The Lesser General Public License permits more lax criteria for linking other +code with the library. + +We call this license the "Lesser" General Public License because it does Less +to protect the user's freedom than the ordinary General Public License. It +also provides other free software developers Less of an advantage over competing +non-free programs. These disadvantages are the reason we use the ordinary +General Public License for many libraries. However, the Lesser license provides +advantages in certain special circumstances. + +For example, on rare occasions, there may be a special need to encourage the +widest possible use of a certain library, so that it becomes a de-facto standard. +To achieve this, non-free programs must be allowed to use the library. A more +frequent case is that a free library does the same job as widely used non-free +libraries. In this case, there is little to gain by limiting the free library +to free software only, so we use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free programs +enables a greater number of people to use a large body of free software. For +example, permission to use the GNU C Library in non-free programs enables +many more people to use the whole GNU operating system, as well as its variant, +the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' +freedom, it does ensure that the user of a program that is linked with the +Library has the freedom and the wherewithal to run that program using a modified +version of the Library. + +The precise terms and conditions for copying, distribution and modification +follow. Pay close attention to the difference between a "work based on the +library" and a "work that uses the library". The former contains code derived +from the library, whereas the latter must be combined with the library in +order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program +which contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Lesser General +Public License (also called "this License"). Each licensee is addressed as +"you". + +A "library" means a collection of software functions and/or data prepared +so as to be conveniently linked with application programs (which use some +of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has +been distributed under these terms. A "work based on the Library" means either +the Library or any derivative work under copyright law: that is to say, a +work containing the Library or a portion of it, either verbatim or with modifications +and/or translated straightforwardly into another language. (Hereinafter, translation +is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications +to it. For a library, complete source code means all the source code for all +modules it contains, plus any associated interface definition files, plus +the scripts used to control compilation and installation of the library. + +Activities other than copying, distribution and modification are not covered +by this License; they are outside its scope. The act of running a program +using the Library is not restricted, and output from such a program is covered +only if its contents constitute a work based on the Library (independent of +the use of the Library in a tool for writing it). Whether that is true depends +on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and disclaimer +of warranty; keep intact all the notices that refer to this License and to +the absence of any warranty; and distribute a copy of this License along with +the Library. + +You may charge a fee for the physical act of transferring a copy, and you +may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, +thus forming a work based on the Library, and copy and distribute such modifications +or work under the terms of Section 1 above, provided that you also meet all +of these conditions: + + a) The modified work must itself be a software library. + +b) You must cause the files modified to carry prominent notices stating that +you changed the files and the date of any change. + +c) You must cause the whole of the work to be licensed at no charge to all +third parties under the terms of this License. + +d) If a facility in the modified Library refers to a function or a table of +data to be supplied by an application program that uses the facility, other +than as an argument passed when the facility is invoked, then you must make +a good faith effort to ensure that, in the event an application does not supply +such function or table, the facility still operates, and performs whatever +part of its purpose remains meaningful. + +(For example, a function in a library to compute square roots has a purpose +that is entirely well-defined independent of the application. Therefore, Subsection +2d requires that any application-supplied function or table used by this function +must be optional: if the application does not supply it, the square root function +must still compute square roots.) + +These requirements apply to the modified work as a whole. If identifiable +sections of that work are not derived from the Library, and can be reasonably +considered independent and separate works in themselves, then this License, +and its terms, do not apply to those sections when you distribute them as +separate works. But when you distribute the same sections as part of a whole +which is a work based on the Library, the distribution of the whole must be +on the terms of this License, whose permissions for other licensees extend +to the entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest your +rights to work written entirely by you; rather, the intent is to exercise +the right to control the distribution of derivative or collective works based +on the Library. + +In addition, mere aggregation of another work not based on the Library with +the Library (or with a work based on the Library) on a volume of a storage +or distribution medium does not bring the other work under the scope of this +License. + +3. You may opt to apply the terms of the ordinary GNU General Public License +instead of this License to a given copy of the Library. To do this, you must +alter all the notices that refer to this License, so that they refer to the +ordinary GNU General Public License, version 2, instead of to this License. +(If a newer version than version 2 of the ordinary GNU General Public License +has appeared, then you can specify that version instead if you wish.) Do not +make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, +so the ordinary GNU General Public License applies to all subsequent copies +and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library +into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of +it, under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you accompany it with the complete corresponding +machine-readable source code, which must be distributed under the terms of +Sections 1 and 2 above on a medium customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a designated +place, then offering equivalent access to copy the source code from the same +place satisfies the requirement to distribute the source code, even though +third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but +is designed to work with the Library by being compiled or linked with it, +is called a "work that uses the Library". Such a work, in isolation, is not +a derivative work of the Library, and therefore falls outside the scope of +this License. + +However, linking a "work that uses the Library" with the Library creates an +executable that is a derivative of the Library (because it contains portions +of the Library), rather than a "work that uses the library". The executable +is therefore covered by this License. Section 6 states terms for distribution +of such executables. + +When a "work that uses the Library" uses material from a header file that +is part of the Library, the object code for the work may be a derivative work +of the Library even though the source code is not. Whether this is true is +especially significant if the work can be linked without the Library, or if +the work is itself a library. The threshold for this to be true is not precisely +defined by law. + +If such an object file uses only numerical parameters, data structure layouts +and accessors, and small macros and small inline functions (ten lines or less +in length), then the use of the object file is unrestricted, regardless of +whether it is legally a derivative work. (Executables containing this object +code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute +the object code for the work under the terms of Section 6. Any executables +containing that work also fall under Section 6, whether or not they are linked +directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a "work +that uses the Library" with the Library to produce a work containing portions +of the Library, and distribute that work under terms of your choice, provided +that the terms permit modification of the work for the customer's own use +and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library +is used in it and that the Library and its use are covered by this License. +You must supply a copy of this License. If the work during execution displays +copyright notices, you must include the copyright notice for the Library among +them, as well as a reference directing the user to the copy of this License. +Also, you must do one of these things: + +a) Accompany the work with the complete corresponding machine-readable source +code for the Library including whatever changes were used in the work (which +must be distributed under Sections 1 and 2 above); and, if the work is an +executable linked with the Library, with the complete machine-readable "work +that uses the Library", as object code and/or source code, so that the user +can modify the Library and then relink to produce a modified executable containing +the modified Library. (It is understood that the user who changes the contents +of definitions files in the Library will not necessarily be able to recompile +the application to use the modified definitions.) + +b) Use a suitable shared library mechanism for linking with the Library. A +suitable mechanism is one that (1) uses at run time a copy of the library +already present on the user's computer system, rather than copying library +functions into the executable, and (2) will operate properly with a modified +version of the library, if the user installs one, as long as the modified +version is interface-compatible with the version that the work was made with. + +c) Accompany the work with a written offer, valid for at least three years, +to give the same user the materials specified in Subsection 6a, above, for +a charge no more than the cost of performing this distribution. + +d) If distribution of the work is made by offering access to copy from a designated +place, offer equivalent access to copy the above specified materials from +the same place. + +e) Verify that the user has already received a copy of these materials or +that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" must +include any data and utility programs needed for reproducing the executable +from it. However, as a special exception, the materials to be distributed +need not include anything that is normally distributed (in either source or +binary form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component itself +accompanies the executable. + +It may happen that this requirement contradicts the license restrictions of +other proprietary libraries that do not normally accompany the operating system. +Such a contradiction means you cannot use both them and the Library together +in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library side-by-side +in a single library together with other library facilities not covered by +this License, and distribute such a combined library, provided that the separate +distribution of the work based on the Library and of the other library facilities +is otherwise permitted, and provided that you do these two things: + +a) Accompany the combined library with a copy of the same work based on the +Library, uncombined with any other library facilities. This must be distributed +under the terms of the Sections above. + +b) Give prominent notice with the combined library of the fact that part of +it is a work based on the Library, and explaining where to find the accompanying +uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the Library +except as expressly provided under this License. Any attempt otherwise to +copy, modify, sublicense, link with, or distribute the Library is void, and +will automatically terminate your rights under this License. However, parties +who have received copies, or rights, from you under this License will not +have their licenses terminated so long as such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed +it. However, nothing else grants you permission to modify or distribute the +Library or its derivative works. These actions are prohibited by law if you +do not accept this License. Therefore, by modifying or distributing the Library +(or any work based on the Library), you indicate your acceptance of this License +to do so, and all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), +the recipient automatically receives a license from the original licensor +to copy, distribute, link with or modify the Library subject to these terms +and conditions. You may not impose any further restrictions on the recipients' +exercise of the rights granted herein. You are not responsible for enforcing +compliance by third parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent infringement +or for any other reason (not limited to patent issues), conditions are imposed +on you (whether by court order, agreement or otherwise) that contradict the +conditions of this License, they do not excuse you from the conditions of +this License. If you cannot distribute so as to satisfy simultaneously your +obligations under this License and any other pertinent obligations, then as +a consequence you may not distribute the Library at all. For example, if a +patent license would not permit royalty-free redistribution of the Library +by all those who receive copies directly or indirectly through you, then the +only way you could satisfy both it and this License would be to refrain entirely +from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents +or other property right claims or to contest validity of any such claims; +this section has the sole purpose of protecting the integrity of the free +software distribution system which is implemented by public license practices. +Many people have made generous contributions to the wide range of software +distributed through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing to +distribute software through any other system and a licensee cannot impose +that choice. + +This section is intended to make thoroughly clear what is believed to be a +consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain +countries either by patents or by copyrighted interfaces, the original copyright +holder who places the Library under this License may add an explicit geographical +distribution limitation excluding those countries, so that distribution is +permitted only in or among countries not thus excluded. In such case, this +License incorporates the limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of +the Lesser General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to address +new problems or concerns. + +Each version is given a distinguishing version number. If the Library specifies +a version number of this License which applies to it and "any later version", +you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the +Library does not specify a license version number, you may choose any version +ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs +whose distribution conditions are incompatible with these, write to the author +to ask for permission. For software which is copyrighted by the Free Software +Foundation, write to the Free Software Foundation; we sometimes make exceptions +for this. Our decision will be guided by the two goals of preserving the free +status of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR +THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE +STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE +OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE +THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE +OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA +OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES +OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH +HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest possible +use to the public, we recommend making it free software that everyone can +redistribute and change. You can do so by permitting redistribution under +these terms (or, alternatively, under the terms of the ordinary General Public +License). + +To apply these terms, attach the following notices to the library. It is safest +to attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the "copyright" +line and a pointer to where the full notice is found. + + + +Copyright (C) + +This library is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the Free +Software Foundation; either version 2.1 of the License, or (at your option) +any later version. + +This library is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +details. + +You should have received a copy of the GNU Lesser General Public License along +with this library; if not, write to the Free Software Foundation, Inc., 51 +Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your school, +if any, to sign a "copyright disclaimer" for the library, if necessary. Here +is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in + +the library `Frob' (a library for tweaking knobs) written + +by James Random Hacker. + +< signature of Ty Coon > , 1 April 1990 + +Ty Coon, President of Vice + +That's all there is to it! diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-3.0-only.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-3.0-only.txt new file mode 100644 index 0000000000..bd405afbef --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/LGPL-3.0-only.txt @@ -0,0 +1,163 @@ +GNU LESSER GENERAL PUBLIC LICENSE + +Version 3, 29 June 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license +document, but changing it is not allowed. + +This version of the GNU Lesser General Public License incorporates the terms +and conditions of version 3 of the GNU General Public License, supplemented +by the additional permissions listed below. + + 0. Additional Definitions. + + + +As used herein, "this License" refers to version 3 of the GNU Lesser General +Public License, and the "GNU GPL" refers to version 3 of the GNU General Public +License. + + + +"The Library" refers to a covered work governed by this License, other than +an Application or a Combined Work as defined below. + + + +An "Application" is any work that makes use of an interface provided by the +Library, but which is not otherwise based on the Library. Defining a subclass +of a class defined by the Library is deemed a mode of using an interface provided +by the Library. + + + +A "Combined Work" is a work produced by combining or linking an Application +with the Library. The particular version of the Library with which the Combined +Work was made is also called the "Linked Version". + + + +The "Minimal Corresponding Source" for a Combined Work means the Corresponding +Source for the Combined Work, excluding any source code for portions of the +Combined Work that, considered in isolation, are based on the Application, +and not on the Linked Version. + + + +The "Corresponding Application Code" for a Combined Work means the object +code and/or source code for the Application, including any data and utility +programs needed for reproducing the Combined Work from the Application, but +excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + +You may convey a covered work under sections 3 and 4 of this License without +being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + +If you modify a copy of the Library, and, in your modifications, a facility +refers to a function or data to be supplied by an Application that uses the +facility (other than as an argument passed when the facility is invoked), +then you may convey a copy of the modified version: + +a) under this License, provided that you make a good faith effort to ensure +that, in the event an Application does not supply the function or data, the +facility still operates, and performs whatever part of its purpose remains +meaningful, or + +b) under the GNU GPL, with none of the additional permissions of this License +applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + +The object code form of an Application may incorporate material from a header +file that is part of the Library. You may convey such object code under terms +of your choice, provided that, if the incorporated material is not limited +to numerical parameters, data structure layouts and accessors, or small macros, +inline functions and templates (ten or fewer lines in length), you do both +of the following: + +a) Give prominent notice with each copy of the object code that the Library +is used in it and that the Library and its use are covered by this License. + +b) Accompany the object code with a copy of the GNU GPL and this license document. + + 4. Combined Works. + +You may convey a Combined Work under terms of your choice that, taken together, +effectively do not restrict modification of the portions of the Library contained +in the Combined Work and reverse engineering for debugging such modifications, +if you also do each of the following: + +a) Give prominent notice with each copy of the Combined Work that the Library +is used in it and that the Library and its use are covered by this License. + +b) Accompany the Combined Work with a copy of the GNU GPL and this license +document. + +c) For a Combined Work that displays copyright notices during execution, include +the copyright notice for the Library among these notices, as well as a reference +directing the user to the copies of the GNU GPL and this license document. + + d) Do one of the following: + +0) Convey the Minimal Corresponding Source under the terms of this License, +and the Corresponding Application Code in a form suitable for, and under terms +that permit, the user to recombine or relink the Application with a modified +version of the Linked Version to produce a modified Combined Work, in the +manner specified by section 6 of the GNU GPL for conveying Corresponding Source. + +1) Use a suitable shared library mechanism for linking with the Library. A +suitable mechanism is one that (a) uses at run time a copy of the Library +already present on the user's computer system, and (b) will operate properly +with a modified version of the Library that is interface-compatible with the +Linked Version. + +e) Provide Installation Information, but only if you would otherwise be required +to provide such information under section 6 of the GNU GPL, and only to the +extent that such information is necessary to install and execute a modified +version of the Combined Work produced by recombining or relinking the Application +with a modified version of the Linked Version. (If you use option 4d0, the +Installation Information must accompany the Minimal Corresponding Source and +Corresponding Application Code. If you use option 4d1, you must provide the +Installation Information in the manner specified by section 6 of the GNU GPL +for conveying Corresponding Source.) + + 5. Combined Libraries. + +You may place library facilities that are a work based on the Library side +by side in a single library together with other library facilities that are +not Applications and are not covered by this License, and convey such a combined +library under terms of your choice, if you do both of the following: + +a) Accompany the combined library with a copy of the same work based on the +Library, uncombined with any other library facilities, conveyed under the +terms of this License. + +b) Give prominent notice with the combined library that part of it is a work +based on the Library, and explaining where to find the accompanying uncombined +form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + +The Free Software Foundation may publish revised and/or new versions of the +GNU Lesser General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to address +new problems or concerns. + +Each version is given a distinguishing version number. If the Library as you +received it specifies that a certain numbered version of the GNU Lesser General +Public License "or any later version" applies to it, you have the option of +following the terms and conditions either of that published version or of +any later version published by the Free Software Foundation. If the Library +as you received it does not specify a version number of the GNU Lesser General +Public License, you may choose any version of the GNU Lesser General Public +License ever published by the Free Software Foundation. + +If the Library as you received it specifies that a proxy can decide whether +future versions of the GNU Lesser General Public License shall apply, that +proxy's public statement of acceptance of any version is permanent authorization +for you to choose that version for the Library. diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/LicenseRef-KDE-Accepted-GPL.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/LicenseRef-KDE-Accepted-GPL.txt new file mode 100644 index 0000000000..60a2dffc9c --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/LicenseRef-KDE-Accepted-GPL.txt @@ -0,0 +1,12 @@ +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 3 of +the license or (at your option) at any later version that is +accepted by the membership of KDE e.V. (or its successor +approved by the membership of KDE e.V.), which shall act as a +proxy as defined in Section 14 of version 3 of the license. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/LicenseRef-KDE-Accepted-LGPL.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/LicenseRef-KDE-Accepted-LGPL.txt new file mode 100644 index 0000000000..232b3c5da1 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/LicenseRef-KDE-Accepted-LGPL.txt @@ -0,0 +1,12 @@ +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the license or (at your option) any later version +that is accepted by the membership of KDE e.V. (or its successor +approved by the membership of KDE e.V.), which shall act as a +proxy as defined in Section 6 of version 3 of the license. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/LicenseRef-Qt-Commercial.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/LicenseRef-Qt-Commercial.txt new file mode 100644 index 0000000000..11e00c7426 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/LicenseRef-Qt-Commercial.txt @@ -0,0 +1,7 @@ +Commercial License Usage +Licensees holding valid commercial Qt licenses may use this file in +accordance with the commercial license agreement provided with the +Software or, alternatively, in accordance with the terms contained in +a written agreement between you and The Qt Company. For licensing terms +and conditions see https://www.qt.io/terms-conditions. For further +information use the contact form at https://www.qt.io/contact-us. diff --git a/local/recipes/kde/kf6-ksvg/source/LICENSES/Qt-LGPL-exception-1.1.txt b/local/recipes/kde/kf6-ksvg/source/LICENSES/Qt-LGPL-exception-1.1.txt new file mode 100644 index 0000000000..d0f532e9e1 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/LICENSES/Qt-LGPL-exception-1.1.txt @@ -0,0 +1,21 @@ +The Qt Company Qt LGPL Exception version 1.1 + +As an additional permission to the GNU Lesser General Public License version 2.1, the object code form of a "work that uses the Library" may incorporate material from a header file that is part of the Library. You may distribute such object code under terms of your choice, provided that: + + (i) the header files of the Library have not been modified; and + + (ii) the incorporated material is limited to numerical parameters, data structure layouts, accessors, macros, inline functions and templates; and + + (iii) you comply with the terms of Section 6 of the GNU Lesser General Public License version 2.1. + +Moreover, you may apply this exception to a modified version of the Library, provided that such modification does not involve copying material from the Library into the modified Library's header files unless such material is limited to + + (i) numerical parameters; + + (ii) data structure layouts; + + (iii) accessors; and + + (iv) small macros, templates and inline functions of five lines or less in length. + +Furthermore, you are not required to apply this additional permission to a modified version of the Library. diff --git a/local/recipes/kde/kf6-ksvg/source/Mainpage.dox b/local/recipes/kde/kf6-ksvg/source/Mainpage.dox new file mode 100644 index 0000000000..e87096783d --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/Mainpage.dox @@ -0,0 +1,67 @@ +/** @mainpage KSvg framework + +\section Introduction + +The KSvg framework introduces a series of apis to render SVG based graphics both with a QPainter-based api and and accelerated QtQuick component set. + +The Qt Quick +framework and set of KDE Frameworks +provide the underpinning for KSvg framework. As a result, it should +work anywhere that Qt does. + +Important classes are: + + - KSvg::Svg and KSvg::FrameSvg: provides themable, cached SVGs + +\subsection types All Types +- \link KSvg::Svg Svg \endlink +- \link KSvg::SvgItem SvgItem \endlink +- \link KSvg::FrameSvg FrameSvg \endlink +- \link KSvg::FrameSvgItem FrameSvgItem \endlink +- \link KSvg::FrameSvgItemMargins FrameSvgItemMargins \endlink +- \link KSvg::ImageSet ImageSet \endlink +- \link ImageTexturesCache ImageTexturesCache \endlink + +@authors +Aaron Seigo \
+Alessandro Diaferia \
+Alex Merry \
+Alexander Wiedenbruch \
+Alexis Ménard \
+André Duffeck \
+Andrew Lake \
+Artur de Souza \
+Bertjan Broeksema \
+Chani Armitage \
+Davide Bettio \
+Dan Meltzer \
+Fredrik Höglund \
+Ivan Cukic \
+John Tapsell \
+Jordi Polo \
+Kevin Ottens \
+Montel Laurent \
+Marco Martin \
+Matt Broadstone \
+Petri Damsten \
+Rafael Fernández López \
+Riccardo Iaconelli \
+Richard J. Moore \
+Rob Scheepmaker \
+Robert Knight \
+Sebastian Kuegler \
+Siraj Razick \
+Zack Rusin \ + +@maintainers +Marco Martin \ + +@licenses +@lgpl + +*/ + +// DOXYGEN_SET_PROJECT_NAME = KSvg +// DOXYGEN_SET_RECURSIVE = YES +// DOXYGEN_EXCLUDE_PATTERNS = *_p.h */private/* */tests/* +// vim:ts=4:sw=4:expandtab:filetype=doxygen diff --git a/local/recipes/kde/kf6-ksvg/source/README.md b/local/recipes/kde/kf6-ksvg/source/README.md new file mode 100644 index 0000000000..8e4254718d --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/README.md @@ -0,0 +1,43 @@ +# KSvg +A library for rendering SVG-based themes with stylesheet re-coloring and on-disk caching. + +## Introduction +KSvg provides both C++ classes and QtQuick components to render svgs based on image packs. +Compared to plain QSvg, it caches the rendered images on disk with KImageCache, and can re-color +properly crafted svg shapes that include internal stylesheets. + +The default behavior is to re-color with the application palette, making it possible to create UI elements in SVG. + +## C++ +In C++ there are 3 main classes, usable also in QWidget applications with a QPainter-compatible API: + +* ``ImageSet``: Used to tell the other classes where to find the SVG files: by default, SVG "themes" + will be searched in the application data dir (share/application_name/theme_name) +* ``Svg``: Class to used to render Svg files: it loads a file with ``setImagePath`` using relative paths + to the theme specified in ``ImageSet`` +* ``FrameSvg``: A subclass of Svg used to render 9-patch images, such as Buttons, where you want to stretch + only the central area but not the edges + +## QML +Import QML bindings with ``import org.kde.ksvg 1.0 as KSvg``. + +ImageSet is exported directly to QML which makes it possible to set the theme from QML. + +Svg and FrameSvg have corresponding items, ``SvgItem`` and ``FrameSvgItem``, which inherit from QQuickItem +and will paint their associated ``Svg`` or ``FrameSvg`` stretched to their full geometry. + +QML code example: + +``` +FrameSvgItem { + // This resolves to a file like /usr/share/myapp/mytheme/widgets/button.svgz + imagePath: "widgets/button" + prefix: "pressed" +} +``` + +## More documentation +Assume the theme filesystem hierarchy used by the Plasma shell, but the general concepts apply everywhere: + +* https://develop.kde.org/docs/plasma/theme/theme-elements/ +* https://develop.kde.org/docs/plasma/theme/quickstart/ diff --git a/local/recipes/kde/kf6-ksvg/source/autotests/CMakeLists.txt b/local/recipes/kde/kf6-ksvg/source/autotests/CMakeLists.txt new file mode 100644 index 0000000000..71f5f3f5a8 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/autotests/CMakeLists.txt @@ -0,0 +1,29 @@ +find_package(Qt6Test ${REQUIRED_QT_VERSION} REQUIRED NO_MODULE) +set_package_properties(Qt6Test PROPERTIES PURPOSE "Required for tests") + +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) +remove_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_STRICT_ITERATORS -DQT_NO_CAST_FROM_BYTEARRAY -DQT_NO_KEYWORDS) + +include(ECMMarkAsTest) +include(ECMAddTests) + +MACRO(KSVG_UNIT_TESTS) + FOREACH(_testname ${ARGN}) + set(libs Qt6::Qml Qt6::Test KF6::Svg + KF6::Archive KF6::CoreAddons KF6::ConfigGui) + if(QT_QTOPENGL_FOUND) + list(APPEND libs Qt6::OpenGL) + endif() + ecm_add_test(${_testname}.cpp + LINK_LIBRARIES ${libs} + NAME_PREFIX "plasmasvg-") + qt_add_resources(${_testname} "images" + FILES "data/background.svgz") + target_include_directories(${_testname} PRIVATE ) + ENDFOREACH(_testname) +ENDMACRO(KSVG_UNIT_TESTS) + +KSVG_UNIT_TESTS( + framesvgtest +) + diff --git a/local/recipes/kde/kf6-ksvg/source/autotests/data/background.svgz b/local/recipes/kde/kf6-ksvg/source/autotests/data/background.svgz new file mode 100644 index 0000000000000000000000000000000000000000..70a668aa314b238a2997704e02c3e175f998c657 GIT binary patch literal 2879 zcmV-F3&8XriwFP!000000PR~@SK`VRe(ztA%XvAyBtxY#(&$~tpkSk-pu)>tAt@n1 z5=_GQ>u*)a$l%b&?qi>0TnbgYb`5*@YFA}j{O{75P;=yZreh!H0K?@dWb2M$+Joa< zr(L6!9Oe0%ZDjc zR6w}^%Dk9mHXNPI=Q!8b^zp!TX12lLQP$ahoS8qJ`Ts*pAK9A@@j_Co3djK;lUY*6 z#7}TdF&>zVYRpZvAni7*>ucVIjiRR70NdEaagTFSm0;yA}|6W5Mo;c7Wvq_nGT<7#hNcVkbf?Unkv2pS+ zq>weI>OnNlNQmA6Arjg%QVbViX-m^G*T^92JPFzqGm6--;qh#3IyXJD zKS87#V+`^fd$P*(PEp935(o(JUQB9j4f7dWZNu)iYKc{l5g?4!Mp6EX0MBwo2sw%k zJdWLUxuD)ak6z+?q=cbGh`21|Ylh})NsFikw~`|fU??x#RB9*T_(feW+&k_#nhr&g z23jBE!*MQm5?2=uy@27=()<(C!d^#k`v}8lkxdAh#$;Vdr<-nFw87=QTbZF-CShW4 zeRDFYlR?6jr8+hJ2}&x9Y&iShZ8iUti5Jc~P2Q zKbFMWx-ORt(kE4_PHOG(?W|>$%T#Jj5xi#v5^e*$l&bUm6~VZ0doFNzw@jPLRP%?= zHvaaAEv)dzWAFq8IwFHj(Vb0D!FKF54idh3zUz#GB1%nyz#Jur3`ZW27iIhnD3U~R zdB8KOssJcZyp-oCVhwSPPT??+<5W2xd;1wn8?z{|#w zBwn=?OCc(!WB?f+(Zb6z5D&^A)kDa(K5Q!BT~z;C2^QJGHh844BKSJN2edzFz#$q7 z1ANVF*}gM9h#ULdVz2-F6M-T)-UQJ%O=NT!J-5;IO~CPzmUkV4m!y{*<6|Mj`(ooe zNb;w+>xTxY$aX|tfqQ_%#o~$@6KfV?R&48H;{B2DrvM>@2qA+hLld9!u+!jEiaRjv zn6_gHN^A-or(k()3xA*D_rhEh5-}1dNFo4Og!qRiz912GD2&W=Duj6`FsclAPROF5 zj?bkyXp2p2kjQS|C{PfB0q_a{P()75Lq=4DJS{7bQ52}~U$><1JIkMD0t>>I0rJrwy z@GiEpL*~ZI3@`Aam^M0~Fe1;33fQqdfq}BPZGPge`QfP{Umwz&OBnB6Y%u)3xu7U; zQ4t?0kUPQ0alar$b%uub4%gLI8OFHR#G2E>_)Gq=BLQ-J*!IBP9X*z7TKtItk;@Xe z$M?d}AvmJE5I$r!$M+5&%FR^xP(pnFvUf0i=z>l7a9@9@0q*Q-vBKfQU8SvGtKZj8 z-=Avt{Yt;wz3H+NoO9N=)oCnS%S%+LpYfyixhEM7OaFq>YF4Ovtz5fD&iG;}pLQAG4S zOoyIlU3AVbZMOY5t2mdXp;+%-o-HqWR=r=+g__z7Av#s-hAvlJi1__AN7>h^r(S5m^ay3v)PyK8ltcsEW6NX$d@(os7I;G z(dd>t)5YFBcO!X=g|`MBp*FV87X9v(|NU}(*&g!UnS2J!@dElQ%k27d$&$^b#P!6r zNsTjyRJR!bK{(0rJ8^hHzgt}A-w`svc_Y3|S}w^8F9KJ`3} zD-G@}byRH*ue&8py6!AkyDs!hD2deUS|OHFy6xOu-CT&}ZoPhdI4H~<(6=0CdnbMC zfik`$a|}doEIhnP19qoSK|&h=shE+-i4i4UqyP>b@cxD4 zH42hH6G{!`__Gd_&m0p&40j14KYPyv$W0SR?wInt^!zoGaM&M`TPB#1@hAF!qW|xK z{?FYV{`eKZPrW;QPjHW~<{(slXcu~BQ+us+-tn;h>tQ_+pzuR`)Q{f?25+++eEhUt zc&Pw_b1i}U&0P+UkBZ8BK)%F%LjEV@e?tDD#vdK>CH@og{}SX&!mow=122rDNItx( z58fN^?h>0b!RN)!C(i#%a6TQWD2D@@k9em8q0IfvJz&oox$N_MUGZRf@qhou@awL4 z-f+JI^W;rq@VrYl5s=?!Gx)Gc0>3Pq=>0ry%kn>T>OhhV6elsi1{+?HT*QMH1o2_s z-GAWZq7Xpn_|gCXDGwxdUqtztWOOLWD8x$sIZXY3~ zj+AWrK@y+srYG#;MV#>vL^?kw>FDRBX>8!}K%$1QBZ$yXPgt59wBt59(Hg89ulR7O&H7 zI;;0nwJ)nS%vXG)T2t!T_~k*DmET9LVYvA*#Q1w?b|(qswYpV*431NLZ_{mdmY=G9 dEgrvvc4I&eVz?st*SwQ2{|9JMI+!>>0059Jq1*rf literal 0 HcmV?d00001 diff --git a/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/test_old_metadata_format_theme/metadata.desktop b/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/test_old_metadata_format_theme/metadata.desktop new file mode 100644 index 0000000000..68686d69e4 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/test_old_metadata_format_theme/metadata.desktop @@ -0,0 +1,19 @@ +[Desktop Entry] +Name=Plasma test theme + + +X-KDE-PluginInfo-Author=KDE Visual Design Group +X-KDE-PluginInfo-Email=kde-artists@kde.org +X-KDE-PluginInfo-Name=default +X-KDE-PluginInfo-Version=5.20 +X-KDE-PluginInfo-Website=https://plasma.kde.org +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-License=LGPL +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-API=5.0 + +[ContrastEffect] +enabled=true +contrast=0.23 +intensity=2.0 +saturation=1.7 diff --git a/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/colors b/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/colors new file mode 100644 index 0000000000..a7e74c131a --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/colors @@ -0,0 +1,120 @@ +[ColorEffects:Disabled] +Color=56,56,56 +ColorAmount=0 +ColorEffect=0 +ContrastAmount=0.65 +ContrastEffect=1 +IntensityAmount=0.1 +IntensityEffect=2 + +[ColorEffects:Inactive] +ChangeSelectionColor=true +Color=112,111,110 +ColorAmount=0.025 +ColorEffect=2 +ContrastAmount=0.1 +ContrastEffect=2 +Enable=false +IntensityAmount=0 +IntensityEffect=0 + +[Colors:Button] +BackgroundAlternate=224,223,222 +BackgroundNormal=239,240,241 +DecorationFocus=30,146,255 +DecorationHover=61,174,230 +ForegroundActive=246,116,0 +ForegroundInactive=175,176,179 +ForegroundLink=61,174,230 +ForegroundNegative=237,21,22 +ForegroundNeutral=201,206,60 +ForegroundNormal=49,54,59 +ForegroundPositive=17,209,23 +ForegroundVisited=61,174,230 + +[Colors:Selection] +BackgroundAlternate=48,138,183 +BackgroundNormal=61,174,230 +DecorationFocus=30,146,255 +DecorationHover=61,174,230 +ForegroundActive=246,116,0 +ForegroundInactive=146,204,230 +ForegroundLink=252,252,252 +ForegroundNegative=237,21,21 +ForegroundNeutral=201,206,59 +ForegroundNormal=252,252,252 +ForegroundPositive=17,209,22 +ForegroundVisited=252,252,252 + +[Colors:Tooltip] +BackgroundAlternate=196,224,255 +BackgroundNormal=239,240,241 +DecorationFocus=30,146,255 +DecorationHover=61,174,230 +ForegroundActive=246,116,0 +ForegroundInactive=175,176,179 +ForegroundLink=61,174,230 +ForegroundNegative=237,21,21 +ForegroundNeutral=201,206,59 +ForegroundNormal=49,54,59 +ForegroundPositive=17,209,22 +ForegroundVisited=61,174,230 + +[Colors:View] +BackgroundAlternate=248,247,246 +BackgroundNormal=252,252,252 +DecorationFocus=30,146,255 +DecorationHover=61,174,230 +ForegroundActive=246,116,0 +ForegroundInactive=175,176,179 +ForegroundLink=61,174,230 +ForegroundNegative=237,21,23 +ForegroundNeutral=201,206,61 +ForegroundNormal=49,54,59 +ForegroundPositive=17,209,24 +ForegroundVisited=61,174,230 + +[Colors:Window] +BackgroundAlternate=218,217,216 +BackgroundNormal=239,240,241 +DecorationFocus=30,146,255 +DecorationHover=61,174,230 +ForegroundActive=246,116,0 +ForegroundInactive=175,176,179 +ForegroundLink=61,174,230 +ForegroundNegative=237,21,21 +ForegroundNeutral=201,206,59 +#A very glaring red to check those colors are actually applied +ForegroundNormal=255,54,59 +ForegroundPositive=17,209,22 +ForegroundVisited=61,174,230 + +[Colors:Complementary] +BackgroundAlternate=59,64,69 +BackgroundNormal=49,54,59 +DecorationFocus=40,146,255 +DecorationHover=71,174,230 +ForegroundActive=246,116,20 +ForegroundInactive=185,176,179 +ForegroundLink=71,174,230 +ForegroundNegative=237,21,24 +ForegroundNeutral=201,206,62 +ForegroundNormal=239,240,241 +ForegroundPositive=17,209,25 +ForegroundVisited=71,174,230 + +[General] +ColorScheme=Breeze +Name=Breeze +shadeSortColumn=true + +[KDE] +contrast=7 + +[WM] +activeBackground=61,174,230 +activeBlend=252,252,252 +activeForeground=252,252,252 +inactiveBackground=123,124,126 +inactiveBlend=123,124,126 +inactiveForeground=252,252,252 diff --git a/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/element.svg b/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/element.svg new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/element.svg @@ -0,0 +1 @@ + diff --git a/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/metadata.json b/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/metadata.json new file mode 100644 index 0000000000..88a8e6c986 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/metadata.json @@ -0,0 +1,18 @@ +{ + "KPlugin": { + "Authors": [ + { + "Email": "kde-artists@kde.org", + "Name": "KDE Visual Design Group" + } + ], + "Category": "", + "EnabledByDefault": true, + "Id": "default", + "License": "LGPL", + "Name": "Plasma test theme", + "Version": "5.20", + "Website": "https://plasma.kde.org" + }, + "X-Plasma-API": "5.0" +} diff --git a/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/opaque/element.svg b/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/opaque/element.svg new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/opaque/element.svg @@ -0,0 +1 @@ + diff --git a/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/plasmarc b/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/plasmarc new file mode 100644 index 0000000000..a31148a73c --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/autotests/data/plasma/desktoptheme/testtheme/plasmarc @@ -0,0 +1,5 @@ +[ContrastEffect] +enabled=true +contrast=0.23 +intensity=2.0 +saturation=1.7 diff --git a/local/recipes/kde/kf6-ksvg/source/autotests/framesvgtest.cpp b/local/recipes/kde/kf6-ksvg/source/autotests/framesvgtest.cpp new file mode 100644 index 0000000000..2e1163074a --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/autotests/framesvgtest.cpp @@ -0,0 +1,131 @@ +/* + SPDX-FileCopyrightText: 2014 Marco Martin + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "framesvgtest.h" +#include +#include + +void copyDirectory(const QString &srcDir, const QString &dstDir) +{ + QDir targetDir(dstDir); + QDirIterator it(srcDir, QDir::Filters(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Name), QDirIterator::Subdirectories); + while (it.hasNext()) { + it.next(); + QString path = it.filePath(); + QString relDestPath = path.last(it.filePath().length() - srcDir.length() - 1); + if (it.fileInfo().isDir()) { + QVERIFY(targetDir.mkpath(relDestPath)); + } else { + QVERIFY(QFile::copy(path, dstDir % '/' % relDestPath)); + } + } +} + +void FrameSvgTest::initTestCase() +{ + QStandardPaths::setTestModeEnabled(true); + + m_themeDir = QDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % '/' % "plasma"); + m_themeDir.removeRecursively(); + + copyDirectory(QFINDTESTDATA("data/plasma"), m_themeDir.absolutePath()); + + m_cacheDir = QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); + m_cacheDir.removeRecursively(); + + m_frameSvg = new KSvg::FrameSvg; + m_frameSvg->setImagePath(QFINDTESTDATA("data/background.svgz")); + QVERIFY(m_frameSvg->isValid()); +} + +void FrameSvgTest::cleanupTestCase() +{ + delete m_frameSvg; + + m_themeDir.removeRecursively(); + m_cacheDir.removeRecursively(); +} + +void FrameSvgTest::margins() +{ + QCOMPARE(m_frameSvg->marginSize(KSvg::FrameSvg::LeftMargin), (qreal)26); + QCOMPARE(m_frameSvg->marginSize(KSvg::FrameSvg::TopMargin), (qreal)26); + QCOMPARE(m_frameSvg->marginSize(KSvg::FrameSvg::RightMargin), (qreal)26); + QCOMPARE(m_frameSvg->marginSize(KSvg::FrameSvg::BottomMargin), (qreal)26); +} + +void FrameSvgTest::contentsRect() +{ + m_frameSvg->resizeFrame(QSize(100, 100)); + QCOMPARE(m_frameSvg->contentsRect(), QRectF(26, 26, 48, 48)); +} + +void FrameSvgTest::repaintBlocked() +{ + // check the properties to be correct even if set during a repaint blocked transaction + m_frameSvg->setRepaintBlocked(true); + QVERIFY(m_frameSvg->isRepaintBlocked()); + + m_frameSvg->setElementPrefix("prefix"); + m_frameSvg->setEnabledBorders(KSvg::FrameSvg::TopBorder | KSvg::FrameSvg::LeftBorder); + m_frameSvg->resizeFrame(QSizeF(100, 100)); + + m_frameSvg->setRepaintBlocked(false); + + QCOMPARE(m_frameSvg->prefix(), QString("prefix")); + QCOMPARE(m_frameSvg->enabledBorders(), KSvg::FrameSvg::TopBorder | KSvg::FrameSvg::LeftBorder); + QCOMPARE(m_frameSvg->frameSize(), QSizeF(100, 100)); +} + +void FrameSvgTest::setImageSet() +{ + // Should not crash + + KSvg::FrameSvg *frameSvg = new KSvg::FrameSvg; + frameSvg->setImagePath("widgets/background"); + frameSvg->setImageSet(new KSvg::ImageSet("breeze-light", {}, this)); + frameSvg->framePixmap(); + frameSvg->setImageSet(new KSvg::ImageSet("breeze-dark", {}, this)); + frameSvg->framePixmap(); + delete frameSvg; + + frameSvg = new KSvg::FrameSvg; + frameSvg->setImagePath("widgets/background"); + frameSvg->setImageSet(new KSvg::ImageSet("breeze-light", {}, this)); + frameSvg->framePixmap(); + frameSvg->setImageSet(new KSvg::ImageSet("breeze-dark", {}, this)); + frameSvg->framePixmap(); + + frameSvg->setImageSet(new KSvg::ImageSet("testtheme", "plasma/desktoptheme", this)); + QCOMPARE(frameSvg->color(KSvg::Svg::Text), QColor(255, 54, 59)); + + delete frameSvg; +} + +void FrameSvgTest::resizeMask() +{ + m_frameSvg->resizeFrame(QSize(100, 100)); + QCOMPARE(m_frameSvg->alphaMask().size(), QSize(100, 100)); + m_frameSvg->resizeFrame(QSize(50, 50)); + QCOMPARE(m_frameSvg->alphaMask().size(), QSize(50, 50)); + m_frameSvg->resizeFrame(QSize(100, 100)); + QCOMPARE(m_frameSvg->alphaMask().size(), QSize(100, 100)); +} + +void FrameSvgTest::loadQrc() +{ + KSvg::FrameSvg *frameSvg = new KSvg::FrameSvg; + frameSvg->setImageSet(new KSvg::ImageSet("testtheme", "plasma/desktoptheme", this)); + frameSvg->setImagePath(QStringLiteral("qrc:/data/background.svgz")); + QVERIFY(frameSvg->isValid()); + // An external image is colored as well + QCOMPARE(frameSvg->color(KSvg::Svg::Text), QColor(255, 54, 59)); + delete frameSvg; +} + +QTEST_MAIN(FrameSvgTest) + +#include "moc_framesvgtest.cpp" diff --git a/local/recipes/kde/kf6-ksvg/source/autotests/framesvgtest.h b/local/recipes/kde/kf6-ksvg/source/autotests/framesvgtest.h new file mode 100644 index 0000000000..5063eca71d --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/autotests/framesvgtest.h @@ -0,0 +1,35 @@ +/* + SPDX-FileCopyrightText: 2014 Marco Martin + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ +#ifndef FRAMESVGTEST_H +#define FRAMESVGTEST_H + +#include + +#include "ksvg/framesvg.h" + +class FrameSvgTest : public QObject +{ + Q_OBJECT + +public Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + +private Q_SLOTS: + void margins(); + void contentsRect(); + void setImageSet(); + void repaintBlocked(); + void resizeMask(); + void loadQrc(); + +private: + KSvg::FrameSvg *m_frameSvg; + QDir m_themeDir; + QDir m_cacheDir; +}; + +#endif diff --git a/local/recipes/kde/kf6-ksvg/source/docs/Doxyfile.local b/local/recipes/kde/kf6-ksvg/source/docs/Doxyfile.local new file mode 100644 index 0000000000..2d8827624f --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/docs/Doxyfile.local @@ -0,0 +1,7 @@ +### KApiDox Project-specific Overrides File + +# define so that deprecated API is not skipped +PREDEFINED += \ + "KSVG_ENABLE_DEPRECATED_SINCE(x, y)=1" \ + "KSVG_BUILD_DEPRECATED_SINCE(x, y)=1" \ + "KSVG_DEPRECATED_VERSION(x, y, t)=" diff --git a/local/recipes/kde/kf6-ksvg/source/metainfo.yaml b/local/recipes/kde/kf6-ksvg/source/metainfo.yaml new file mode 100644 index 0000000000..7554f074c9 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/metainfo.yaml @@ -0,0 +1,19 @@ +description: A library for rendering SVG-based themes with stylesheet re-coloring and on-disk caching +tier: 3 +type: solution +platforms: + - name: Linux + - name: FreeBSD + - name: Windows + - name: macOS + - name: Android +portingAid: false +deprecated: false +release: true +libraries: + - cmake: KF6::Svg +cmakename: KF6Svg + +public_lib: true +group: Frameworks +subgroup: Tier 3 diff --git a/local/recipes/kde/kf6-ksvg/source/po/ar/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/ar/libksvg6.po new file mode 100644 index 0000000000..4454405323 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/ar/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) 2024 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# SPDX-FileCopyrightText: 2024 Zayed Al-Saidi +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2024-02-12 12:10+0400\n" +"Last-Translator: Zayed Al-Saidi \n" +"Language-Team: ar\n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "زايد السعيدي" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "zayed.alsaidi@gmail.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/ast/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/ast/libksvg6.po new file mode 100644 index 0000000000..f4a1f12dfe --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/ast/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) 2023 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# SPDX-FileCopyrightText: 2023 Enol P. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-10-25 10:01+0200\n" +"Last-Translator: Enol P. \n" +"Language-Team: \n" +"Language: ast\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 23.08.2\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Softastur" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "alministradores@softastur.org" diff --git a/local/recipes/kde/kf6-ksvg/source/po/bg/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/bg/libksvg6.po new file mode 100644 index 0000000000..33a1d3722d --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/bg/libksvg6.po @@ -0,0 +1,30 @@ +# Bulgarian translations for ksvg package. +# Copyright (C) 2023 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# Automatically generated, 2023. +# Mincho Kondarev , 2023. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-08-09 09:53+0200\n" +"Last-Translator: Mincho Kondarev \n" +"Language-Team: \n" +"Language: bg\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 23.04.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Минчо Кондарев" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "mkondarev@yahoo.de" diff --git a/local/recipes/kde/kf6-ksvg/source/po/ca/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/ca/libksvg6.po new file mode 100644 index 0000000000..8f34834460 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/ca/libksvg6.po @@ -0,0 +1,30 @@ +# Translation of libksvg6.po to Catalan +# Copyright (C) 2023 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Josep M. Ferrer , 2023. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-13 10:41+0200\n" +"Last-Translator: Josep M. Ferrer \n" +"Language-Team: Catalan \n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 22.12.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Josep M. Ferrer" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "txemaq@gmail.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/ca@valencia/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/ca@valencia/libksvg6.po new file mode 100644 index 0000000000..3f92f2fcb6 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/ca@valencia/libksvg6.po @@ -0,0 +1,30 @@ +# Translation of libksvg6.po to Catalan (Valencian) +# Copyright (C) 2023 This_file_is_part_of_KDE +# This file is distributed under the license LGPL version 2.1 or +# version 3 or later versions approved by the membership of KDE e.V. +# +# Josep M. Ferrer , 2023. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-13 10:41+0200\n" +"Last-Translator: Josep M. Ferrer \n" +"Language-Team: Catalan \n" +"Language: ca@valencia\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 22.12.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Josep M. Ferrer" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "txemaq@gmail.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/cs/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/cs/libksvg6.po new file mode 100644 index 0000000000..4af9e6c98b --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/cs/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# Vit Pelcak , 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-08-07 17:01+0200\n" +"Last-Translator: Vit Pelcak \n" +"Language-Team: Czech \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"X-Generator: Lokalize 23.04.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Vít Pelčák" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "vit@pelcak.org" diff --git a/local/recipes/kde/kf6-ksvg/source/po/de/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/de/libksvg6.po new file mode 100644 index 0000000000..b2302b5648 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/de/libksvg6.po @@ -0,0 +1,30 @@ +# German translations for ksvg package. +# Copyright (C) 2023 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# Frederik Schwarzer , 2023. +# +# Automatically generated, 2023. +msgid "" +msgstr "" +"Project-Id-Version: libksvg6\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-24 21:19+0200\n" +"Last-Translator: Frederik Schwarzer \n" +"Language-Team: German \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 23.11.70\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Deutsches KDE-Übersetzerteam" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "kde-i18n-de@kde.org" diff --git a/local/recipes/kde/kf6-ksvg/source/po/en_GB/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/en_GB/libksvg6.po new file mode 100644 index 0000000000..b07af888bb --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/en_GB/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) 2024 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# SPDX-FileCopyrightText: 2024 Steve Allewell +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2024-05-20 19:22+0100\n" +"Last-Translator: Steve Allewell \n" +"Language-Team: British English\n" +"Language: en_GB\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 24.02.2\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Steve Allewell" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "steve.allewell@gmail.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/eo/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/eo/libksvg6.po new file mode 100644 index 0000000000..b1a538c65b --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/eo/libksvg6.po @@ -0,0 +1,28 @@ +# translation of libksvg6.pot to esperanto +# Copyright (C) 2023 Free Software Foundation, Inc. +# This file is distributed under the same license as the ksvg package. +# Oliver Kellogg \n" +"Language-Team: Esperanto \n" +"Language: eo\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Oliver Kellogg" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "olivermkellogg@gmail.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/es/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/es/libksvg6.po new file mode 100644 index 0000000000..f1416b3b2c --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/es/libksvg6.po @@ -0,0 +1,30 @@ +# Spanish translations for libksvg5.po package. +# Copyright (C) 2023 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# Automatically generated, 2023. +# Eloy Cuadra , 2023. +msgid "" +msgstr "" +"Project-Id-Version: libksvg5\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-15 00:31+0200\n" +"Last-Translator: Eloy Cuadra \n" +"Language-Team: Spanish \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 23.04.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Eloy Cuadra" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "ecuadra@eloihr.net" diff --git a/local/recipes/kde/kf6-ksvg/source/po/eu/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/eu/libksvg6.po new file mode 100644 index 0000000000..2637152ad6 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/eu/libksvg6.po @@ -0,0 +1,31 @@ +# Translation for libksvg5.po to Euskara/Basque (eu) +# Copyright (C) 2023 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# KDE euskaratzeko proiektuko arduraduna . +# +# Translators: +# Iñigo Salvador Azurmendi , 2023. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-15 08:51+0200\n" +"Last-Translator: Iñigo Salvador Azurmendi \n" +"Language-Team: Basque \n" +"Language: eu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 23.04.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Iñigo Salvador Azurmendi" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "xalba@ni.eus" diff --git a/local/recipes/kde/kf6-ksvg/source/po/fi/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/fi/libksvg6.po new file mode 100644 index 0000000000..448db530fa --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/fi/libksvg6.po @@ -0,0 +1,27 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# Tommi Nieminen , 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-24 21:33+0300\n" +"Last-Translator: Tommi Nieminen \n" +"Language-Team: Finnish \n" +"Language: fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Tommi Nieminen" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "translator@legisign.org" diff --git a/local/recipes/kde/kf6-ksvg/source/po/fr/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/fr/libksvg6.po new file mode 100644 index 0000000000..e548eb1661 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/fr/libksvg6.po @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: 2023 Xavier Besnard +# SPDX-FileCopyrightText: 2023 Xavier Besnard +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-12-20 09:33+0100\n" +"Last-Translator: Xavier Besnard \n" +"Language-Team: French \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 23.08.4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Xavier Besnard" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "xavier.besnard@kde.org" diff --git a/local/recipes/kde/kf6-ksvg/source/po/gl/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/gl/libksvg6.po new file mode 100644 index 0000000000..25db060e63 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/gl/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# Adrián Chaves (Gallaecio) , 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-29 07:52+0200\n" +"Last-Translator: Adrián Chaves (Gallaecio) \n" +"Language-Team: Galician \n" +"Language: gl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 23.04.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Adrian Chaves (Gallaecio)" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "adrian@chaves.io" diff --git a/local/recipes/kde/kf6-ksvg/source/po/he/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/he/libksvg6.po new file mode 100644 index 0000000000..a831152fd3 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/he/libksvg6.po @@ -0,0 +1,29 @@ +# Copyright (C) 2024 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# SPDX-FileCopyrightText: 2024 Yaron Shahrabani +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2024-03-19 07:50+0200\n" +"Last-Translator: Yaron Shahrabani \n" +"Language-Team: צוות התרגום של KDE ישראל\n" +"Language: he\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && " +"n % 10 == 0) ? 2 : 3));\n" +"X-Generator: Lokalize 23.08.5\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "צוות התרגום של KDE ישראל" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "kde-l10n-he@kde.org" diff --git a/local/recipes/kde/kf6-ksvg/source/po/hi/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/hi/libksvg6.po new file mode 100644 index 0000000000..0894061f56 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/hi/libksvg6.po @@ -0,0 +1,28 @@ +# Hindi translations for ksvg package. +# Copyright (C) 2024 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# Kali , 2024. +# +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2024-12-15 17:36+0530\n" +"Last-Translator: Kali \n" +"Language-Team: Hindi \n" +"Language: hi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "तुम्हारे नाम" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "आपके ईमेल" diff --git a/local/recipes/kde/kf6-ksvg/source/po/hu/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/hu/libksvg6.po new file mode 100644 index 0000000000..c9425521c9 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/hu/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) 2024 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# SPDX-FileCopyrightText: 2024 Kristof Kiszel +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2024-01-07 22:36+0100\n" +"Last-Translator: Kristof Kiszel \n" +"Language-Team: Hungarian \n" +"Language: hu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 23.08.4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Kiszel Kristóf" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "ulysses@fsf.hu" diff --git a/local/recipes/kde/kf6-ksvg/source/po/ia/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/ia/libksvg6.po new file mode 100644 index 0000000000..03fc78074f --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/ia/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# giovanni , 2023. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-08-13 15:13+0200\n" +"Last-Translator: giovanni \n" +"Language-Team: Interlingua \n" +"Language: ia\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 21.12.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Giovanni Sora" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "g.sora@tiscali.it" diff --git a/local/recipes/kde/kf6-ksvg/source/po/is/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/is/libksvg6.po new file mode 100644 index 0000000000..44b3fe1f0c --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/is/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# Sveinn í Felli , 2024. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2024-02-19 09:43+0000\n" +"Last-Translator: Sveinn í Felli \n" +"Language-Team: Icelandic\n" +"Language: is\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 22.04.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Sveinn í Felli" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "sv1@fellsnet.is" diff --git a/local/recipes/kde/kf6-ksvg/source/po/it/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/it/libksvg6.po new file mode 100644 index 0000000000..ebc4e7e4b8 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/it/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# Vincenzo Reale , 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-15 23:42+0200\n" +"Last-Translator: Vincenzo Reale \n" +"Language-Team: Italian \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 23.04.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Vincenzo Reale" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "smart2128vr@gmail.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/ja/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/ja/libksvg6.po new file mode 100644 index 0000000000..ce7bd0d3d5 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/ja/libksvg6.po @@ -0,0 +1,25 @@ +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-14 21:55-0700\n" +"Last-Translator: Japanese KDE translation team \n" +"Language-Team: Japanese \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "" diff --git a/local/recipes/kde/kf6-ksvg/source/po/ka/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/ka/libksvg6.po new file mode 100644 index 0000000000..db91d1cedc --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/ka/libksvg6.po @@ -0,0 +1,29 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-14 05:42+0200\n" +"Last-Translator: Temuri Doghonadze \n" +"Language-Team: Georgian \n" +"Language: ka\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 3.3.2\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Temuri Doghonadze" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "Temuri.doghonadze@gmail.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/ko/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/ko/libksvg6.po new file mode 100644 index 0000000000..7bd0508c4a --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/ko/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# Shinjo Park , 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-25 01:00+0200\n" +"Last-Translator: Shinjo Park \n" +"Language-Team: Korean \n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Lokalize 22.12.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "박신조" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "kde@peremen.name" diff --git a/local/recipes/kde/kf6-ksvg/source/po/lt/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/lt/libksvg6.po new file mode 100644 index 0000000000..4bd652ffbd --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/lt/libksvg6.po @@ -0,0 +1,29 @@ +# Lithuanian translations for ksvg package. +# Copyright (C) 2024 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# Automatically generated, 2024. +# +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-13 02:10+0000\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: lt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : n%10>=2 && (n%100<10 || n" +"%100>=20) ? 1 : n%10==0 || (n%100>10 && n%100<20) ? 2 : 3);\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "" diff --git a/local/recipes/kde/kf6-ksvg/source/po/nl/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/nl/libksvg6.po new file mode 100644 index 0000000000..f6f599182d --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/nl/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# Freek de Kruijf , 2023. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-13 12:27+0200\n" +"Last-Translator: Freek de Kruijf \n" +"Language-Team: \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 23.04.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Freek de Kruijf - 2023" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "freekdekruijf@kde.nl" diff --git a/local/recipes/kde/kf6-ksvg/source/po/nn/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/nn/libksvg6.po new file mode 100644 index 0000000000..f8b0d68bb7 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/nn/libksvg6.po @@ -0,0 +1,30 @@ +# Translation of libksvg6 to Norwegian Nynorsk +# +# Karl Ove Hufthammer , 2023. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-29 12:34+0200\n" +"Last-Translator: Karl Ove Hufthammer \n" +"Language-Team: Norwegian Nynorsk \n" +"Language: nn\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 23.04.3\n" +"X-Environment: kde\n" +"X-Accelerator-Marker: &\n" +"X-Text-Markup: kde4\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Karl Ove Hufthammer" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "karl@huftis.org" diff --git a/local/recipes/kde/kf6-ksvg/source/po/pl/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/pl/libksvg6.po new file mode 100644 index 0000000000..a36cd02c5d --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/pl/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# Łukasz Wojniłowicz , 2023. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-09-24 08:17+0200\n" +"Last-Translator: Łukasz Wojniłowicz \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Łukasz Wojniłowicz" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "lukasz.wojnilowicz@gmail.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/pt_BR/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/pt_BR/libksvg6.po new file mode 100644 index 0000000000..25b8a039f0 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/pt_BR/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# Luiz Fernando Ranghetti , 2023. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-25 10:06-0300\n" +"Last-Translator: Luiz Fernando Ranghetti \n" +"Language-Team: Brazilian Portuguese \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 22.12.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Luiz Fernando Ranghetti" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "elchevive@opensuse.org" diff --git a/local/recipes/kde/kf6-ksvg/source/po/ro/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/ro/libksvg6.po new file mode 100644 index 0000000000..37279c59a9 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/ro/libksvg6.po @@ -0,0 +1,29 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# Sergiu Bivol , 2024. +# +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2024-02-18 14:48+0000\n" +"Last-Translator: Sergiu Bivol \n" +"Language-Team: Romanian \n" +"Language: ro\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " +"20)) ? 1 : 2;\n" +"X-Generator: Lokalize 21.12.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Sergiu Bivol" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "sergiu@cip.md" diff --git a/local/recipes/kde/kf6-ksvg/source/po/ru/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/ru/libksvg6.po new file mode 100644 index 0000000000..4628bc7e80 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/ru/libksvg6.po @@ -0,0 +1,29 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# Alexander Yavorsky , 2024. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2024-01-05 22:09+0300\n" +"Last-Translator: Alexander Yavorsky \n" +"Language-Team: Russian \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Lokalize 21.08.3\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Александр Яворский" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "kekcuha@gmail.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/sa/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/sa/libksvg6.po new file mode 100644 index 0000000000..5f58a40498 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/sa/libksvg6.po @@ -0,0 +1,29 @@ +# Copyright (C) 2024 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# SPDX-FileCopyrightText: 2024 kali +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2024-12-24 20:39+0530\n" +"Last-Translator: kali \n" +"Language-Team: Sanskrit \n" +"Language: sa\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 24.08.2\n" +"X-Poedit-SourceCharset: UTF-8\n" +"Plural-Forms: nplurals=2; plural=(n>2);\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "श्रीकान्त् कलवार्" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "skkalwar999@gmail.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/sk/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/sk/libksvg6.po new file mode 100644 index 0000000000..3086966c15 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/sk/libksvg6.po @@ -0,0 +1,26 @@ +# translation of libksvg6.po to Slovak +# SPDX-FileCopyrightText: 2023 Roman Paholík +msgid "" +msgstr "" +"Project-Id-Version: libksvg6\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-12-09 09:08+0100\n" +"Last-Translator: Roman Paholik \n" +"Language-Team: Slovak \n" +"Language: sk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 23.08.3\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Roman Paholík" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "wizzardsk@gmail.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/sl/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/sl/libksvg6.po new file mode 100644 index 0000000000..b8e6ba1d1a --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/sl/libksvg6.po @@ -0,0 +1,29 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# Matjaž Jeran , 2023. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-14 06:33+0200\n" +"Last-Translator: Matjaž Jeran \n" +"Language-Team: Slovenian \n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 23.04.2\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n" +"%100==4 ? 3 : 0);\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Matjaž Jeran" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "matjaz.jeran@amis.net" diff --git a/local/recipes/kde/kf6-ksvg/source/po/sv/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/sv/libksvg6.po new file mode 100644 index 0000000000..682a1f7ff6 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/sv/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) 2024 This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# SPDX-FileCopyrightText: 2024 Stefan Asserhäll +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2024-06-21 14:32+0200\n" +"Last-Translator: Stefan Asserhäll \n" +"Language-Team: Swedish \n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Lokalize 23.08.5\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Stefan Asserhäll" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "stefan.asserhall@gmail.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/tr/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/tr/libksvg6.po new file mode 100644 index 0000000000..4040b69d0f --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/tr/libksvg6.po @@ -0,0 +1,28 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# Emir SARI , 2023. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-13 13:03+0300\n" +"Last-Translator: Emir SARI \n" +"Language-Team: Turkish \n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Lokalize 23.07.70\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Emir SARI" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "emir_sari@icloud.com" diff --git a/local/recipes/kde/kf6-ksvg/source/po/uk/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/uk/libksvg6.po new file mode 100644 index 0000000000..89eece48e0 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/uk/libksvg6.po @@ -0,0 +1,29 @@ +# Copyright (C) YEAR This file is copyright: +# This file is distributed under the same license as the ksvg package. +# +# Yuri Chornoivan , 2023. +msgid "" +msgstr "" +"Project-Id-Version: ksvg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2023-07-13 08:52+0300\n" +"Last-Translator: Yuri Chornoivan \n" +"Language-Team: Ukrainian \n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" +"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Lokalize 20.12.0\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Юрій Чорноіван" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "yurchor@ukr.net" diff --git a/local/recipes/kde/kf6-ksvg/source/po/zh_CN/libksvg6.po b/local/recipes/kde/kf6-ksvg/source/po/zh_CN/libksvg6.po new file mode 100644 index 0000000000..f85252eab9 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/po/zh_CN/libksvg6.po @@ -0,0 +1,28 @@ +msgid "" +msgstr "" +"Project-Id-Version: kdeorg\n" +"Report-Msgid-Bugs-To: https://bugs.kde.org\n" +"POT-Creation-Date: 2023-07-13 02:10+0000\n" +"PO-Revision-Date: 2024-04-22 15:58\n" +"Last-Translator: \n" +"Language-Team: Chinese Simplified\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Crowdin-Project: kdeorg\n" +"X-Crowdin-Project-ID: 269464\n" +"X-Crowdin-Language: zh-CN\n" +"X-Crowdin-File: /kf6-trunk/messages/ksvg/libksvg6.pot\n" +"X-Crowdin-File-ID: 44419\n" + +#, kde-format +msgctxt "NAME OF TRANSLATORS" +msgid "Your names" +msgstr "Tyson Tan" + +#, kde-format +msgctxt "EMAIL OF TRANSLATORS" +msgid "Your emails" +msgstr "tds00@qq.com" diff --git a/local/recipes/kde/kf6-ksvg/source/src/CMakeLists.txt b/local/recipes/kde/kf6-ksvg/source/src/CMakeLists.txt new file mode 100644 index 0000000000..376f32bd54 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/CMakeLists.txt @@ -0,0 +1,12 @@ +add_subdirectory(ksvg) +#add_subdirectory(declarativeimports) + +if (BUILD_TOOLS) + add_subdirectory(tools) +endif() + +ecm_qt_install_logging_categories( + EXPORT KSVG + FILE ksvg.categories + DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR} +) diff --git a/local/recipes/kde/kf6-ksvg/source/src/Messages.sh b/local/recipes/kde/kf6-ksvg/source/src/Messages.sh new file mode 100644 index 0000000000..ce1937a33b --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/Messages.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +# Invoke the extractrc script on all .ui, .rc, and .kcfg files in the sources. +# The results are stored in a pseudo .cpp file to be picked up by xgettext. +lst=`find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` +if [ -n "$lst" ] ; then + $EXTRACTRC $lst >> rc.cpp +fi + +# Run xgettext to extract strings from all source files. +$XGETTEXT `find . -name \*.cpp -o -name \*.h -o -name \*.qml` -o $podir/libksvg6.pot diff --git a/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/CMakeLists.txt b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/CMakeLists.txt new file mode 100644 index 0000000000..d4b1ec0886 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/CMakeLists.txt @@ -0,0 +1,27 @@ +ecm_add_qml_module(corebindingsplugin URI "org.kde.ksvg" VERSION 1.0 DEPENDENCIES QtQuick GENERATE_PLUGIN_SOURCE) + +target_sources(corebindingsplugin PRIVATE + svgitem.cpp + framesvgitem.cpp + managedtexturenode.cpp + imagetexturescache.cpp + types.h +) + +target_link_libraries(corebindingsplugin PRIVATE + Qt6::Quick + Qt6::Qml + Qt6::Svg + KF6::Svg + KF6::ColorScheme + KF6::KirigamiPlatform +) + +ecm_qt_declare_logging_category(corebindingsplugin + HEADER debug_p.h + IDENTIFIER LOG_KSVGQML + CATEGORY_NAME kf.svg + DESCRIPTION "KSvg QML plugin" +) + +ecm_finalize_qml_module(corebindingsplugin DESTINATION ${KDE_INSTALL_QMLDIR}) diff --git a/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/framesvgitem.cpp b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/framesvgitem.cpp new file mode 100644 index 0000000000..56c2b3a8ff --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/framesvgitem.cpp @@ -0,0 +1,782 @@ +/* + SPDX-FileCopyrightText: 2010 Marco Martin + SPDX-FileCopyrightText: 2014 David Edmundson + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "framesvgitem.h" + +#include "imagetexturescache.h" +#include "managedtexturenode.h" + +#include +#include +#include + +#include +#include + +#include +#include + +#include //floor() + +#include +#include + +namespace KSvg +{ +Q_GLOBAL_STATIC(ImageTexturesCache, s_cache) + +class FrameNode : public QSGNode +{ +public: + FrameNode(const QString &prefix, FrameSvg *svg) + : QSGNode() + , leftWidth(0) + , rightWidth(0) + , topHeight(0) + , bottomHeight(0) + { + if (svg->enabledBorders() & FrameSvg::LeftBorder) { + leftWidth = svg->elementSize(prefix % QLatin1String("left")).width(); + } + if (svg->enabledBorders() & FrameSvg::RightBorder) { + rightWidth = svg->elementSize(prefix % QLatin1String("right")).width(); + } + if (svg->enabledBorders() & FrameSvg::TopBorder) { + topHeight = svg->elementSize(prefix % QLatin1String("top")).height(); + } + if (svg->enabledBorders() & FrameSvg::BottomBorder) { + bottomHeight = svg->elementSize(prefix % QLatin1String("bottom")).height(); + } + } + + QRect contentsRect(const QSize &size) const + { + const QSize contentSize(size.width() - leftWidth - rightWidth, size.height() - topHeight - bottomHeight); + + return QRect(QPoint(leftWidth, topHeight), contentSize); + } + +private: + int leftWidth; + int rightWidth; + int topHeight; + int bottomHeight; +}; + +class FrameItemNode : public ManagedTextureNode +{ +public: + enum FitMode { + // render SVG at native resolution then stretch it in openGL + FastStretch, + // on resize re-render the part of the frame from the SVG + Stretch, + Tile, + }; + + FrameItemNode(FrameSvgItem *frameSvg, FrameSvg::EnabledBorders borders, FitMode fitMode, QSGNode *parent) + : ManagedTextureNode() + , m_frameSvg(frameSvg) + , m_border(borders) + , m_fitMode(fitMode) + { + parent->appendChildNode(this); + + if (m_fitMode == Tile) { + if (m_border == FrameSvg::TopBorder || m_border == FrameSvg::BottomBorder || m_border == FrameSvg::NoBorder) { + static_cast(material())->setHorizontalWrapMode(QSGTexture::Repeat); + static_cast(opaqueMaterial())->setHorizontalWrapMode(QSGTexture::Repeat); + } + if (m_border == FrameSvg::LeftBorder || m_border == FrameSvg::RightBorder || m_border == FrameSvg::NoBorder) { + static_cast(material())->setVerticalWrapMode(QSGTexture::Repeat); + static_cast(opaqueMaterial())->setVerticalWrapMode(QSGTexture::Repeat); + } + } + + if (m_fitMode == Tile || m_fitMode == FastStretch) { + QString elementId = m_frameSvg->frameSvg()->actualPrefix() + FrameSvgHelpers::borderToElementId(m_border); + m_elementNativeSize = m_frameSvg->frameSvg()->elementSize(elementId).toSize(); + + if (m_elementNativeSize.isEmpty()) { + // if the default element is empty, we can avoid the slower tiling path + // this also avoids a divide by 0 error + m_fitMode = FastStretch; + } + + updateTexture(m_elementNativeSize, elementId); + } + } + + void updateTexture(const QSize &size, const QString &elementId) + { + QQuickWindow::CreateTextureOptions options; + if (m_fitMode != Tile) { + options = QQuickWindow::TextureCanUseAtlas; + } + setTexture(s_cache->loadTexture(m_frameSvg->window(), m_frameSvg->frameSvg()->image(size, elementId), options)); + } + + void reposition(const QRect &frameGeometry, QSize &fullSize) + { + QRectF nodeRect = FrameSvgHelpers::sectionRect(m_border, frameGeometry, fullSize); + + // ensure we're not passing a weird rectangle to updateTexturedRectGeometry + if (!nodeRect.isValid() || nodeRect.isEmpty()) { + nodeRect = QRect(); + } + + // the position of the relevant texture within this texture ID. + // for atlas' this will only be a small part of the texture + QRectF textureRect; + + if (m_fitMode == Tile) { + textureRect = QRectF(0, 0, 1, 1); // we can never be in an atlas for tiled images. + + // if tiling horizontally + if (m_border == FrameSvg::TopBorder || m_border == FrameSvg::BottomBorder || m_border == FrameSvg::NoBorder) { + // cmp. CSS3's border-image-repeat: "repeat", though with first tile not centered, but aligned to left + textureRect.setWidth((qreal)nodeRect.width() / m_elementNativeSize.width()); + } + // if tiling vertically + if (m_border == FrameSvg::LeftBorder || m_border == FrameSvg::RightBorder || m_border == FrameSvg::NoBorder) { + // cmp. CSS3's border-image-repeat: "repeat", though with first tile not centered, but aligned to top + textureRect.setHeight((qreal)nodeRect.height() / m_elementNativeSize.height()); + } + } else if (m_fitMode == Stretch) { + QString prefix = m_frameSvg->frameSvg()->actualPrefix(); + + QString elementId = prefix + FrameSvgHelpers::borderToElementId(m_border); + + // re-render the SVG at new size + updateTexture(nodeRect.size().toSize(), elementId); + textureRect = texture()->normalizedTextureSubRect(); + } else if (texture()) { // for fast stretch. + textureRect = texture()->normalizedTextureSubRect(); + } + + QSGGeometry::updateTexturedRectGeometry(geometry(), nodeRect, textureRect); + markDirty(QSGNode::DirtyGeometry); + } + +private: + FrameSvgItem *m_frameSvg; + FrameSvg::EnabledBorders m_border; + QSize m_elementNativeSize; + FitMode m_fitMode; +}; + +FrameSvgItemMargins::FrameSvgItemMargins(KSvg::FrameSvg *frameSvg, QObject *parent) + : QObject(parent) + , m_frameSvg(frameSvg) + , m_fixed(false) + , m_inset(false) +{ + // qDebug() << "margins at: " << left() << top() << right() << bottom(); +} + +qreal FrameSvgItemMargins::left() const +{ + if (m_fixed) { + return m_frameSvg->fixedMarginSize(FrameSvg::LeftMargin); + } else if (m_inset) { + return m_frameSvg->insetSize(FrameSvg::LeftMargin); + } else { + return m_frameSvg->marginSize(FrameSvg::LeftMargin); + } +} + +qreal FrameSvgItemMargins::top() const +{ + if (m_fixed) { + return m_frameSvg->fixedMarginSize(FrameSvg::TopMargin); + } else if (m_inset) { + return m_frameSvg->insetSize(FrameSvg::TopMargin); + } else { + return m_frameSvg->marginSize(FrameSvg::TopMargin); + } +} + +qreal FrameSvgItemMargins::right() const +{ + if (m_fixed) { + return m_frameSvg->fixedMarginSize(FrameSvg::RightMargin); + } else if (m_inset) { + return m_frameSvg->insetSize(FrameSvg::RightMargin); + } else { + return m_frameSvg->marginSize(FrameSvg::RightMargin); + } +} + +qreal FrameSvgItemMargins::bottom() const +{ + if (m_fixed) { + return m_frameSvg->fixedMarginSize(FrameSvg::BottomMargin); + } else if (m_inset) { + return m_frameSvg->insetSize(FrameSvg::BottomMargin); + } else { + return m_frameSvg->marginSize(FrameSvg::BottomMargin); + } +} + +qreal FrameSvgItemMargins::horizontal() const +{ + return left() + right(); +} + +qreal FrameSvgItemMargins::vertical() const +{ + return top() + bottom(); +} + +QList FrameSvgItemMargins::margins() const +{ + qreal left; + qreal top; + qreal right; + qreal bottom; + m_frameSvg->getMargins(left, top, right, bottom); + return {left, top, right, bottom}; +} + +void FrameSvgItemMargins::update() +{ + Q_EMIT marginsChanged(); +} + +void FrameSvgItemMargins::setFixed(bool fixed) +{ + if (fixed == m_fixed) { + return; + } + + m_fixed = fixed; + Q_EMIT marginsChanged(); +} + +bool FrameSvgItemMargins::isFixed() const +{ + return m_fixed; +} + +void FrameSvgItemMargins::setInset(bool inset) +{ + if (inset == m_inset) { + return; + } + + m_inset = inset; + Q_EMIT marginsChanged(); +} + +bool FrameSvgItemMargins::isInset() const +{ + return m_inset; +} + +FrameSvgItem::FrameSvgItem(QQuickItem *parent) + : QQuickItem(parent) + , m_margins(nullptr) + , m_fixedMargins(nullptr) + , m_insetMargins(nullptr) + , m_textureChanged(false) + , m_sizeChanged(false) + , m_fastPath(true) +{ + m_frameSvg = new KSvg::FrameSvg(this); + + setFlag(QQuickItem::ItemHasContents, true); + setFlag(ItemHasContents, true); + connect(m_frameSvg, &FrameSvg::repaintNeeded, this, &FrameSvgItem::doUpdate); + connect(m_frameSvg, &Svg::fromCurrentImageSetChanged, this, &FrameSvgItem::fromCurrentImageSetChanged); + connect(m_frameSvg, &Svg::statusChanged, this, &FrameSvgItem::statusChanged); +} + +FrameSvgItem::~FrameSvgItem() +{ +} + +class CheckMarginsChange +{ +public: + CheckMarginsChange(QList &oldMargins, FrameSvgItemMargins *marginsObject) + : m_oldMargins(oldMargins) + , m_marginsObject(marginsObject) + { + } + + ~CheckMarginsChange() + { + const QList oldMarginsBefore = m_oldMargins; + m_oldMargins = m_marginsObject ? m_marginsObject->margins() : QList(); + + if (m_marginsObject && oldMarginsBefore != m_oldMargins) { + m_marginsObject->update(); + } + } + +private: + QList &m_oldMargins; + FrameSvgItemMargins *const m_marginsObject; +}; + +void FrameSvgItem::setImagePath(const QString &path) +{ + if (m_frameSvg->imagePath() == path) { + return; + } + + CheckMarginsChange checkMargins(m_oldMargins, m_margins); + CheckMarginsChange checkFixedMargins(m_oldFixedMargins, m_fixedMargins); + CheckMarginsChange checkInsetMargins(m_oldInsetMargins, m_insetMargins); + + updateDevicePixelRatio(); + m_frameSvg->setImagePath(path); + + if (implicitWidth() <= 0) { + setImplicitWidth(m_frameSvg->marginSize(KSvg::FrameSvg::LeftMargin) + m_frameSvg->marginSize(KSvg::FrameSvg::RightMargin)); + } + + if (implicitHeight() <= 0) { + setImplicitHeight(m_frameSvg->marginSize(KSvg::FrameSvg::TopMargin) + m_frameSvg->marginSize(KSvg::FrameSvg::BottomMargin)); + } + + Q_EMIT imagePathChanged(); + + if (isComponentComplete()) { + applyPrefixes(); + + m_frameSvg->resizeFrame(size()); + m_textureChanged = true; + update(); + } +} + +QString FrameSvgItem::imagePath() const +{ + return m_frameSvg->imagePath(); +} + +void FrameSvgItem::setPrefix(const QVariant &prefixes) +{ + QStringList prefixList; + // is this a simple string? + if (prefixes.canConvert()) { + prefixList << prefixes.toString(); + } else if (prefixes.canConvert()) { + prefixList = prefixes.toStringList(); + } + + if (m_prefixes == prefixList) { + return; + } + + CheckMarginsChange checkMargins(m_oldMargins, m_margins); + CheckMarginsChange checkFixedMargins(m_oldFixedMargins, m_fixedMargins); + CheckMarginsChange checkInsetMargins(m_oldInsetMargins, m_insetMargins); + + m_prefixes = prefixList; + applyPrefixes(); + + if (implicitWidth() <= 0) { + setImplicitWidth(m_frameSvg->marginSize(KSvg::FrameSvg::LeftMargin) + m_frameSvg->marginSize(KSvg::FrameSvg::RightMargin)); + } + + if (implicitHeight() <= 0) { + setImplicitHeight(m_frameSvg->marginSize(KSvg::FrameSvg::TopMargin) + m_frameSvg->marginSize(KSvg::FrameSvg::BottomMargin)); + } + + Q_EMIT prefixChanged(); + + if (isComponentComplete()) { + m_frameSvg->resizeFrame(QSizeF(width(), height())); + m_textureChanged = true; + update(); + } +} + +QVariant FrameSvgItem::prefix() const +{ + return m_prefixes; +} + +QString FrameSvgItem::usedPrefix() const +{ + return m_frameSvg->prefix(); +} + +FrameSvgItemMargins *FrameSvgItem::margins() +{ + if (!m_margins) { + m_margins = new FrameSvgItemMargins(m_frameSvg, this); + } + return m_margins; +} + +FrameSvgItemMargins *FrameSvgItem::fixedMargins() +{ + if (!m_fixedMargins) { + m_fixedMargins = new FrameSvgItemMargins(m_frameSvg, this); + m_fixedMargins->setFixed(true); + } + return m_fixedMargins; +} + +FrameSvgItemMargins *FrameSvgItem::inset() +{ + if (!m_insetMargins) { + m_insetMargins = new FrameSvgItemMargins(m_frameSvg, this); + m_insetMargins->setInset(true); + } + return m_insetMargins; +} + +bool FrameSvgItem::fromCurrentImageSet() const +{ + return m_frameSvg->fromCurrentImageSet(); +} + +void FrameSvgItem::setStatus(KSvg::Svg::Status status) +{ + m_frameSvg->setStatus(status); +} + +KSvg::Svg::Status FrameSvgItem::status() const +{ + return m_frameSvg->status(); +} + +void FrameSvgItem::setEnabledBorders(const KSvg::FrameSvg::EnabledBorders borders) +{ + if (m_frameSvg->enabledBorders() == borders) { + return; + } + + CheckMarginsChange checkMargins(m_oldMargins, m_margins); + + m_frameSvg->setEnabledBorders(borders); + Q_EMIT enabledBordersChanged(); + m_textureChanged = true; + update(); +} + +KSvg::FrameSvg::EnabledBorders FrameSvgItem::enabledBorders() const +{ + return m_frameSvg->enabledBorders(); +} + +void FrameSvgItem::setColorSet(KSvg::Svg::ColorSet colorSet) +{ + if (m_frameSvg->colorSet() == colorSet) { + return; + } + + m_frameSvg->setColorSet(colorSet); + m_textureChanged = true; + + update(); +} + +KSvg::Svg::ColorSet FrameSvgItem::colorSet() const +{ + return m_frameSvg->colorSet(); +} + +bool FrameSvgItem::hasElementPrefix(const QString &prefix) const +{ + return m_frameSvg->hasElementPrefix(prefix); +} + +bool FrameSvgItem::hasElement(const QString &elementName) const +{ + return m_frameSvg->hasElement(elementName); +} + +QRegion FrameSvgItem::mask() const +{ + return m_frameSvg->mask(); +} + +int FrameSvgItem::minimumDrawingHeight() const +{ + return m_frameSvg->minimumDrawingHeight(); +} + +int FrameSvgItem::minimumDrawingWidth() const +{ + return m_frameSvg->minimumDrawingWidth(); +} + +void FrameSvgItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + const bool isComponentComplete = this->isComponentComplete(); + if (isComponentComplete) { + m_frameSvg->resizeFrame(newGeometry.size()); + m_sizeChanged = true; + } + + QQuickItem::geometryChange(newGeometry, oldGeometry); + + // the above only triggers updatePaintNode, so we have to inform subscribers + // about the potential change of the mask explicitly here + if (isComponentComplete) { + Q_EMIT maskChanged(); + } +} + +void FrameSvgItem::doUpdate() +{ + if (m_frameSvg->isRepaintBlocked()) { + return; + } + + CheckMarginsChange checkMargins(m_oldMargins, m_margins); + CheckMarginsChange checkFixedMargins(m_oldFixedMargins, m_fixedMargins); + CheckMarginsChange checkInsetMargins(m_oldInsetMargins, m_insetMargins); + + // if the theme changed, the available prefix may have changed as well + applyPrefixes(); + + if (implicitWidth() <= 0) { + setImplicitWidth(m_frameSvg->marginSize(KSvg::FrameSvg::LeftMargin) + m_frameSvg->marginSize(KSvg::FrameSvg::RightMargin)); + } + + if (implicitHeight() <= 0) { + setImplicitHeight(m_frameSvg->marginSize(KSvg::FrameSvg::TopMargin) + m_frameSvg->marginSize(KSvg::FrameSvg::BottomMargin)); + } + + QString prefix = m_frameSvg->actualPrefix(); + bool hasOverlay = (!prefix.startsWith(QLatin1String("mask-")) // + && m_frameSvg->hasElement(prefix % QLatin1String("overlay"))); + bool hasComposeOverBorder = m_frameSvg->hasElement(prefix % QLatin1String("hint-compose-over-border")) + && m_frameSvg->hasElement(QLatin1String("mask-") % prefix % QLatin1String("center")); + m_fastPath = !hasOverlay && !hasComposeOverBorder; + + // Software rendering (at time of writing Qt5.10) doesn't seem to like our + // tiling/stretching in the 9-tiles. + // Also when using QPainter it's arguably faster to create and cache pixmaps + // of the whole frame, which is what the slow path does + if (QQuickWindow::sceneGraphBackend() == QLatin1String("software")) { + m_fastPath = false; + } + m_textureChanged = true; + + update(); + + Q_EMIT maskChanged(); + Q_EMIT repaintNeeded(); +} + +KSvg::FrameSvg *FrameSvgItem::frameSvg() const +{ + return m_frameSvg; +} + +QSGNode *FrameSvgItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) +{ + if (!window() || !m_frameSvg // + || (!m_frameSvg->hasElementPrefix(m_frameSvg->actualPrefix()) // + && !m_frameSvg->hasElementPrefix(m_frameSvg->prefix()))) { + delete oldNode; + return nullptr; + } + + const QSGTexture::Filtering filtering = smooth() ? QSGTexture::Linear : QSGTexture::Nearest; + + if (m_fastPath) { + if (m_textureChanged) { + delete oldNode; + oldNode = nullptr; + } + + if (!oldNode) { + QString prefix = m_frameSvg->actualPrefix(); + oldNode = new FrameNode(prefix, m_frameSvg); + + bool tileCenter = (m_frameSvg->hasElement(QStringLiteral("hint-tile-center")) // + || m_frameSvg->hasElement(prefix % QLatin1String("hint-tile-center"))); + bool stretchBorders = (m_frameSvg->hasElement(QStringLiteral("hint-stretch-borders")) // + || m_frameSvg->hasElement(prefix % QLatin1String("hint-stretch-borders"))); + FrameItemNode::FitMode borderFitMode = stretchBorders ? FrameItemNode::Stretch : FrameItemNode::Tile; + FrameItemNode::FitMode centerFitMode = tileCenter ? FrameItemNode::Tile : FrameItemNode::Stretch; + + new FrameItemNode(this, FrameSvg::NoBorder, centerFitMode, oldNode); + if (enabledBorders() & (FrameSvg::TopBorder | FrameSvg::LeftBorder)) { + new FrameItemNode(this, FrameSvg::TopBorder | FrameSvg::LeftBorder, FrameItemNode::FastStretch, oldNode); + } + if (enabledBorders() & (FrameSvg::TopBorder | FrameSvg::RightBorder)) { + new FrameItemNode(this, FrameSvg::TopBorder | FrameSvg::RightBorder, FrameItemNode::FastStretch, oldNode); + } + if (enabledBorders() & FrameSvg::TopBorder) { + new FrameItemNode(this, FrameSvg::TopBorder, borderFitMode, oldNode); + } + if (enabledBorders() & FrameSvg::BottomBorder) { + new FrameItemNode(this, FrameSvg::BottomBorder, borderFitMode, oldNode); + } + if (enabledBorders() & (FrameSvg::BottomBorder | FrameSvg::LeftBorder)) { + new FrameItemNode(this, FrameSvg::BottomBorder | FrameSvg::LeftBorder, FrameItemNode::FastStretch, oldNode); + } + if (enabledBorders() & (FrameSvg::BottomBorder | FrameSvg::RightBorder)) { + new FrameItemNode(this, FrameSvg::BottomBorder | FrameSvg::RightBorder, FrameItemNode::FastStretch, oldNode); + } + if (enabledBorders() & FrameSvg::LeftBorder) { + new FrameItemNode(this, FrameSvg::LeftBorder, borderFitMode, oldNode); + } + if (enabledBorders() & FrameSvg::RightBorder) { + new FrameItemNode(this, FrameSvg::RightBorder, borderFitMode, oldNode); + } + + m_sizeChanged = true; + m_textureChanged = false; + } + + QSGNode *node = oldNode->firstChild(); + while (node) { + static_cast(node)->setFiltering(filtering); + node = node->nextSibling(); + } + + if (m_sizeChanged) { + FrameNode *frameNode = static_cast(oldNode); + QSize frameSize(width(), height()); + QRect geometry = frameNode->contentsRect(frameSize); + QSGNode *node = oldNode->firstChild(); + while (node) { + static_cast(node)->reposition(geometry, frameSize); + node = node->nextSibling(); + } + + m_sizeChanged = false; + } + } else { + ManagedTextureNode *textureNode = dynamic_cast(oldNode); + if (!textureNode) { + delete oldNode; + textureNode = new ManagedTextureNode; + m_textureChanged = true; // force updating the texture on our newly created node + oldNode = textureNode; + } + textureNode->setFiltering(filtering); + + if ((m_textureChanged || m_sizeChanged) || textureNode->texture()->textureSize() != m_frameSvg->size()) { + QImage image = m_frameSvg->framePixmap().toImage(); + textureNode->setTexture(s_cache->loadTexture(window(), image)); + textureNode->setRect(0, 0, width(), height()); + + m_textureChanged = false; + m_sizeChanged = false; + } + } + + return oldNode; +} + +void FrameSvgItem::classBegin() +{ + QQuickItem::classBegin(); + m_frameSvg->setRepaintBlocked(true); +} + +void FrameSvgItem::componentComplete() +{ + m_kirigamiTheme = qobject_cast(qmlAttachedPropertiesObject(this, true)); + if (!m_kirigamiTheme) { + qCWarning(LOG_KSVGQML) << "no theme!" << qmlAttachedPropertiesObject(this, true) << this; + return; + } + + auto checkApplyTheme = [this]() { + if (!m_frameSvg->imageSet()->filePath(QStringLiteral("colors")).isEmpty()) { + m_frameSvg->clearCache(); + m_frameSvg->clearColorOverrides(); + } + }; + auto applyTheme = [this]() { + if (!m_frameSvg->imageSet()->filePath(QStringLiteral("colors")).isEmpty()) { + m_frameSvg->clearCache(); + m_frameSvg->clearColorOverrides(); + + return; + } + m_frameSvg->setColor(Svg::Text, m_kirigamiTheme->textColor()); + m_frameSvg->setColor(Svg::Background, m_kirigamiTheme->backgroundColor()); + m_frameSvg->setColor(Svg::Highlight, m_kirigamiTheme->highlightColor()); + m_frameSvg->setColor(Svg::HighlightedText, m_kirigamiTheme->highlightedTextColor()); + m_frameSvg->setColor(Svg::PositiveText, m_kirigamiTheme->positiveTextColor()); + m_frameSvg->setColor(Svg::NeutralText, m_kirigamiTheme->neutralTextColor()); + m_frameSvg->setColor(Svg::NegativeText, m_kirigamiTheme->negativeTextColor()); + }; + applyTheme(); + connect(m_kirigamiTheme, &Kirigami::Platform::PlatformTheme::colorsChanged, this, applyTheme); + connect(m_frameSvg->imageSet(), &ImageSet::imageSetChanged, this, checkApplyTheme); + connect(m_frameSvg, &Svg::imageSetChanged, this, checkApplyTheme); + + CheckMarginsChange checkMargins(m_oldMargins, m_margins); + CheckMarginsChange checkFixedMargins(m_oldFixedMargins, m_fixedMargins); + CheckMarginsChange checkInsetMargins(m_oldInsetMargins, m_insetMargins); + + QQuickItem::componentComplete(); + m_frameSvg->resizeFrame(size()); + m_frameSvg->setRepaintBlocked(false); + m_textureChanged = true; +} + +void FrameSvgItem::updateDevicePixelRatio() +{ + const auto newDevicePixelRatio = std::max(1.0, (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio())); + if (newDevicePixelRatio != m_frameSvg->devicePixelRatio()) { + m_frameSvg->setDevicePixelRatio(newDevicePixelRatio); + m_textureChanged = true; + } +} + +void FrameSvgItem::applyPrefixes() +{ + if (m_frameSvg->imagePath().isEmpty()) { + return; + } + + const QString oldPrefix = m_frameSvg->prefix(); + + if (m_prefixes.isEmpty()) { + m_frameSvg->setElementPrefix(QString()); + if (oldPrefix != m_frameSvg->prefix()) { + Q_EMIT usedPrefixChanged(); + } + return; + } + + bool found = false; + for (const QString &prefix : std::as_const(m_prefixes)) { + if (m_frameSvg->hasElementPrefix(prefix)) { + m_frameSvg->setElementPrefix(prefix); + found = true; + break; + } + } + if (!found) { + // this setElementPrefix is done to keep the same behavior as before, when it was a simple string + m_frameSvg->setElementPrefix(m_prefixes.constLast()); + } + if (oldPrefix != m_frameSvg->prefix()) { + Q_EMIT usedPrefixChanged(); + } +} + +void FrameSvgItem::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) +{ + if (change == ItemSceneChange && value.window) { + updateDevicePixelRatio(); + } else if (change == QQuickItem::ItemDevicePixelRatioHasChanged) { + updateDevicePixelRatio(); + } + + QQuickItem::itemChange(change, value); +} + +} // KSvg namespace + +#include "moc_framesvgitem.cpp" diff --git a/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/framesvgitem.h b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/framesvgitem.h new file mode 100644 index 0000000000..6ae43429f5 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/framesvgitem.h @@ -0,0 +1,328 @@ +/* + SPDX-FileCopyrightText: 2010 Marco Martin + SPDX-FileCopyrightText: 2014 David Edmundson + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#ifndef FRAMESVGITEM_P +#define FRAMESVGITEM_P + +#include +#include + +#include + +#include + +namespace Kirigami +{ +namespace Platform +{ +class PlatformTheme; +} +}; + +namespace KSvg +{ +class FrameSvg; + +/** + * @class FrameSvgItemMargins + * + * @short The sizes of a frame's margins. + */ +class FrameSvgItemMargins : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("FrameSvgItemMargins are read-only properties of FrameSvgItem") + + /** + * @brief This property holds the left margin's width in pixels. + * @property real left + */ + Q_PROPERTY(qreal left READ left NOTIFY marginsChanged) + + /** + * @brief This property holds the top margin's width in pixels. + * @property real top + */ + Q_PROPERTY(qreal top READ top NOTIFY marginsChanged) + + /** + * @brief This property holds the right margin's width in pixels. + * @property real right + */ + Q_PROPERTY(qreal right READ right NOTIFY marginsChanged) + + /** + * @brief This property holds the bottom margin's width in pixels. + * @property real bottom + */ + Q_PROPERTY(qreal bottom READ bottom NOTIFY marginsChanged) + + /** + * @brief This property holds the combined width of the left and right margins. + * @property real horizontal + */ + Q_PROPERTY(qreal horizontal READ horizontal NOTIFY marginsChanged) + + /** + * @brief This property holds the combined width of the top and bottom margins. + * @property real vertical + */ + Q_PROPERTY(qreal vertical READ vertical NOTIFY marginsChanged) + +public: + FrameSvgItemMargins(KSvg::FrameSvg *frameSvg, QObject *parent = nullptr); + + qreal left() const; + qreal top() const; + qreal right() const; + qreal bottom() const; + qreal horizontal() const; + qreal vertical() const; + + /// returns a vector with left, top, right, bottom + QList margins() const; + + void setFixed(bool fixed); + bool isFixed() const; + + void setInset(bool inset); + bool isInset() const; + +public Q_SLOTS: + void update(); + +Q_SIGNALS: + void marginsChanged(); + +private: + FrameSvg *m_frameSvg; + bool m_fixed; + bool m_inset; +}; + +/** + * @class FrameSvgItem + * @short An SVG Item with borders. + * @import org.kde.ksvg + */ +class FrameSvgItem : public QQuickItem +{ + Q_OBJECT + QML_ELEMENT + Q_INTERFACES(QQmlParserStatus) + + /** + * @brief This property specifies the relative path of the SVG in the theme. + * + * Example: "widgets/background" + * + * @property QString imagePath + */ + Q_PROPERTY(QString imagePath READ imagePath WRITE setImagePath NOTIFY imagePathChanged) + + /** + * This property holds the prefix for the SVG. + * prefix for the 9-piece SVG, like "pushed" or "normal" for a button. + * see https://techbase.kde.org/Development/Tutorials/Plasma5/ThemeDetails + * for a list of paths and prefixes + * It can also be an array of strings, specifying a fallback chain in case + * the first element isn't found in the theme, eg ["toolbutton-normal", "normal"] + * so it's easy to keep backwards compatibility with old themes + * (Note: fallback chain is supported only @since 5.32) + */ + Q_PROPERTY(QVariant prefix READ prefix WRITE setPrefix NOTIFY prefixChanged) + + /** + * @brief This property holds the actual prefix that was used, if a fallback + * chain array was set as "prefix". + * + * @since 5.34 + * @property QString usedPrefix + */ + Q_PROPERTY(QString usedPrefix READ usedPrefix NOTIFY usedPrefixChanged) + + /** + * @brief This property holds the frame's margins. + * @see FrameSvgItemMargins + * @property FrameSvgItemMargins margins + */ + Q_PROPERTY(KSvg::FrameSvgItemMargins *margins READ margins CONSTANT) + + /** + * @brief This property holds the fixed margins of the frame which are used + * regardless of any margins being enabled or not. + * + * @see FrameSvgItemMargins + * @property FrameSvgItemMargins margins + */ + Q_PROPERTY(KSvg::FrameSvgItemMargins *fixedMargins READ fixedMargins CONSTANT) + + /** + * @brief This property holds the frame's inset. + * + * @see FrameSvgItemMargins + * + * @since 5.77 + * @property FrameSvgItemMargins margins + */ + Q_PROPERTY(KSvg::FrameSvgItemMargins *inset READ inset CONSTANT) + + /** + * @brief This property specifies which borders are shown. + * @see KSvg::FrameSvg::EnabledBorder + * @property flags enabledBorders + */ + Q_PROPERTY(KSvg::FrameSvg::EnabledBorders enabledBorders READ enabledBorders WRITE setEnabledBorders NOTIFY enabledBordersChanged) + + /** + * @brief This property holds whether the current SVG is present in + * the currently-used theme and no fallback is involved. + */ + Q_PROPERTY(bool fromCurrentImageSet READ fromCurrentImageSet NOTIFY fromCurrentImageSetChanged) + + /** + * @brief This property specifies the SVG's status. + * + * Depending on the specified status, the SVG will use different colors: + * * Normal: text's color is textColor, and background color is + * backgroundColor. + * * Selected: text color becomes highlightedText and background color is + * changed to highlightColor. + * + * @see Kirigami::PlatformTheme + * @see KSvg::Svg::status + * @since 5.23 + * @property enum status + */ + Q_PROPERTY(KSvg::Svg::Status status READ status WRITE setStatus NOTIFY statusChanged) + + /** + * @brief This property holds the mask that contains the SVG's painted areas. + * @since 5.58 + * @property QRegion mask + */ + Q_PROPERTY(QRegion mask READ mask NOTIFY maskChanged) + + /** + * @brief This property holds the minimum height required to correctly draw + * this SVG. + * + * @since 5.101 + * @property int minimumDrawingHeight + */ + Q_PROPERTY(int minimumDrawingHeight READ minimumDrawingHeight NOTIFY repaintNeeded) + + /** + * @brief This property holds the minimum width required to correctly draw + * this SVG. + * + * @since 5.101 + * @property int minimumDrawingWidth + */ + Q_PROPERTY(int minimumDrawingWidth READ minimumDrawingWidth NOTIFY repaintNeeded) + +public: + /** + * @return whether the svg has the necessary elements with the given prefix + * to draw a frame. + * + * @param prefix the given prefix we want to check if drawable + */ + Q_INVOKABLE bool hasElementPrefix(const QString &prefix) const; + + /** + * @return whether the SVG includes the given element. + * + * This is a convenience function that forwards to hasElement(). + * + * @see KSvg::Svg::hasElement() + */ + Q_INVOKABLE bool hasElement(const QString &elementName) const; + + /// @cond INTERNAL_DOCS + FrameSvgItem(QQuickItem *parent = nullptr); + ~FrameSvgItem() override; + + void setImagePath(const QString &path); + QString imagePath() const; + + void setPrefix(const QVariant &prefix); + QVariant prefix() const; + + QString usedPrefix() const; + + void setEnabledBorders(const KSvg::FrameSvg::EnabledBorders borders); + KSvg::FrameSvg::EnabledBorders enabledBorders() const; + + void setColorSet(KSvg::Svg::ColorSet colorSet); + KSvg::Svg::ColorSet colorSet() const; + + FrameSvgItemMargins *margins(); + FrameSvgItemMargins *fixedMargins(); + FrameSvgItemMargins *inset(); + + bool fromCurrentImageSet() const; + + void setStatus(KSvg::Svg::Status status); + KSvg::Svg::Status status() const; + int minimumDrawingHeight() const; + int minimumDrawingWidth() const; + + void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; + + QRegion mask() const; + + /** + * Only to be used from inside this library, is not intended to be invokable + */ + KSvg::FrameSvg *frameSvg() const; + + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override; + + void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) override; + +protected: + void classBegin() override; + void componentComplete() override; + + /// @endcond + +Q_SIGNALS: + void imagePathChanged(); + void prefixChanged(); + void enabledBordersChanged(); + void fromCurrentImageSetChanged(); + void repaintNeeded(); + void statusChanged(); + void usedPrefixChanged(); + void maskChanged(); + +private Q_SLOTS: + void doUpdate(); + +private: + void updateDevicePixelRatio(); + void applyPrefixes(); + + KSvg::FrameSvg *m_frameSvg; + Kirigami::Platform::PlatformTheme *m_kirigamiTheme; + FrameSvgItemMargins *m_margins; + FrameSvgItemMargins *m_fixedMargins; + FrameSvgItemMargins *m_insetMargins; + // logged margins to check for changes + QList m_oldMargins; + QList m_oldFixedMargins; + QList m_oldInsetMargins; + QStringList m_prefixes; + bool m_textureChanged; + bool m_sizeChanged; + bool m_fastPath; +}; + +} + +#endif diff --git a/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/imagetexturescache.cpp b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/imagetexturescache.cpp new file mode 100644 index 0000000000..34f410f7a1 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/imagetexturescache.cpp @@ -0,0 +1,58 @@ +/* + SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "imagetexturescache.h" +#include + +typedef QHash>> TexturesCache; + +class ImageTexturesCachePrivate +{ +public: + TexturesCache cache; +}; + +ImageTexturesCache::ImageTexturesCache() + : d(new ImageTexturesCachePrivate) +{ +} + +ImageTexturesCache::~ImageTexturesCache() +{ +} + +QSharedPointer ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options) +{ + qint64 id = image.cacheKey(); + QSharedPointer texture = d->cache.value(id).value(window).toStrongRef(); + + if (!texture) { + auto cleanAndDelete = [this, window, id](QSGTexture *texture) { + QHash> &textures = (d->cache)[id]; + textures.remove(window); + if (textures.isEmpty()) { + d->cache.remove(id); + } + delete texture; + }; + texture = QSharedPointer(window->createTextureFromImage(image, options), cleanAndDelete); + (d->cache)[id][window] = texture.toWeakRef(); + } + + // if we have a cache in an atlas but our request cannot use an atlassed texture + // create a new texture and use that + // don't use removedFromAtlas() as that requires keeping a reference to the non atlased version + if (!(options & QQuickWindow::TextureCanUseAtlas) && texture->isAtlasTexture()) { + texture = QSharedPointer(window->createTextureFromImage(image, options)); + } + + return texture; +} + +QSharedPointer ImageTexturesCache::loadTexture(QQuickWindow *window, const QImage &image) +{ + return loadTexture(window, image, QQuickWindow::CreateTextureOptions()); +} diff --git a/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/imagetexturescache.h b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/imagetexturescache.h new file mode 100644 index 0000000000..30b065b26b --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/imagetexturescache.h @@ -0,0 +1,48 @@ +/* + SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef IMAGETEXTURESCACHE_H +#define IMAGETEXTURESCACHE_H + +#include +#include + +class QImage; +class QSGTexture; +class ImageTexturesCachePrivate; + +/** + * @class ImageTexturesCache imagetexturescache.h KQuickAddons/ImageTexturesCache + * + * @short Helps to manage textures by creating images and reference counts them. + * + * Use this class as a factory for textures, when creating them from a QImage + * instance. Keeps track of all the created textures in a map between the + * QImage::cacheKey() and the cached texture until it gets de-referenced. + * + * @see ManagedTextureNode + */ +class ImageTexturesCache +{ +public: + ImageTexturesCache(); + ~ImageTexturesCache(); + + /** + * @returns the texture for a given @p window and @p image. + * + * If @p image id is the same as one already provided before, we will not + * create a new texture, and will instead return a shared pointer to the existing texture. + */ + QSharedPointer loadTexture(QQuickWindow *window, const QImage &image, QQuickWindow::CreateTextureOptions options); + + QSharedPointer loadTexture(QQuickWindow *window, const QImage &image); + +private: + QScopedPointer d; +}; + +#endif // IMAGETEXTURESCACHE_H diff --git a/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/managedtexturenode.cpp b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/managedtexturenode.cpp new file mode 100644 index 0000000000..e701feddbf --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/managedtexturenode.cpp @@ -0,0 +1,17 @@ +/* + SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "managedtexturenode.h" + +ManagedTextureNode::ManagedTextureNode() +{ +} + +void ManagedTextureNode::setTexture(QSharedPointer texture) +{ + m_texture = texture; + QSGSimpleTextureNode::setTexture(texture.data()); +} diff --git a/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/managedtexturenode.h b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/managedtexturenode.h new file mode 100644 index 0000000000..e0b6dde598 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/managedtexturenode.h @@ -0,0 +1,27 @@ +/* + SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef MANAGEDTEXTURENODE_H +#define MANAGEDTEXTURENODE_H + +#include +#include +#include +#include + +class ManagedTextureNode : public QSGSimpleTextureNode +{ + Q_DISABLE_COPY(ManagedTextureNode) +public: + ManagedTextureNode(); + + void setTexture(QSharedPointer texture); + +private: + QSharedPointer m_texture; +}; + +#endif diff --git a/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/svgitem.cpp b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/svgitem.cpp new file mode 100644 index 0000000000..c1e6e9e59b --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/svgitem.cpp @@ -0,0 +1,292 @@ +/* + SPDX-FileCopyrightText: 2010 Marco Martin + SPDX-FileCopyrightText: 2014 David Edmundson + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "svgitem.h" + +#include +#include +#include +#include + +#include "ksvg/svg.h" + +#include "managedtexturenode.h" + +#include +#include + +namespace KSvg +{ +SvgItem::SvgItem(QQuickItem *parent) + : QQuickItem(parent) + , m_textureChanged(false) +{ + m_svg = new KSvg::Svg(this); + setFlag(QQuickItem::ItemHasContents, true); + + connect(m_svg, &Svg::repaintNeeded, this, &SvgItem::updateNeeded); + connect(m_svg, &Svg::repaintNeeded, this, &SvgItem::naturalSizeChanged); + connect(m_svg, &Svg::sizeChanged, this, &SvgItem::naturalSizeChanged); + connect(m_svg, &Svg::repaintNeeded, this, &SvgItem::elementRectChanged); + connect(m_svg, &Svg::sizeChanged, this, &SvgItem::elementRectChanged); +} + +SvgItem::~SvgItem() +{ + // Make sure to not call anything on m_svg when this is shutting down + // Kirigami::PlatformTheme will lose its window at that point so will + // emit colorschanged, which we shouldn't react to during destructor + disconnect(m_kirigamiTheme, nullptr, this, nullptr); +} + +void SvgItem::componentComplete() +{ + m_kirigamiTheme = qobject_cast(qmlAttachedPropertiesObject(this, true)); + if (!m_kirigamiTheme) { + qCWarning(LOG_KSVGQML) << "No theme!" << qmlAttachedPropertiesObject(this, true) << this; + return; + } + + auto checkApplyTheme = [this]() { + if (!m_svg->imageSet()->filePath(QStringLiteral("colors")).isEmpty()) { + m_svg->clearColorOverrides(); + } + }; + auto applyTheme = [this]() { + if (!m_svg) { + return; + } + if (!m_svg->imageSet()->filePath(QStringLiteral("colors")).isEmpty()) { + m_svg->clearColorOverrides(); + return; + } + m_svg->setColor(Svg::Text, m_kirigamiTheme->textColor()); + m_svg->setColor(Svg::Background, m_kirigamiTheme->backgroundColor()); + m_svg->setColor(Svg::Highlight, m_kirigamiTheme->highlightColor()); + m_svg->setColor(Svg::HighlightedText, m_kirigamiTheme->highlightedTextColor()); + m_svg->setColor(Svg::PositiveText, m_kirigamiTheme->positiveTextColor()); + m_svg->setColor(Svg::NeutralText, m_kirigamiTheme->neutralTextColor()); + m_svg->setColor(Svg::NegativeText, m_kirigamiTheme->negativeTextColor()); + }; + applyTheme(); + connect(m_kirigamiTheme, &Kirigami::Platform::PlatformTheme::colorsChanged, this, applyTheme); + connect(m_svg->imageSet(), &ImageSet::imageSetChanged, this, checkApplyTheme); + connect(m_svg, &Svg::imageSetChanged, this, checkApplyTheme); + + QQuickItem::componentComplete(); +} + +void SvgItem::setImagePath(const QString &path) +{ + if (!m_svg || m_svg->imagePath() == path) { + return; + } + + updateDevicePixelRatio(); + m_svg->setImagePath(path); + + Q_EMIT imagePathChanged(); + + if (isComponentComplete()) { + update(); + } +} + +QString SvgItem::imagePath() const +{ + return m_svg->imagePath(); +} + +void SvgItem::setElementId(const QString &elementID) +{ + if (elementID == m_elementID) { + return; + } + + if (implicitWidth() <= 0) { + setImplicitWidth(naturalSize().width()); + } + if (implicitHeight() <= 0) { + setImplicitHeight(naturalSize().height()); + } + + m_elementID = elementID; + Q_EMIT elementIdChanged(); + Q_EMIT naturalSizeChanged(); + Q_EMIT elementRectChanged(); + + scheduleImageUpdate(); +} + +QString SvgItem::elementId() const +{ + return m_elementID; +} + +void SvgItem::setSvg(KSvg::Svg *svg) +{ + if (m_svg) { + disconnect(m_svg.data(), nullptr, this, nullptr); + } + m_svg = svg; + + if (svg) { + connect(svg, &Svg::repaintNeeded, this, &SvgItem::updateNeeded); + connect(svg, &Svg::repaintNeeded, this, &SvgItem::naturalSizeChanged); + connect(svg, &Svg::repaintNeeded, this, &SvgItem::elementRectChanged); + connect(svg, &Svg::sizeChanged, this, &SvgItem::naturalSizeChanged); + connect(svg, &Svg::sizeChanged, this, &SvgItem::elementRectChanged); + } + + if (implicitWidth() <= 0) { + setImplicitWidth(naturalSize().width()); + } + if (implicitHeight() <= 0) { + setImplicitHeight(naturalSize().height()); + } + + scheduleImageUpdate(); + + Q_EMIT svgChanged(); + Q_EMIT naturalSizeChanged(); + Q_EMIT elementRectChanged(); + Q_EMIT imagePathChanged(); +} + +KSvg::Svg *SvgItem::svg() const +{ + return m_svg.data(); +} + +QSizeF SvgItem::naturalSize() const +{ + if (!m_svg) { + return QSizeF(); + } else if (!m_elementID.isEmpty()) { + return m_svg->elementSize(m_elementID); + } + + return m_svg->size(); +} + +QRectF SvgItem::elementRect() const +{ + if (!m_svg) { + return QRectF(); + } else if (!m_elementID.isEmpty()) { + return m_svg->elementRect(m_elementID); + } + + return QRectF(QPointF(0, 0), m_svg->size()); +} + +QSGNode *SvgItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) +{ + Q_UNUSED(updatePaintNodeData); + if (!window() || !m_svg) { + delete oldNode; + return nullptr; + } + + // this is more than just an optimization, uploading a null image to QSGAtlasTexture causes a crash + if (width() == 0.0 || height() == 0.0) { + delete oldNode; + return nullptr; + } + + ManagedTextureNode *textureNode = static_cast(oldNode); + if (!textureNode) { + textureNode = new ManagedTextureNode; + m_textureChanged = true; + } + + // TODO use a heuristic to work out when to redraw + // if !m_smooth and size is approximate simply change the textureNode.rect without + // updating the material + + if (m_textureChanged || textureNode->texture()->textureSize() != QSize(width(), height())) { + // despite having a valid size sometimes we still get a null QImage from KSvg::Svg + // loading a null texture to an atlas fatals + // Dave E fixed this in Qt in 5.3.something onwards but we need this for now + if (m_image.isNull()) { + delete textureNode; + return nullptr; + } + + QSharedPointer texture(window()->createTextureFromImage(m_image, QQuickWindow::TextureCanUseAtlas)); + textureNode->setTexture(texture); + m_textureChanged = false; + + textureNode->setRect(0, 0, width(), height()); + } + + textureNode->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest); + + return textureNode; +} + +void SvgItem::updateNeeded() +{ + if (implicitWidth() <= 0) { + setImplicitWidth(naturalSize().width()); + } + if (implicitHeight() <= 0) { + setImplicitHeight(naturalSize().height()); + } + scheduleImageUpdate(); +} + +void SvgItem::scheduleImageUpdate() +{ + polish(); + update(); +} + +void SvgItem::updatePolish() +{ + QQuickItem::updatePolish(); + + if (m_svg) { + // setContainsMultipleImages has to be done there since m_svg can be shared with somebody else + m_textureChanged = true; + m_svg->setContainsMultipleImages(!m_elementID.isEmpty()); + m_image = m_svg->image(QSize(width(), height()), m_elementID); + } +} + +void SvgItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + if (newGeometry.size() != oldGeometry.size() && newGeometry.isValid()) { + scheduleImageUpdate(); + } + + QQuickItem::geometryChange(newGeometry, oldGeometry); +} + +void SvgItem::updateDevicePixelRatio() +{ + const auto newDevicePixelRatio = std::max(1.0, (window() ? window()->devicePixelRatio() : qApp->devicePixelRatio())); + if (newDevicePixelRatio != m_svg->devicePixelRatio()) { + m_svg->setDevicePixelRatio(newDevicePixelRatio); + m_textureChanged = true; + } +} + +void SvgItem::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) +{ + if (change == ItemSceneChange && value.window) { + updateDevicePixelRatio(); + } else if (change == QQuickItem::ItemDevicePixelRatioHasChanged) { + updateDevicePixelRatio(); + } + + QQuickItem::itemChange(change, value); +} + +} // KSvg namespace + +#include "moc_svgitem.cpp" diff --git a/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/svgitem.h b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/svgitem.h new file mode 100644 index 0000000000..0588966655 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/svgitem.h @@ -0,0 +1,139 @@ +/* + SPDX-FileCopyrightText: 2010 Marco Martin + SPDX-FileCopyrightText: 2014 David Edmundson + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#ifndef SVGITEM_P +#define SVGITEM_P + +#include +#include + +#include + +namespace Kirigami +{ +namespace Platform +{ +class PlatformTheme; +} +}; + +namespace KSvg +{ +class Svg; + +/** + * @class SvgItem + * @short Displays an SVG or an element from an SVG file + */ +class SvgItem : public QQuickItem +{ + Q_OBJECT + QML_ELEMENT + + /** + * @brief This property specifies the relative path of the Svg in the theme. + * + * Example: "widgets/background" + * + * @property QString imagePath + */ + Q_PROPERTY(QString imagePath READ imagePath WRITE setImagePath NOTIFY imagePathChanged) + + /** + * @brief This property specifies the sub-element of the SVG to be + * rendered. + * + * If this is empty, the whole SVG document will be rendered. + * + * @property QString elementId + */ + Q_PROPERTY(QString elementId READ elementId WRITE setElementId NOTIFY elementIdChanged) + + /** + * @brief This property holds the SVG's natural, unscaled size. + * + * This is useful if a pixel-perfect rendering of outlines is needed. + * + * @property QSizeF naturalSize + */ + Q_PROPERTY(QSizeF naturalSize READ naturalSize NOTIFY naturalSizeChanged) + + /** + * @brief This property holds the rectangle of the selected elementId + * relative to the unscaled size of the SVG document. + * + * Note that this property will holds the entire SVG if element id is not + * selected. + * + * @property QRectF elementRect + */ + Q_PROPERTY(QRectF elementRect READ elementRect NOTIFY elementRectChanged) + + /** + * @brief This property holds the internal SVG instance. + * + * Usually, specifying just the imagePath is enough. Use this if you have + * many items taking the same SVG as source, and you want to share the + * internal SVG object. + * + * @property KSvg::Svg svg + */ + Q_PROPERTY(KSvg::Svg *svg READ svg WRITE setSvg NOTIFY svgChanged) + +public: + /// @cond INTERNAL_DOCS + + explicit SvgItem(QQuickItem *parent = nullptr); + ~SvgItem() override; + + void setImagePath(const QString &path); + QString imagePath() const; + + void setElementId(const QString &elementID); + QString elementId() const; + + void setSvg(KSvg::Svg *svg); + KSvg::Svg *svg() const; + + QSizeF naturalSize() const; + + QRectF elementRect() const; + + QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) override; + /// @endcond + + void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) override; + +protected: + void componentComplete() override; + +Q_SIGNALS: + void imagePathChanged(); + void elementIdChanged(); + void svgChanged(); + void naturalSizeChanged(); + void elementRectChanged(); + +protected Q_SLOTS: + /// @cond INTERNAL_DOCS + void updateNeeded(); + /// @endcond + +private: + void updateDevicePixelRatio(); + void scheduleImageUpdate(); + void updatePolish() override; + void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; + + QPointer m_svg; + Kirigami::Platform::PlatformTheme *m_kirigamiTheme; + QString m_elementID; + QImage m_image; + bool m_textureChanged; +}; +} + +#endif diff --git a/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/types.h b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/types.h new file mode 100644 index 0000000000..3935095106 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/declarativeimports/types.h @@ -0,0 +1,45 @@ +/* + SPDX-FileCopyrightText: 2023 Nicolas Fella + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KSVG_TYPES_H +#define KSVG_TYPES_H + +#include + +#include + +#include +#include + +struct PlatformThemeForeign { + Q_GADGET + QML_ANONYMOUS + QML_FOREIGN(Kirigami::Platform::PlatformTheme) +}; + +struct SvgForeign { + Q_GADGET + QML_ELEMENT + QML_NAMED_ELEMENT(Svg) + QML_FOREIGN(KSvg::Svg) +}; + +struct FrameSvgForeign { + Q_GADGET + QML_ELEMENT + QML_NAMED_ELEMENT(FrameSvg) + QML_FOREIGN(KSvg::FrameSvg) +}; + +struct ImageSetForeign { + Q_GADGET + QML_ELEMENT + QML_SINGLETON + QML_NAMED_ELEMENT(ImageSet) + QML_FOREIGN(KSvg::ImageSet) +}; + +#endif diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/.krazy b/local/recipes/kde/kf6-ksvg/source/src/ksvg/.krazy new file mode 100644 index 0000000000..587e2fcca6 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/.krazy @@ -0,0 +1,2 @@ +EXTRA defines,kdebug,qenums,tipsandthis +SKIP /widgets/template\.h diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/CMakeLists.txt b/local/recipes/kde/kf6-ksvg/source/src/ksvg/CMakeLists.txt new file mode 100644 index 0000000000..aafce44f7d --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/CMakeLists.txt @@ -0,0 +1,119 @@ + + +# Consumer's include dir which has to be explicitly used to make headers of this lib visible to documented includes +# Results in duplicate of prefix-dir & C++ namespace below, but part of different things, so by design: +# //class header files +set(KSVG_INSTALL_INCLUDEDIR "${KDE_INSTALL_INCLUDEDIR_KF}/KSvg") + +add_library(KF6Svg) +add_library(KF6::Svg ALIAS KF6Svg) + +qt_extract_metatypes(KF6Svg) + +set_target_properties(KF6Svg PROPERTIES + VERSION ${KSVG_VERSION} + SOVERSION ${KSVG_SOVERSION} + EXPORT_NAME Svg +) + +target_sources(KF6Svg PRIVATE + framesvg.cpp + svg.cpp + imageset.cpp + private/imageset_p.cpp +) + +ecm_qt_declare_logging_category(KF6Svg + HEADER debug_p.h + IDENTIFIER LOG_KSVG + CATEGORY_NAME kf.svg + DESCRIPTION "KSvg lib" + EXPORT KSVG +) + +ecm_generate_export_header(KF6Svg + EXPORT_FILE_NAME ksvg/ksvg_export.h + BASE_NAME KSvg + GROUP_BASE_NAME KF + VERSION ${KF_VERSION} + USE_VERSION_HEADER + DEPRECATED_BASE_VERSION 0 + EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} + DEPRECATION_VERSIONS +) + +target_link_libraries(KF6Svg +PUBLIC + Qt6::Gui + KF6::ConfigCore +PRIVATE + Qt6::Svg + KF6::Archive + KF6::CoreAddons + KF6::GuiAddons #kimagecache + KF6::ConfigCore + KF6::ColorScheme +) + +set(KSvg_BUILD_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/KSvg +) +target_include_directories(KF6Svg + PUBLIC + "$" + INTERFACE + "$" +) + +########### install files ############### +ecm_generate_headers(KSvg_CamelCase_HEADERS + HEADER_NAMES + FrameSvg + Svg + ImageSet + REQUIRED_HEADERS KSvg_namespaced_HEADERS + PREFIX KSvg +) + +install( + FILES ${KSvg_namespaced_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/ksvg/ksvg_export.h + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KSvg/ksvg # C++ namespace + COMPONENT Devel +) + +install( + FILES ${KSvg_CamelCase_HEADERS} + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KSvg/KSvg # C++ namespace + COMPONENT Devel +) + +install(TARGETS KF6Svg EXPORT KF6SvgTargets ${KF_INSTALL_TARGETS_DEFAULT_ARGS}) + +if(BUILD_QCH) + ecm_add_qch( + KF6Svg_QCH + NAME KSvg + BASE_NAME KF6Svg + VERSION ${KF_VERSION} + ORG_DOMAIN org.kde + SOURCES # using only public headers, to cover only public API + ${KSvg_namespaced_HEADERS} + ../../Mainpage.dox + MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" + LINK_QCHS + Qt6Gui_QCH + INCLUDE_DIRS + ${KSvg_BUILD_INCLUDE_DIRS} + BLANK_MACROS + KSVG_EXPORT + KSVG_DEPRECATED + KSVG_DEPRECATED_EXPORT + "KSVG_DEPRECATED_VERSION(x, y, t)" + TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} + QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} + COMPONENT Devel + ) +endif() diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/README b/local/recipes/kde/kf6-ksvg/source/src/ksvg/README new file mode 100644 index 0000000000..12a63647c2 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/README @@ -0,0 +1,22 @@ +KSvg + +This directory contains the classes making up KSvg, which provides rendering api for Svg files, +and support for the themes used in the Plasma Desktop. + +Domain specific sets of functionality, e.g. for network awareness or sensors, +are not found here but as Applet, Wallpaper, +ContainmentActions, Containment and other plugins. + +Commit Guidelines: +* If your patch is not an obvious or trivial bug fix, have it peer reviewed + by another Frameworks developer; https://phabricator.kde.org is your friend :) + +* All code MUST follow the KDE Frameworks coding style, as found at: + https://techbase.kde.org/Policies/Frameworks_Coding_Style + +* All new public API MUST have apidox written before committing and must go + through an API review with another Frameworks developer. We have to maintain + binary compatibility, remember! + +Unit tests are next to godliness. + diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/framesvg.cpp b/local/recipes/kde/kf6-ksvg/source/src/ksvg/framesvg.cpp new file mode 100644 index 0000000000..b80e4ae9be --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/framesvg.cpp @@ -0,0 +1,1043 @@ +/* + SPDX-FileCopyrightText: 2008-2010 Aaron Seigo + SPDX-FileCopyrightText: 2008-2010 Marco Martin + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "framesvg.h" +#include "private/framesvg_p.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "debug_p.h" +#include "imageset.h" +#include "private/framesvg_helpers.h" +#include "private/imageset_p.h" +#include "private/svg_p.h" + +namespace KSvg +{ +QHash>> FrameSvgPrivate::s_sharedFrames; + +// Any attempt to generate a frame whose width or height is larger than this +// will be rejected +static const int MAX_FRAME_SIZE = 100000; + +FrameData::~FrameData() +{ + FrameSvgPrivate::s_sharedFrames[imageSet].remove(cacheId); +} + +FrameSvg::FrameSvg(QObject *parent) + : Svg(parent) + , d(new FrameSvgPrivate(this)) +{ + connect(this, &FrameSvg::repaintNeeded, this, std::bind(&FrameSvgPrivate::updateNeeded, d)); +} + +FrameSvg::~FrameSvg() +{ + delete d; +} + +void FrameSvg::setImagePath(const QString &path) +{ + if (path == imagePath()) { + return; + } + + clearCache(); + + setContainsMultipleImages(true); + Svg::d->setImagePath(path); + if (!d->repaintBlocked) { + d->updateFrameData(Svg::d->lastModified); + } +} + +void FrameSvg::setEnabledBorders(const EnabledBorders borders) +{ + if (borders == d->enabledBorders) { + return; + } + + d->enabledBorders = borders; + + if (!d->repaintBlocked) { + d->updateFrameData(Svg::d->lastModified); + } +} + +FrameSvg::EnabledBorders FrameSvg::enabledBorders() const +{ + return d->enabledBorders; +} + +void FrameSvg::setElementPrefix(KSvg::FrameSvg::LocationPrefix location) +{ + switch (location) { + case TopEdge: + setElementPrefix(QStringLiteral("north")); + break; + case BottomEdge: + setElementPrefix(QStringLiteral("south")); + break; + case LeftEdge: + setElementPrefix(QStringLiteral("west")); + break; + case RightEdge: + setElementPrefix(QStringLiteral("east")); + break; + default: + setElementPrefix(QString()); + break; + } + + d->location = location; +} + +void FrameSvg::setElementPrefix(const QString &prefix) +{ + if (prefix.isEmpty() || !hasElement(prefix % QLatin1String("-center"))) { + d->prefix.clear(); + } else { + d->prefix = prefix; + if (!d->prefix.isEmpty()) { + d->prefix += QLatin1Char('-'); + } + } + d->requestedPrefix = prefix; + + d->location = FrameSvg::Floating; + + if (!d->repaintBlocked) { + d->updateFrameData(Svg::d->lastModified); + } +} + +bool FrameSvg::hasElementPrefix(const QString &prefix) const +{ + // for now it simply checks if a center element exists, + // because it could make sense for certain themes to not have all the elements + if (prefix.isEmpty()) { + return hasElement(QStringLiteral("center")); + } + if (prefix.endsWith(QLatin1Char('-'))) { + return hasElement(prefix % QLatin1String("center")); + } + + return hasElement(prefix % QLatin1String("-center")); +} + +bool FrameSvg::hasElementPrefix(KSvg::FrameSvg::LocationPrefix location) const +{ + switch (location) { + case TopEdge: + return hasElementPrefix(QStringLiteral("north")); + case BottomEdge: + return hasElementPrefix(QStringLiteral("south")); + case LeftEdge: + return hasElementPrefix(QStringLiteral("west")); + case RightEdge: + return hasElementPrefix(QStringLiteral("east")); + default: + return hasElementPrefix(QString()); + } +} + +QString FrameSvg::prefix() +{ + return d->requestedPrefix; +} + +void FrameSvg::resizeFrame(const QSizeF &size) +{ + if (imagePath().isEmpty()) { + return; + } + + if (size.isEmpty()) { +#ifndef NDEBUG + // qCDebug(LOG_KSVG) << "Invalid size" << size; +#endif + return; + } + + if (d->frame && size.toSize() == d->frame->frameSize) { + return; + } + d->pendingFrameSize = size.toSize(); + + if (!d->repaintBlocked) { + d->updateFrameData(Svg::d->lastModified, FrameSvgPrivate::UpdateFrame); + } +} + +QSizeF FrameSvg::frameSize() const +{ + if (!d->frame) { + return QSizeF(-1, -1); + } else { + return d->frameSize(d->frame.data()); + } +} + +qreal FrameSvg::marginSize(const FrameSvg::MarginEdge edge) const +{ + if (!d->frame) { + return .0; + } + + if (d->frame->noBorderPadding) { + return .0; + } + + switch (edge) { + case FrameSvg::TopMargin: + return d->frame->topMargin; + + case FrameSvg::LeftMargin: + return d->frame->leftMargin; + + case FrameSvg::RightMargin: + return d->frame->rightMargin; + + // KSvg::BottomMargin + default: + return d->frame->bottomMargin; + } +} + +qreal FrameSvg::insetSize(const FrameSvg::MarginEdge edge) const +{ + if (!d->frame) { + return .0; + } + + if (d->frame->noBorderPadding) { + return .0; + } + + switch (edge) { + case FrameSvg::TopMargin: + return d->frame->insetTopMargin; + + case FrameSvg::LeftMargin: + return d->frame->insetLeftMargin; + + case FrameSvg::RightMargin: + return d->frame->insetRightMargin; + + // KSvg::BottomMargin + default: + return d->frame->insetBottomMargin; + } +} + +qreal FrameSvg::fixedMarginSize(const FrameSvg::MarginEdge edge) const +{ + if (!d->frame) { + return .0; + } + + if (d->frame->noBorderPadding) { + return .0; + } + + switch (edge) { + case FrameSvg::TopMargin: + return d->frame->fixedTopMargin; + + case FrameSvg::LeftMargin: + return d->frame->fixedLeftMargin; + + case FrameSvg::RightMargin: + return d->frame->fixedRightMargin; + + // KSvg::BottomMargin + default: + return d->frame->fixedBottomMargin; + } +} + +void FrameSvg::getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const +{ + if (!d->frame || d->frame->noBorderPadding) { + left = top = right = bottom = 0; + return; + } + + top = d->frame->topMargin; + left = d->frame->leftMargin; + right = d->frame->rightMargin; + bottom = d->frame->bottomMargin; +} + +void FrameSvg::getFixedMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const +{ + if (!d->frame || d->frame->noBorderPadding) { + left = top = right = bottom = 0; + return; + } + + top = d->frame->fixedTopMargin; + left = d->frame->fixedLeftMargin; + right = d->frame->fixedRightMargin; + bottom = d->frame->fixedBottomMargin; +} + +void FrameSvg::getInset(qreal &left, qreal &top, qreal &right, qreal &bottom) const +{ + if (!d->frame || d->frame->noBorderPadding) { + left = top = right = bottom = 0; + return; + } + + top = d->frame->insetTopMargin; + left = d->frame->insetLeftMargin; + right = d->frame->insetRightMargin; + bottom = d->frame->insetBottomMargin; +} + +QRectF FrameSvg::contentsRect() const +{ + if (d->frame) { + QRectF rect(QPoint(0, 0), d->frame->frameSize); + return rect.adjusted(d->frame->leftMargin, d->frame->topMargin, -d->frame->rightMargin, -d->frame->bottomMargin); + } else { + return QRectF(); + } +} + +QPixmap FrameSvg::alphaMask() const +{ + // FIXME: the distinction between overlay and + return d->alphaMask(); +} + +QRegion FrameSvg::mask() const +{ + QRegion result; + if (!d->frame) { + return result; + } + + size_t id = qHash(d->cacheId(d->frame.data(), QString()), SvgRectsCache::s_seed); + + QRegion *obj = d->frame->cachedMasks.object(id); + + if (!obj) { + QPixmap alphaMask = d->alphaMask(); + const qreal dpr = alphaMask.devicePixelRatio(); + + // region should always be in logical pixels, resize pixmap to be in the logical sizes + if (alphaMask.devicePixelRatio() != 1.0) { + alphaMask = alphaMask.scaled(alphaMask.width() / dpr, alphaMask.height() / dpr); + } + + // mask() of a QPixmap without alpha Channel will be null + // but if our mask has no lpha at all, we want instead consider the entire area as the mask + if (alphaMask.hasAlphaChannel()) { + obj = new QRegion(QBitmap(alphaMask.mask())); + } else { + obj = new QRegion(alphaMask.rect()); + } + + result = *obj; + d->frame->cachedMasks.insert(id, obj); + } else { + result = *obj; + } + return result; +} + +void FrameSvg::setCacheAllRenderedFrames(bool cache) +{ + if (d->cacheAll && !cache) { + clearCache(); + } + + d->cacheAll = cache; +} + +bool FrameSvg::cacheAllRenderedFrames() const +{ + return d->cacheAll; +} + +void FrameSvg::clearCache() +{ + if (d->frame) { + d->frame->cachedBackground = QPixmap(); + d->frame->cachedMasks.clear(); + } + if (d->maskFrame) { + d->maskFrame->cachedBackground = QPixmap(); + d->maskFrame->cachedMasks.clear(); + } +} + +QPixmap FrameSvg::framePixmap() +{ + if (d->frame->cachedBackground.isNull()) { + d->generateBackground(d->frame); + } + + return d->frame->cachedBackground; +} + +void FrameSvg::paintFrame(QPainter *painter, const QRectF &target, const QRectF &source) +{ + if (d->frame->cachedBackground.isNull()) { + d->generateBackground(d->frame); + if (d->frame->cachedBackground.isNull()) { + return; + } + } + + painter->drawPixmap(target, d->frame->cachedBackground, source.isValid() ? source : target); +} + +void FrameSvg::paintFrame(QPainter *painter, const QPointF &pos) +{ + if (d->frame->cachedBackground.isNull()) { + d->generateBackground(d->frame); + if (d->frame->cachedBackground.isNull()) { + return; + } + } + + painter->drawPixmap(pos, d->frame->cachedBackground); +} + +int FrameSvg::minimumDrawingHeight() +{ + if (d->frame) { + return d->frame->fixedTopHeight + d->frame->fixedBottomHeight; + } + return 0; +} + +int FrameSvg::minimumDrawingWidth() +{ + if (d->frame) { + return d->frame->fixedRightWidth + d->frame->fixedLeftWidth; + } + return 0; +} + +//#define DEBUG_FRAMESVG_CACHE +FrameSvgPrivate::~FrameSvgPrivate() = default; + +QPixmap FrameSvgPrivate::alphaMask() +{ + QString maskPrefix; + + if (q->hasElement(QLatin1String("mask-") % prefix % QLatin1String("center"))) { + maskPrefix = QStringLiteral("mask-"); + } + + if (maskPrefix.isNull()) { + if (frame->cachedBackground.isNull()) { + generateBackground(frame); + } + return frame->cachedBackground; + } + + // We are setting the prefix only temporary to generate + // the needed mask image + const QString maskRequestedPrefix = requestedPrefix.isEmpty() ? QStringLiteral("mask") : maskPrefix % requestedPrefix; + maskPrefix = maskPrefix % prefix; + + if (!maskFrame) { + maskFrame = lookupOrCreateMaskFrame(frame, maskPrefix, maskRequestedPrefix); + if (!maskFrame->cachedBackground.isNull()) { + return maskFrame->cachedBackground; + } + updateSizes(maskFrame); + generateBackground(maskFrame); + return maskFrame->cachedBackground; + } + + const bool shouldUpdate = (maskFrame->enabledBorders != frame->enabledBorders // + || maskFrame->frameSize != frameSize(frame.data()) // + || maskFrame->imagePath != frame->imagePath); + if (shouldUpdate) { + maskFrame = lookupOrCreateMaskFrame(frame, maskPrefix, maskRequestedPrefix); + if (!maskFrame->cachedBackground.isNull()) { + return maskFrame->cachedBackground; + } + updateSizes(maskFrame); + } + + if (maskFrame->cachedBackground.isNull()) { + generateBackground(maskFrame); + } + + return maskFrame->cachedBackground; +} + +QSharedPointer +FrameSvgPrivate::lookupOrCreateMaskFrame(const QSharedPointer &frame, const QString &maskPrefix, const QString &maskRequestedPrefix) +{ + const size_t key = qHash(cacheId(frame.data(), maskPrefix)); + QSharedPointer mask = s_sharedFrames[q->imageSet()->d].value(key); + + // See if we can find a suitable candidate in the shared frames. + // If there is one, use it. + if (mask) { + return mask; + } + + mask.reset(new FrameData(*frame.data())); + mask->prefix = maskPrefix; + mask->requestedPrefix = maskRequestedPrefix; + mask->imageSet = q->imageSet()->d; + mask->imagePath = frame->imagePath; + mask->enabledBorders = frame->enabledBorders; + mask->frameSize = frameSize(frame).toSize(); + mask->cacheId = key; + mask->lastModified = frame->lastModified; + s_sharedFrames[q->imageSet()->d].insert(key, mask); + + return mask; +} + +void FrameSvgPrivate::generateBackground(const QSharedPointer &frame) +{ + if (!frame->cachedBackground.isNull() || !q->hasElementPrefix(frame->prefix)) { + return; + } + + const size_t id = qHash(cacheId(frame.data(), frame->prefix)); + + bool frameCached = !frame->cachedBackground.isNull(); + bool overlayCached = false; + + const bool overlayAvailable = !frame->prefix.startsWith(QLatin1String("mask-")) && q->hasElement(frame->prefix % QLatin1String("overlay")); + QPixmap overlay; + if (q->isUsingRenderingCache()) { + frameCached = q->imageSet()->d->findInCache(QString::number(id), frame->cachedBackground, frame->lastModified) && !frame->cachedBackground.isNull(); + if (frameCached) { + frame->cachedBackground.setDevicePixelRatio(q->devicePixelRatio()); + } + + if (overlayAvailable) { + const size_t overlayId = qHash(cacheId(frame.data(), frame->prefix % QLatin1String("overlay"))); + overlayCached = q->imageSet()->d->findInCache(QString::number(overlayId), overlay, frame->lastModified) && !overlay.isNull(); + if (overlayCached) { + overlay.setDevicePixelRatio(q->devicePixelRatio()); + } + } + } + + if (!frameCached) { + generateFrameBackground(frame); + } + + // Overlays + QSizeF overlaySize; + QPointF actualOverlayPos = QPointF(0, 0); + if (overlayAvailable && !overlayCached) { + overlaySize = q->elementSize(frame->prefix % QLatin1String("overlay")).toSize(); + + if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-pos-right"))) { + actualOverlayPos.setX(frame->frameSize.width() - overlaySize.width()); + } else if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-pos-bottom"))) { + actualOverlayPos.setY(frame->frameSize.height() - overlaySize.height()); + // Stretched or Tiled? + } else if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-stretch"))) { + overlaySize = frameSize(frame).toSize(); + } else { + if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-tile-horizontal"))) { + overlaySize.setWidth(frameSize(frame).width()); + } + if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-tile-vertical"))) { + overlaySize.setHeight(frameSize(frame).height()); + } + } + + overlay = alphaMask(); + QPainter overlayPainter(&overlay); + overlayPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); + // Tiling? + if (q->hasElement(frame->prefix % QLatin1String("hint-overlay-tile-horizontal")) + || q->hasElement(frame->prefix % QLatin1String("hint-overlay-tile-vertical"))) { + QSizeF s = q->size().toSize(); + q->resize(q->elementSize(frame->prefix % QLatin1String("overlay"))); + + overlayPainter.drawTiledPixmap(QRectF(QPointF(0, 0), overlaySize), q->pixmap(frame->prefix % QLatin1String("overlay"))); + q->resize(s); + } else { + q->paint(&overlayPainter, QRectF(actualOverlayPos, overlaySize), frame->prefix % QLatin1String("overlay")); + } + + overlayPainter.end(); + } + + if (!frameCached) { + cacheFrame(frame->prefix, frame->cachedBackground, overlayCached ? overlay : QPixmap()); + } + + if (!overlay.isNull()) { + QPainter p(&frame->cachedBackground); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + p.drawPixmap(actualOverlayPos, overlay, QRectF(actualOverlayPos, overlaySize)); + } +} + +void FrameSvgPrivate::generateFrameBackground(const QSharedPointer &frame) +{ + // qCDebug(LOG_KSVG) << "generating background"; + const QSizeF size = frameSize(frame) * q->devicePixelRatio(); + + if (!size.isValid()) { +#ifndef NDEBUG + // qCDebug(LOG_KSVG) << "Invalid frame size" << size; +#endif + return; + } + if (size.width() >= MAX_FRAME_SIZE || size.height() >= MAX_FRAME_SIZE) { + qCWarning(LOG_KSVG) << "Not generating frame background for a size whose width or height is more than" << MAX_FRAME_SIZE << size; + return; + } + + // Don't cut away pieces of the frame + frame->cachedBackground = QPixmap(QSize(std::ceil(size.width()), std::ceil(size.height()))); + frame->cachedBackground.fill(Qt::transparent); + QPainter p(&frame->cachedBackground); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.setRenderHint(QPainter::SmoothPixmapTransform); + + QRectF contentRect = contentGeometry(frame, size); + paintCenter(p, frame, contentRect, size); + + paintCorner(p, frame, FrameSvg::LeftBorder | FrameSvg::TopBorder, contentRect); + paintCorner(p, frame, FrameSvg::RightBorder | FrameSvg::TopBorder, contentRect); + paintCorner(p, frame, FrameSvg::LeftBorder | FrameSvg::BottomBorder, contentRect); + paintCorner(p, frame, FrameSvg::RightBorder | FrameSvg::BottomBorder, contentRect); + + // Sides + const qreal leftHeight = q->elementSize(frame->prefix % QLatin1String("left")).height(); + paintBorder(p, frame, FrameSvg::LeftBorder, QSizeF(frame->leftWidth, leftHeight) * q->devicePixelRatio(), contentRect); + const qreal rightHeight = q->elementSize(frame->prefix % QLatin1String("right")).height(); + paintBorder(p, frame, FrameSvg::RightBorder, QSizeF(frame->rightWidth, rightHeight) * q->devicePixelRatio(), contentRect); + + const qreal topWidth = q->elementSize(frame->prefix % QLatin1String("top")).width(); + paintBorder(p, frame, FrameSvg::TopBorder, QSizeF(topWidth, frame->topHeight) * q->devicePixelRatio(), contentRect); + const qreal bottomWidth = q->elementSize(frame->prefix % QLatin1String("bottom")).width(); + paintBorder(p, frame, FrameSvg::BottomBorder, QSizeF(bottomWidth, frame->bottomHeight) * q->devicePixelRatio(), contentRect); + p.end(); + + // Set the devicePixelRatio only at the end, drawing all happened in device pixels + frame->cachedBackground.setDevicePixelRatio(q->devicePixelRatio()); +} + +QRectF FrameSvgPrivate::contentGeometry(const QSharedPointer &frame, const QSizeF &size) const +{ + const QSizeF contentSize(size.width() - frame->leftWidth * q->devicePixelRatio() - frame->rightWidth * q->devicePixelRatio(), + size.height() - frame->topHeight * q->devicePixelRatio() - frame->bottomHeight * q->devicePixelRatio()); + QRectF contentRect(QPointF(0, 0), contentSize); + if (frame->enabledBorders & FrameSvg::LeftBorder && q->hasElement(frame->prefix % QLatin1String("left"))) { + contentRect.translate(frame->leftWidth * q->devicePixelRatio(), 0); + } + + // Corners + if (frame->enabledBorders & FrameSvg::TopBorder && q->hasElement(frame->prefix % QLatin1String("top"))) { + contentRect.translate(0, frame->topHeight * q->devicePixelRatio()); + } + return contentRect; +} + +void FrameSvgPrivate::updateFrameData(uint lastModified, UpdateType updateType) +{ + auto fd = frame; + uint newKey = 0; + + if (fd) { + const uint oldKey = fd->cacheId; + + const QString oldPath = fd->imagePath; + const FrameSvg::EnabledBorders oldBorders = fd->enabledBorders; + const QSizeF currentSize = fd->frameSize; + + fd->enabledBorders = enabledBorders; + fd->frameSize = pendingFrameSize; + fd->imagePath = q->imagePath(); + + newKey = qHash(cacheId(fd.data(), prefix)); + + // reset frame to old values + fd->enabledBorders = oldBorders; + fd->frameSize = currentSize; + fd->imagePath = oldPath; + + // FIXME: something more efficient than string comparison? + if (oldKey == newKey) { + return; + } + + // qCDebug(LOG_KSVG) << "looking for" << newKey; + auto newFd = FrameSvgPrivate::s_sharedFrames[q->imageSet()->d].value(newKey); + if (newFd) { + // qCDebug(LOG_KSVG) << "FOUND IT!" << newFd->refcount; + // we've found a match, use that one + Q_ASSERT(newKey == newFd.lock()->cacheId); + frame = newFd; + return; + } + + fd.reset(new FrameData(*fd)); + } else { + fd.reset(new FrameData(q, QString())); + } + + frame = fd; + fd->prefix = prefix; + fd->requestedPrefix = requestedPrefix; + // updateSizes(); + fd->enabledBorders = enabledBorders; + fd->frameSize = pendingFrameSize; + fd->imagePath = q->imagePath(); + fd->lastModified = lastModified; + // was fd just created empty now? + if (newKey == 0) { + newKey = qHash(cacheId(fd.data(), prefix)); + } + + // we know it isn't in s_sharedFrames due to the check above, so insert it now + FrameSvgPrivate::s_sharedFrames[q->imageSet()->d].insert(newKey, fd); + fd->cacheId = newKey; + fd->imageSet = q->imageSet()->d; + if (updateType == UpdateFrameAndMargins) { + updateAndSignalSizes(); + } else { + updateSizes(frame); + } +} + +void FrameSvgPrivate::paintCenter(QPainter &p, const QSharedPointer &frame, const QRectF &contentRect, const QSizeF &fullSize) +{ + // fullSize and contentRect are in device pixels + if (!contentRect.isEmpty()) { + const QString centerElementId = frame->prefix % QLatin1String("center"); + if (frame->tileCenter) { + QSizeF centerTileSize = q->elementSize(centerElementId); + QPixmap center(centerTileSize.toSize()); + center.fill(Qt::transparent); + + QPainter centerPainter(¢er); + centerPainter.setCompositionMode(QPainter::CompositionMode_Source); + q->paint(¢erPainter, QRectF(QPointF(0, 0), centerTileSize), centerElementId); + + if (frame->composeOverBorder) { + p.drawTiledPixmap(QRectF(QPointF(0, 0), fullSize), center); + } else { + p.drawTiledPixmap(FrameSvgHelpers::sectionRect(FrameSvg::NoBorder, contentRect, fullSize * q->devicePixelRatio()), center); + } + } else { + if (frame->composeOverBorder) { + q->paint(&p, QRectF(QPointF(0, 0), fullSize), centerElementId); + } else { + q->paint(&p, FrameSvgHelpers::sectionRect(FrameSvg::NoBorder, contentRect, fullSize * q->devicePixelRatio()), centerElementId); + } + } + } + + if (frame->composeOverBorder) { + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); + p.drawPixmap(QRectF(QPointF(0, 0), fullSize), alphaMask(), QRectF(QPointF(0, 0), alphaMask().size())); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + } +} + +void FrameSvgPrivate::paintBorder(QPainter &p, + const QSharedPointer &frame, + const FrameSvg::EnabledBorders borders, + const QSizeF &size, + const QRectF &contentRect) const +{ + // size and contentRect are in device pixels + QString side = frame->prefix % FrameSvgHelpers::borderToElementId(borders); + if (frame->enabledBorders & borders && q->hasElement(side) && !size.isEmpty()) { + if (frame->stretchBorders) { + q->paint(&p, FrameSvgHelpers::sectionRect(borders, contentRect, frame->frameSize * q->devicePixelRatio()), side); + } else { + QSize grownSize(std::ceil(size.width()), std::ceil(size.height())); + QPixmap px(grownSize); + // QPixmap px(QSize(std::ceil(size.width()), std::ceil(size.height()))); + px.fill(Qt::transparent); + + QPainter sidePainter(&px); + sidePainter.setCompositionMode(QPainter::CompositionMode_Source); + // A QRect as we have to exactly fill a QPixmap of integer size, prefer going slightly outside it to not have empty edges in the pixmap to tile + q->paint(&sidePainter, QRect(QPoint(0, 0), grownSize), side); + + // We are composing QPixmaps here, so all objects with integer size + // Rounding the position and ceiling the size is the way that gives better tiled results + auto r = FrameSvgHelpers::sectionRect(borders, contentRect, frame->frameSize * q->devicePixelRatio()); + r.setTopLeft(r.topLeft().toPoint()); + r.setSize(QSizeF(std::ceil(r.size().width()), std::ceil(r.size().height()))); + + p.drawTiledPixmap(r, px); + } + } +} + +void FrameSvgPrivate::paintCorner(QPainter &p, const QSharedPointer &frame, KSvg::FrameSvg::EnabledBorders border, const QRectF &contentRect) const +{ + // contentRect is in device pixels + // Draw the corner only if both borders in both directions are enabled. + if ((frame->enabledBorders & border) != border) { + return; + } + const QString corner = frame->prefix % FrameSvgHelpers::borderToElementId(border); + if (q->hasElement(corner)) { + auto r = FrameSvgHelpers::sectionRect(border, contentRect, frame->frameSize * q->devicePixelRatio()); + // We are composing QPixmaps here, so all objects with integer size + // Rounding the position and ceiling the size is the way that gives better tiled results + r.setTopLeft(r.topLeft().toPoint()); + r.setSize(QSizeF(std::ceil(r.size().width()), std::ceil(r.size().height()))); + q->paint(&p, r.toRect(), corner); + } +} + +SvgPrivate::CacheId FrameSvgPrivate::cacheId(FrameData *frame, const QString &prefixToSave) const +{ + const QSize size = frameSize(frame).toSize(); + return SvgPrivate::CacheId{double(size.width()), + double(size.height()), + frame->imagePath, + prefixToSave, + q->status(), + q->devicePixelRatio(), + q->colorSet(), + (uint)frame->enabledBorders, + 0, + q->Svg::d->lastModified}; +} + +void FrameSvgPrivate::cacheFrame(const QString &prefixToSave, const QPixmap &background, const QPixmap &overlay) +{ + if (!q->isUsingRenderingCache()) { + return; + } + + // insert background + if (!frame) { + return; + } + + const size_t id = qHash(cacheId(frame.data(), prefixToSave)); + + // qCDebug(LOG_KSVG)<<"Saving to cache frame"<imageSet()->d->insertIntoCache(QString::number(id), background, QString::number((qint64)q, 16) % prefixToSave); + + if (!overlay.isNull()) { + // insert overlay + const size_t overlayId = qHash(cacheId(frame.data(), frame->prefix % QLatin1String("overlay"))); + q->imageSet()->d->insertIntoCache(QString::number(overlayId), overlay, QString::number((qint64)q, 16) % prefixToSave % QLatin1String("overlay")); + } +} + +void FrameSvgPrivate::updateSizes(FrameData *frame) const +{ + // qCDebug(LOG_KSVG) << "!!!!!!!!!!!!!!!!!!!!!! updating sizes" << prefix; + Q_ASSERT(frame); + + QSizeF s = q->size(); + q->resize(); + if (!frame->cachedBackground.isNull()) { + frame->cachedBackground = QPixmap(); + } + + // This function needs to do a lot of string creation, since we have four + // sides with matching margins and insets. Rather than creating a new string + // every time for these, create a single buffer that can contain a full + // element name and pass that around using views, so we save a lot of + // allocations. + QString nameBuffer; + const auto offset = frame->prefix.length(); + nameBuffer.reserve(offset + 30); + nameBuffer.append(frame->prefix); + + // This uses UTF16 literals to avoid having to create QLatin1String and then + // converting that to a QString temporary for the replace operation. + // Additionally, we use a template parameter to provide us the compile-time + // length of the literal so we don't need to calculate that. + auto createName = [&nameBuffer, offset](const char16_t(&name)[length]) { + nameBuffer.replace(offset, length - 1, reinterpret_cast(name), length); + return QStringView(nameBuffer).mid(0, offset + length - 1); + }; + + // This has the same size regardless the border is enabled or not + frame->fixedTopHeight = q->elementSize(createName(u"top")).height(); + + if (auto topMargin = q->elementRect(createName(u"hint-top-margin")); topMargin.isValid()) { + frame->fixedTopMargin = topMargin.height(); + } else { + frame->fixedTopMargin = frame->fixedTopHeight; + } + + // The same, but its size depends from the margin being enabled + if (frame->enabledBorders & FrameSvg::TopBorder) { + frame->topMargin = frame->fixedTopMargin; + frame->topHeight = frame->fixedTopHeight; + } else { + frame->topMargin = frame->topHeight = 0; + } + + if (auto topInset = q->elementRect(createName(u"hint-top-inset")); topInset.isValid()) { + frame->insetTopMargin = topInset.height(); + } else { + frame->insetTopMargin = -1; + } + + frame->fixedLeftWidth = q->elementSize(createName(u"left")).width(); + + if (auto leftMargin = q->elementRect(createName(u"hint-left-margin")); leftMargin.isValid()) { + frame->fixedLeftMargin = leftMargin.width(); + } else { + frame->fixedLeftMargin = frame->fixedLeftWidth; + } + + if (frame->enabledBorders & FrameSvg::LeftBorder) { + frame->leftMargin = frame->fixedLeftMargin; + frame->leftWidth = frame->fixedLeftWidth; + } else { + frame->leftMargin = frame->leftWidth = 0; + } + + if (auto leftInset = q->elementRect(createName(u"hint-left-inset")); leftInset.isValid()) { + frame->insetLeftMargin = leftInset.width(); + } else { + frame->insetLeftMargin = -1; + } + + frame->fixedRightWidth = q->elementSize(createName(u"right")).width(); + + if (auto rightMargin = q->elementRect(createName(u"hint-right-margin")); rightMargin.isValid()) { + frame->fixedRightMargin = rightMargin.width(); + } else { + frame->fixedRightMargin = frame->fixedRightWidth; + } + + if (frame->enabledBorders & FrameSvg::RightBorder) { + frame->rightMargin = frame->fixedRightMargin; + frame->rightWidth = frame->fixedRightWidth; + } else { + frame->rightMargin = frame->rightWidth = 0; + } + + if (auto rightInset = q->elementRect(createName(u"hint-right-inset")); rightInset.isValid()) { + frame->insetRightMargin = rightInset.width(); + } else { + frame->insetRightMargin = -1; + } + + frame->fixedBottomHeight = q->elementSize(createName(u"bottom")).height(); + + if (auto bottomMargin = q->elementRect(createName(u"hint-bottom-margin")); bottomMargin.isValid()) { + frame->fixedBottomMargin = bottomMargin.height(); + } else { + frame->fixedBottomMargin = frame->fixedBottomHeight; + } + + if (frame->enabledBorders & FrameSvg::BottomBorder) { + frame->bottomMargin = frame->fixedBottomMargin; + frame->bottomHeight = frame->fixedBottomHeight; + } else { + frame->bottomMargin = frame->bottomHeight = 0; + } + + if (auto bottomInset = q->elementRect(createName(u"hint-bottom-inset")); bottomInset.isValid()) { + frame->insetBottomMargin = bottomInset.height(); + } else { + frame->insetBottomMargin = -1; + } + + static const QString maskPrefix = QStringLiteral("mask-"); + static const QString hintTileCenter = QStringLiteral("hint-tile-center"); + static const QString hintNoBorderPadding = QStringLiteral("hint-no-border-padding"); + static const QString hintStretchBorders = QStringLiteral("hint-stretch-borders"); + + frame->composeOverBorder = (q->hasElement(createName(u"hint-compose-over-border")) && q->hasElement(maskPrefix % createName(u"center"))); + + // since it's rectangular, topWidth and bottomWidth must be the same + // the ones that don't have a frame->prefix is for retrocompatibility + frame->tileCenter = (q->hasElement(hintTileCenter) || q->hasElement(createName(u"hint-tile-center"))); + frame->noBorderPadding = (q->hasElement(hintNoBorderPadding) || q->hasElement(createName(u"hint-no-border-padding"))); + frame->stretchBorders = (q->hasElement(hintStretchBorders) || q->hasElement(createName(u"hint-stretch-borders"))); + q->resize(s); +} + +void FrameSvgPrivate::updateNeeded() +{ + q->setElementPrefix(requestedPrefix); + // frame not created yet? + if (!frame) { + return; + } + q->clearCache(); + updateSizes(frame); +} + +void FrameSvgPrivate::updateAndSignalSizes() +{ + // frame not created yet? + if (!frame) { + return; + } + updateSizes(frame); + Q_EMIT q->repaintNeeded(); +} + +QSizeF FrameSvgPrivate::frameSize(FrameData *frame) const +{ + if (!frame) { + return QSizeF(); + } + + if (!frame->frameSize.isValid()) { + updateSizes(frame); + frame->frameSize = q->size().toSize(); + } + + return frame->frameSize; +} + +QString FrameSvg::actualPrefix() const +{ + return d->prefix; +} + +bool FrameSvg::isRepaintBlocked() const +{ + return d->repaintBlocked; +} + +void FrameSvg::setRepaintBlocked(bool blocked) +{ + d->repaintBlocked = blocked; + + if (!blocked) { + d->updateFrameData(Svg::d->lastModified); + } +} + +} // KSvg namespace + +#include "moc_framesvg.cpp" diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/framesvg.h b/local/recipes/kde/kf6-ksvg/source/src/ksvg/framesvg.h new file mode 100644 index 0000000000..26107d03a7 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/framesvg.h @@ -0,0 +1,420 @@ +/* + SPDX-FileCopyrightText: 2008 Aaron Seigo + SPDX-FileCopyrightText: 2008 Marco Martin + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KSVG_FRAMESVG_H +#define KSVG_FRAMESVG_H + +#include +#include + +#include + +#include + +class QPainter; +class QPoint; +class QPointF; +class QRect; +class QRectF; +class QSize; +class QSizeF; +class QMatrix; + +namespace KSvg +{ +class FrameSvgPrivate; + +/** + * @class FrameSvg ksvg/framesvg.h + * + * @short Provides an SVG with borders. + * + * When using SVG images for a background of an object that may change + * its aspect ratio, such as a dialog, simply scaling a single image + * may not be enough. + * + * FrameSvg allows SVGs to provide several elements for borders as well + * as a central element, each of which are scaled individually. These elements + * should be named: + * * @c center - the central element, which will be scaled in both directions + * * @c top - the top border; the height is fixed, but it will be scaled + * horizontally to the same width as @c center + * * @c bottom - the bottom border; scaled in the same way as @c top + * * @c left - the left border; the width is fixed, but it will be scaled + * vertically to the same height as @c center + * * @c right - the right border; scaled in the same way as @c left + * * @c topleft - fixed size; must be the same height as @c top and the same + * width as @c left + * * @c bottomleft, @c topright, @c bottomright - similar to @c topleft + * + * @c center must exist, but all the others are optional. @c topleft and + * @c topright will be ignored if @c top does not exist, and similarly for + * @c bottomleft and @c bottomright. + * + * @see KSvg::Svg + **/ +class KSVG_EXPORT FrameSvg : public Svg +{ + Q_OBJECT + + Q_PROPERTY(EnabledBorders enabledBorders READ enabledBorders WRITE setEnabledBorders) + +public: + /** + * @brief This flag enum specifies which borders should be drawn. + */ + enum EnabledBorder { + NoBorder = 0, + TopBorder = 1, + BottomBorder = 2, + LeftBorder = 4, + RightBorder = 8, + AllBorders = TopBorder | BottomBorder | LeftBorder | RightBorder, + }; + Q_DECLARE_FLAGS(EnabledBorders, EnabledBorder) + Q_FLAG(EnabledBorders) + + // TODO: merge those two? + enum LocationPrefix { + Floating = 0, /**< Free floating.*/ + TopEdge, /**< Along the top of the screen*/ + BottomEdge, /**< Along the bottom of the screen*/ + LeftEdge, /**< Along the left side of the screen */ + RightEdge, /**< Along the right side of the screen */ + }; + Q_ENUM(LocationPrefix) + + enum MarginEdge { + TopMargin = 0, /**< The top margin **/ + BottomMargin, /**< The bottom margin **/ + LeftMargin, /**< The left margin **/ + RightMargin, /**< The right margin **/ + }; + Q_ENUM(MarginEdge) + + /** + * Constructs a new FrameSvg that paints the proper named subelements + * as borders. It may also be used as a regular KSvg::Svg object + * for direct access to elements in the Svg. + * + * @param parent options QObject to parent this to + * + * @related KSvg::Theme + */ + explicit FrameSvg(QObject *parent = nullptr); + ~FrameSvg() override; + + /** + * Loads a new Svg + * @param imagePath the new file + */ + Q_INVOKABLE void setImagePath(const QString &path) override; + + /** + * @brief This method sets which borders should be painted. + * @param flags borders we want to paint + * + * @see ::EnabledBorder + * @param borders + */ + void setEnabledBorders(const EnabledBorders borders); + + /** + * @brief This is a convenience method to get the enabled borders. + * @return what borders are painted + */ + EnabledBorders enabledBorders() const; + + /** + * @brief This method resizes the frame, maintaining the same border size. + * @param size the new size of the frame + */ + Q_INVOKABLE void resizeFrame(const QSizeF &size); + + /** + * @returns the size of the frame + */ + Q_INVOKABLE QSizeF frameSize() const; + + /** + * + * @brief This method returns the margin size for the given edge. + * + * Note that @c 0 will be returned if the given margin is disabled. + * + * If you don't care about the margin being on or off, use + * ::fixedMarginSize() instead. + * + * @param edge the margin edge we want, top, bottom, left or right + * @return the margin size + */ + Q_INVOKABLE qreal marginSize(const FrameSvg::MarginEdge edge) const; + + /** + * @brief This is a convenience method that extracts the size of the four + * margins and saves their size into the passed variables. + * + * If you don't care about the margins being on or off, use + * ::getFixedMargins() instead. + * + * @param left left margin size + * @param top top margin size + * @param right right margin size + * @param bottom bottom margin size + */ + Q_INVOKABLE void getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const; + + /** + * @brief This method returns the margin size for the specified edge. + * + * Compared to ::marginSize(), this does not depend on whether the margin is + * enabled or not. + * + * @param edge the margin edge we want, top, bottom, left or right + * @return the margin size + */ + Q_INVOKABLE qreal fixedMarginSize(const FrameSvg::MarginEdge edge) const; + + /** + * @brief This is a convenience method that extracts the size of the four + * margins and saves their size into the passed variables. + * + * Compared to ::getMargins(), this doesn't depend on whether the margins are + * enabled or not. + * + * @param left left margin size + * @param top top margin size + * @param right right margin size + * @param bottom bottom margin size + */ + Q_INVOKABLE void getFixedMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const; + + /** + * @brief This method returns the insets margin size for the specified edge. + * @param edge the margin edge we want, top, bottom, left or right + * @return the margin size + * @since 5.77 + */ + Q_INVOKABLE qreal insetSize(const FrameSvg::MarginEdge edge) const; + + /** + * @brief This is a convenience method that extracts the size of the four + * inset margins and saves their size into the passed variables. + * + * @param left left margin size + * @param top top margin size + * @param right right margin size + * @param bottom bottom margin size + * @since 5.77 + */ + Q_INVOKABLE void getInset(qreal &left, qreal &top, qreal &right, qreal &bottom) const; + + /** + * @brief This method returns the rectangle of the center element, taking + * the margins into account. + */ + Q_INVOKABLE QRectF contentsRect() const; + + /** + * @brief This method sets the prefix (@see setElementPrefix) to 'north', + * 'south', 'west' and 'east' when the location is TopEdge, BottomEdge, + * LeftEdge and RightEdge, respectively. Clears the prefix in other cases. + * + * The prefix must exist in the SVG document, which means that this can only + * be called successfully after setImagePath is called. + * + * @param location location in the UI this frame will be drawn + */ + Q_INVOKABLE void setElementPrefix(KSvg::FrameSvg::LocationPrefix location); + + /** + * @brief This method sets the prefix for the SVG elements to be used for + * painting. + * + * For example, if prefix is 'active', then instead of using the 'top' + * element of the SVG file to paint the top border, the 'active-top' element + * will be used. The same goes for other SVG elements. + * + * If the elements with prefixes are not present, the default ones are used. + * (for the sake of speed, the test is present only for the 'center' element) + * + * Setting the prefix manually resets the location to Floating. + * + * The prefix must exist in the SVG document, which means that this can only be + * called successfully after setImagePath is called. + * + * @param prefix prefix for the SVG elements that make up the frame + */ + Q_INVOKABLE void setElementPrefix(const QString &prefix); + + /** + * @brief This method returns whether the SVG has the necessary elements + * with the given prefix to draw a frame. + * + * @param prefix the given prefix we want to check if drawable (can have trailing '-' since 5.59) + */ + Q_INVOKABLE bool hasElementPrefix(const QString &prefix) const; + + /** + * @brief This is an overloaded method provided for convenience that is + * equivalent to hasElementPrefix("north"), hasElementPrefix("south") + * hasElementPrefix("west") and hasElementPrefix("east"). + * + * @return true if the svg has the necessary elements with the given prefix + * to draw a frame. + * + * @param location the given prefix we want to check if drawable + */ + Q_INVOKABLE bool hasElementPrefix(KSvg::FrameSvg::LocationPrefix location) const; + + /** + * @brief This method returns the prefix for SVG elements of the FrameSvg + * (including a '-' at the end if not empty). + * + * @return the prefix + * @see actualPrefix() + */ + Q_INVOKABLE QString prefix(); + + /** + * @brief This method returns a mask that tightly contains the fully opaque + * areas of the SVG. + * + * @return a region of opaque areas + */ + Q_INVOKABLE QRegion mask() const; + + /** + * @brief This method returns a pixmap whose alpha channel is the opacity of + * the frame. It may be the frame itself or a special frame with the + * "mask-" prefix. + */ + QPixmap alphaMask() const; + + /** + * @brief This method sets whether saving all the rendered prefixes in a + * cache or not. + * + * @param cache whether to use the cache. + */ + Q_INVOKABLE void setCacheAllRenderedFrames(bool cache); + + /** + * @brief This method returns whether all the different prefixes should be + * kept in a cache when rendered. + */ + Q_INVOKABLE bool cacheAllRenderedFrames() const; + + /** + * @brief This method deletes the internal cache. + * + * Calling this method frees memeory. Use this if you want to switch the + * rendered element and you don't plan to switch back to the previous one + * for a long time. + * + * This only works if setUsingRenderingCache(@c true) has been called. + * + * @see KSvg::Svg::setUsingRenderingCache() + */ + Q_INVOKABLE void clearCache(); + + /** + * @brief This method returns a pixmap of the SVG represented by this + * object. + * + * @param elementId the ID string of the element to render, or an empty + * string for the whole SVG (the default). + * + * @return a QPixmap of the rendered SVG + */ + Q_INVOKABLE QPixmap framePixmap(); + + /** + * @brief This method paints the loaded SVG with the elements that + * represents the border. + * + * @param painter the QPainter to use + * @param target the target rectangle on the paint device + * @param source the portion rectangle of the source image + */ + Q_INVOKABLE void paintFrame(QPainter *painter, const QRectF &target, const QRectF &source = QRectF()); + + /** + * @brief This method paints the loaded SVG with the elements that + * represents the border. + * + * This is an overloaded member provided for convenience + * + * @param painter the QPainter to use + * @param pos where to paint the svg + */ + Q_INVOKABLE void paintFrame(QPainter *painter, const QPointF &pos = QPointF(0, 0)); + + /** + * @brief This method returns the prefix that is actually being used + * (including a '-' at the end if not empty). + * + * @see ::prefix() + */ + QString actualPrefix() const; + + /** + * @brief This method returns whether we are in a transaction of many + * changes at once. + * + * This is used to restrict rebuilding generated graphics for each change + * made. + * + * @since 5.31 + */ + bool isRepaintBlocked() const; + + /** + * @brief This method sets whether we should block rebuilding generated + * graphics for each change made. + * + * Setting this to @c true will block rebuilding the generated graphics for + * each change made and will do these changes in blocks instead. + * + * How to use this method: + * When making several changes at once to the frame properties--such as + * prefix, enabled borders, and size--set this property to true to avoid + * regenerating the graphics for each change. Set it to false again after + * applying all required changes. + * + * Note that any change will not be visible in the painted frame while this + * property is set to true. + * @since 5.31 + */ + void setRepaintBlocked(bool blocked); + + /** + * @brief This method returns the minimum height required to correctly draw + * this SVG. + * + * @since 5.101 + */ + Q_INVOKABLE int minimumDrawingHeight(); + + /** + * @brief This method returns the minimum width required to correctly draw + * this SVG. + * + * @since 5.101 + */ + Q_INVOKABLE int minimumDrawingWidth(); + +private: + FrameSvgPrivate *const d; + friend class FrameData; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(FrameSvg::EnabledBorders) + +} // KSvg namespace + +#endif // multiple inclusion guard diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/imageset.cpp b/local/recipes/kde/kf6-ksvg/source/src/ksvg/imageset.cpp new file mode 100644 index 0000000000..903550ced0 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/imageset.cpp @@ -0,0 +1,263 @@ +/* + SPDX-FileCopyrightText: 2006-2007 Aaron Seigo + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "imageset.h" +#include "private/imageset_p.h" +#include "private/svg_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "debug_p.h" + +namespace KSvg +{ +ImageSet::ImageSet(QObject *parent) + : QObject(parent) +{ + if (!ImageSetPrivate::globalImageSet) { + ImageSetPrivate::globalImageSet = new ImageSetPrivate; + if (QCoreApplication::instance()) { + connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, ImageSetPrivate::globalImageSet, &ImageSetPrivate::onAppExitCleanup); + } + } + ImageSetPrivate::globalImageSet->ref.ref(); + d = ImageSetPrivate::globalImageSet; + + connect(d, &ImageSetPrivate::imageSetChanged, this, &ImageSet::imageSetChanged); +} + +ImageSet::ImageSet(const QString &imageSetName, const QString &basePath, QObject *parent) + : QObject(parent) +{ + auto &priv = ImageSetPrivate::themes[imageSetName]; + if (!priv) { + priv = new ImageSetPrivate; + if (QCoreApplication::instance()) { + connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, priv, &ImageSetPrivate::onAppExitCleanup); + } + } + + priv->ref.ref(); + d = priv; + + // turn off caching so we don't accidentally trigger unnecessary disk activity at this point + bool useCache = d->cacheImageSet; + d->cacheImageSet = false; + if (!basePath.isEmpty()) { + d->basePath = basePath; + if (!d->basePath.endsWith(QDir::separator())) { + d->basePath += QDir::separator(); + } + } + d->setImageSetName(imageSetName, false); + d->cacheImageSet = useCache; + d->fixedName = true; + connect(d, &ImageSetPrivate::imageSetChanged, this, &ImageSet::imageSetChanged); +} + +ImageSet::~ImageSet() +{ + if (d == ImageSetPrivate::globalImageSet) { + if (!d->ref.deref()) { + disconnect(ImageSetPrivate::globalImageSet, nullptr, this, nullptr); + delete ImageSetPrivate::globalImageSet; + ImageSetPrivate::globalImageSet = nullptr; + d = nullptr; + } + } else { + if (!d->ref.deref()) { + delete ImageSetPrivate::themes.take(d->imageSetName); + } + } +} + +void ImageSet::setBasePath(const QString &basePath) +{ + if (d->basePath == basePath) { + return; + } + + d->basePath = basePath; + if (!d->basePath.endsWith(QDir::separator())) { + d->basePath += QDir::separator(); + } + + // Don't use scheduleImageSetChangeNotification as we want things happening immediately there, + // we don't want in the client code to be setting things like the svg size right after thing just to + // be reset right after in an async fashion + d->discardCache(PixmapCache | SvgElementsCache); + d->cachesToDiscard = NoCache; + + Q_EMIT basePathChanged(basePath); + Q_EMIT imageSetChanged(d->imageSetName); +} + +QString ImageSet::basePath() const +{ + return d->basePath; +} + +void ImageSet::setSelectors(const QStringList &selectors) +{ + d->selectors = selectors; + d->scheduleImageSetChangeNotification(PixmapCache | SvgElementsCache); +} + +QStringList ImageSet::selectors() const +{ + return d->selectors; +} + +void ImageSet::setImageSetName(const QString &imageSetName) +{ + if (d->imageSetName == imageSetName) { + return; + } + + if (d != ImageSetPrivate::globalImageSet) { + disconnect(QCoreApplication::instance(), nullptr, d, nullptr); + if (!d->ref.deref()) { + delete ImageSetPrivate::themes.take(d->imageSetName); + } + + auto &priv = ImageSetPrivate::themes[imageSetName]; + if (!priv) { + priv = new ImageSetPrivate; + if (QCoreApplication::instance()) { + connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, priv, &ImageSetPrivate::onAppExitCleanup); + } + } + priv->ref.ref(); + d = priv; + connect(d, &ImageSetPrivate::imageSetChanged, this, &ImageSet::imageSetChanged); + } + + d->setImageSetName(imageSetName, true); +} + +QString ImageSet::imageSetName() const +{ + return d->imageSetName; +} + +QString ImageSet::imagePath(const QString &name) const +{ + // look for a compressed svg file in the theme + if (name.contains(QLatin1String("../")) || name.isEmpty()) { + // we don't support relative paths + // qCDebug(LOG_KSVG) << "ImageSet says: bad image path " << name; + return QString(); + } + + const QString svgzName = name % QLatin1String(".svgz"); + QString path = d->findInImageSet(svgzName, d->imageSetName); + + if (path.isEmpty()) { + // try for an uncompressed svg file + const QString svgName = name % QLatin1String(".svg"); + path = d->findInImageSet(svgName, d->imageSetName); + + // search in fallback themes if necessary + for (int i = 0; path.isEmpty() && i < d->fallbackImageSets.count(); ++i) { + if (d->imageSetName == d->fallbackImageSets[i]) { + continue; + } + + // try a compressed svg file in the fallback theme + path = d->findInImageSet(svgzName, d->fallbackImageSets[i]); + + if (path.isEmpty()) { + // try an uncompressed svg file in the fallback theme + path = d->findInImageSet(svgName, d->fallbackImageSets[i]); + } + } + } + + return path; +} + +QString ImageSet::filePath(const QString &name) const +{ + // look for a compressed svg file in the theme + if (name.contains(QLatin1String("../")) || name.isEmpty()) { + // we don't support relative paths + // qCDebug(LOG_KSVG) << "ImageSet says: bad image path " << name; + return QString(); + } + + QString path = d->findInImageSet(name, d->imageSetName); + + if (path.isEmpty()) { + // search in fallback themes if necessary + for (int i = 0; path.isEmpty() && i < d->fallbackImageSets.count(); ++i) { + if (d->imageSetName == d->fallbackImageSets[i]) { + continue; + } + + path = d->findInImageSet(name, d->fallbackImageSets[i]); + } + } + + return path; +} + +bool ImageSet::currentImageSetHasImage(const QString &name) const +{ + if (name.contains(QLatin1String("../"))) { + // we don't support relative paths + return false; + } + + QString path = d->findInImageSet(name % QLatin1String(".svgz"), d->imageSetName); + if (path.isEmpty()) { + path = d->findInImageSet(name % QLatin1String(".svg"), d->imageSetName); + } + return path.contains(d->basePath % d->imageSetName); +} + +void ImageSet::setUseGlobalSettings(bool useGlobal) +{ + if (d->useGlobal == useGlobal) { + return; + } + + d->useGlobal = useGlobal; + d->cfg = KConfigGroup(); + d->imageSetName.clear(); +} + +bool ImageSet::useGlobalSettings() const +{ + return d->useGlobal; +} + +void ImageSet::setCacheLimit(int kbytes) +{ + d->cacheSize = kbytes; + delete d->pixmapCache; + d->pixmapCache = nullptr; +} + +KPluginMetaData ImageSet::metadata() const +{ + return d->pluginMetaData; +} + +} + +#include "moc_imageset.cpp" diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/imageset.h b/local/recipes/kde/kf6-ksvg/source/src/ksvg/imageset.h new file mode 100644 index 0000000000..cb36ce204b --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/imageset.h @@ -0,0 +1,209 @@ +/* + SPDX-FileCopyrightText: 2006-2007 Aaron Seigo + SPDX-FileCopyrightText: 2013 Marco Martin + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KSVG_IMAGESET_H +#define KSVG_IMAGESET_H + +#include +#include + +#include +#include + +class KPluginMetaData; + +namespace KSvg +{ +class ImageSetPrivate; +class SvgPrivate; + +// TODO: move in the plasma part the watching and regeneration of icon themes + +/** + * @class ImageSet ksvg/imageset.h + * + * @short Interface to the Svg image set + * + * + * KSvg::ImageSet provides access to a common and standardized set of graphic + * elements stored in SVG format. This allows artists to create single packages + * of SVGs that will affect the look and feel of all workspace components. + * + * KSvg::Svg uses KSvg::ImageSet internally to locate and load the appropriate + * SVG data. Alternatively, KSvg::ImageSet can be used directly to retrieve + * file system paths to SVGs by name. + */ +class KSVG_EXPORT ImageSet : public QObject +{ + Q_OBJECT + + Q_PROPERTY(QString imageSetName READ imageSetName WRITE setImageSetName NOTIFY imageSetChanged) + Q_PROPERTY(QString basePath READ basePath WRITE setBasePath NOTIFY imageSetChanged) + Q_PROPERTY(bool useGlobalSettings READ useGlobalSettings NOTIFY imageSetChanged) + +public: + /** + * Default constructor. + * @param parent the parent object + */ + explicit ImageSet(QObject *parent = nullptr); + + /** + * @brief This method constructs a theme which will be a custom theme + * instance of imageSetName. + * + * @param imageSetName the name of the theme to create + * @param basePath base path for the theme to look for svgs. if empty, the default will be used. + * @param parent the parent object + */ + explicit ImageSet(const QString &imageSetName, const QString &basePath = {}, QObject *parent = nullptr); + + ~ImageSet() override; + + /** + * @brief This method sets a base path for the theme to look for SVGs. + * + * It can be a path relative to QStandardPaths::GenericDataLocation or an + * absolute path. + * + * @param basePath the base path + */ + void setBasePath(const QString &basePath); + + /** + * @brief This method returns the base path of the theme where the SVGs will + * be looked for. + */ + QString basePath() const; + + /** + * @brief This method sets the file selectors. + * + * The theme can have different svgs with the same name for different + * situations and platforms. The Plasma desktop for instance uses "opaque" + * or "translucent" based on presence of compositing and KWin blur effects. + * Other uses may be platform, like android-specific graphics. + * + * @param selectors selectors in order of preference + */ + void setSelectors(const QStringList &selectors); + + /** + * @brief This method returns the current selectors in order of preference. + */ + QStringList selectors() const; + + /** + * @brief This method sets the current theme. + */ + void setImageSetName(const QString &imageSetName); + + /** + * @brief This method returns the name of the current theme. + */ + QString imageSetName() const; + + /** + * @brief This method returns the path for an SVG image in the current + * theme. + * + * @param name the name of the file in the theme directory (without the + * ".svg" part or a leading slash). + * + * @return the full path to the requested file for the current theme + */ + QString imagePath(const QString &name) const; + + /** + * @brief This method returns the path for a generic file in the current + * theme. + * + * The theme can also ship any generic file, such as configuration files. + * + * @param name the name of the file in the theme directory (without a + * leading slash) + * + * @return the full path to the requested file for the current theme + */ + QString filePath(const QString &name) const; + + /** + * @brief This method checks whether this theme contains an image with the + * given name. + * + * @param name the name of the file in the theme directory (without the + * ".svg" part or a leading slash) + * + * @return true if the image exists for this theme + */ + bool currentImageSetHasImage(const QString &name) const; + + /** + * @brief This method sets whether the theme should follow the global + * settings or use application-specific settings. + * + * @param useGlobal pass in true to follow the global settings + */ + void setUseGlobalSettings(bool useGlobal); + + /** + * @brief This method returns whether the global settings are followed. + * + * If application-specific settings are being used, it returns @c false. + */ + bool useGlobalSettings() const; + + /** + * @brief This method sets the maximum size of the cache (in kilobytes). + * + * If cache gets bigger than the limit, then some entries are removed. + * Setting cache limit to 0 disables automatic cache size limiting. + * + * Note that the cleanup might not be done immediately, so the cache might + * temporarily (for a few seconds) grow bigger than the limit. + **/ + void setCacheLimit(int kbytes); + + /** + * @brief This method returns the plugin metadata for this theme. + * + * Metadata contains information such as name, description, author, website, + * and url. + */ + KPluginMetaData metadata() const; + +Q_SIGNALS: + /** + * @brif This signal is emitted when the user makes changes to the theme. + * + * Rendered images, colors, etc. should be updated at this point. However, + * SVGs should *not* be repainted in response to this signal; connect to + * Svg::repaintNeeded() instead for that, as SVG objects need repainting not + * only when imageSetChanged() is emitted; moreover SVG objects connect to + * and respond appropriately to imageSetChanged() internally, emitting + * Svg::repaintNeeded() at an appropriate time. + */ + void imageSetChanged(const QString &basePath); + + /** + * @brief This signal is emitted when the user changes the base path of the + * image set. + */ + void basePathChanged(const QString &basePath); + +private: + friend class SvgPrivate; + friend class Svg; + friend class FrameSvg; + friend class FrameSvgPrivate; + friend class ImageSetPrivate; + ImageSetPrivate *d; +}; + +} // KSvg namespace + +#endif // multiple inclusion guard diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/framesvg_helpers.h b/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/framesvg_helpers.h new file mode 100644 index 0000000000..95cd6ba8b7 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/framesvg_helpers.h @@ -0,0 +1,83 @@ +/* + SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KSVG_FRAMESVG_HELPERS_H +#define KSVG_FRAMESVG_HELPERS_H + +#include "framesvg.h" + +namespace KSvg +{ +namespace FrameSvgHelpers +{ +/** + * @returns the element id name for said @p borders + */ +QString borderToElementId(FrameSvg::EnabledBorders borders) +{ + if (borders == FrameSvg::NoBorder) { + return QStringLiteral("center"); + } else if (borders == FrameSvg::TopBorder) { + return QStringLiteral("top"); + } else if (borders == FrameSvg::BottomBorder) { + return QStringLiteral("bottom"); + } else if (borders == FrameSvg::LeftBorder) { + return QStringLiteral("left"); + } else if (borders == FrameSvg::RightBorder) { + return QStringLiteral("right"); + } else if (borders == (FrameSvg::TopBorder | FrameSvg::LeftBorder)) { + return QStringLiteral("topleft"); + } else if (borders == (FrameSvg::TopBorder | FrameSvg::RightBorder)) { + return QStringLiteral("topright"); + } else if (borders == (FrameSvg::BottomBorder | FrameSvg::LeftBorder)) { + return QStringLiteral("bottomleft"); + } else if (borders == (FrameSvg::BottomBorder | FrameSvg::RightBorder)) { + return QStringLiteral("bottomright"); + } else { + qWarning() << "unrecognized border" << borders; + } + return QString(); +} + +/** + * @returns the suggested geometry for the @p borders given a @p fullSize frame size and a @p contentRect + */ +QRectF sectionRect(KSvg::FrameSvg::EnabledBorders borders, const QRectF &contentRect, const QSizeF &fullSize) +{ + // don't use QRect corner methods here, they have semantics that might come as unexpected. + // prefer constructing the points explicitly. e.g. from QRect::topRight docs: + // Note that for historical reasons this function returns QPoint(left() + width() -1, top()). + + if (borders == FrameSvg::NoBorder) { + return contentRect; + } else if (borders == FrameSvg::TopBorder) { + return QRectF(QPointF(contentRect.left(), 0), QSizeF(contentRect.width(), contentRect.top())); + } else if (borders == FrameSvg::BottomBorder) { + return QRectF(QPointF(contentRect.left(), contentRect.bottom()), QSizeF(contentRect.width(), fullSize.height() - contentRect.bottom())); + } else if (borders == FrameSvg::LeftBorder) { + return QRectF(QPointF(0, contentRect.top()), QSizeF(contentRect.left(), contentRect.height())); + } else if (borders == FrameSvg::RightBorder) { + return QRectF(QPointF(contentRect.right(), contentRect.top()), QSizeF(fullSize.width() - contentRect.right(), contentRect.height())); + } else if (borders == (FrameSvg::TopBorder | FrameSvg::LeftBorder)) { + return QRectF(QPointF(0, 0), QSizeF(contentRect.left(), contentRect.top())); + } else if (borders == (FrameSvg::TopBorder | FrameSvg::RightBorder)) { + return QRectF(QPointF(contentRect.right(), 0), QSizeF(fullSize.width() - contentRect.right(), contentRect.top())); + } else if (borders == (FrameSvg::BottomBorder | FrameSvg::LeftBorder)) { + return QRectF(QPointF(0, contentRect.bottom()), QSizeF(contentRect.left(), fullSize.height() - contentRect.bottom())); + } else if (borders == (FrameSvg::BottomBorder | FrameSvg::RightBorder)) { + return QRectF(QPointF(contentRect.right(), contentRect.bottom()), + QSizeF(fullSize.width() - contentRect.right(), fullSize.height() - contentRect.bottom())); + } else { + qWarning() << "unrecognized border" << borders; + } + return QRectF(); +} + +} + +} + +#endif diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/framesvg_p.h b/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/framesvg_p.h new file mode 100644 index 0000000000..463b2ee45b --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/framesvg_p.h @@ -0,0 +1,202 @@ +/* + SPDX-FileCopyrightText: 2008 Aaron Seigo + SPDX-FileCopyrightText: 2009 Marco Martin + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KSVG_FRAMESVG_P_H +#define KSVG_FRAMESVG_P_H + +#include +#include +#include + +#include + +#include + +#include "framesvg.h" +#include "svg_p.h" + +namespace KSvg +{ +class FrameData +{ +public: + FrameData(FrameSvg *svg, const QString &p) + : imagePath(svg->imagePath()) + , prefix(p) + , enabledBorders(FrameSvg::AllBorders) + , frameSize(-1, -1) + , topHeight(0) + , leftWidth(0) + , rightWidth(0) + , bottomHeight(0) + , topMargin(0) + , leftMargin(0) + , rightMargin(0) + , bottomMargin(0) + , noBorderPadding(false) + , stretchBorders(false) + , tileCenter(false) + , composeOverBorder(false) + , imageSet(nullptr) + { + } + + FrameData(const FrameData &other) + : imagePath(other.imagePath) + , prefix(other.prefix) + , enabledBorders(other.enabledBorders) + , cachedMasks(MAX_CACHED_MASKS) + , frameSize(other.frameSize) + , topHeight(0) + , leftWidth(0) + , rightWidth(0) + , bottomHeight(0) + , topMargin(0) + , leftMargin(0) + , rightMargin(0) + , bottomMargin(0) + , noBorderPadding(false) + , stretchBorders(false) + , tileCenter(false) + , composeOverBorder(false) + , imageSet(nullptr) + { + } + + ~FrameData(); + + QString imagePath; + QString prefix; + QString requestedPrefix; + FrameSvg::EnabledBorders enabledBorders; + QPixmap cachedBackground; + QCache cachedMasks; + static const int MAX_CACHED_MASKS = 10; + uint lastModified = 0; + + // Those sizes are in logical pixels + QSizeF frameSize; + uint cacheId; + + // measures + qreal topHeight; + qreal leftWidth; + qreal rightWidth; + qreal bottomHeight; + + // margins, are equal to the measures by default + qreal topMargin; + qreal leftMargin; + qreal rightMargin; + qreal bottomMargin; + + // measures + qreal fixedTopHeight; + qreal fixedLeftWidth; + qreal fixedRightWidth; + qreal fixedBottomHeight; + + // margins, are equal to the measures by default + qreal fixedTopMargin; + qreal fixedLeftMargin; + qreal fixedRightMargin; + qreal fixedBottomMargin; + + // margins, we only have the hqreal for insets + qreal insetTopMargin; + qreal insetLeftMargin; + qreal insetRightMargin; + qreal insetBottomMargin; + + // size of the svg where the size of the "center" + // element is contentWidth x contentHeight + bool noBorderPadding : 1; + bool stretchBorders : 1; + bool tileCenter : 1; + bool composeOverBorder : 1; + + KSvg::ImageSetPrivate *imageSet; +}; + +class FrameSvgPrivate +{ +public: + FrameSvgPrivate(FrameSvg *psvg) + : q(psvg) + , overlayPos(0, 0) + , enabledBorders(FrameSvg::AllBorders) + , cacheAll(false) + , repaintBlocked(false) + { + } + + ~FrameSvgPrivate(); + + QPixmap alphaMask(); + + enum UpdateType { + UpdateFrame, + UpdateFrameAndMargins, + }; + + void generateBackground(const QSharedPointer &frame); + void generateFrameBackground(const QSharedPointer &); + SvgPrivate::CacheId cacheId(FrameData *frame, const QString &prefixToUse) const; + void cacheFrame(const QString &prefixToSave, const QPixmap &background, const QPixmap &overlay); + void updateSizes(FrameData *frame) const; + void updateSizes(const QSharedPointer &frame) const + { + return updateSizes(frame.data()); + } + void updateNeeded(); + void updateAndSignalSizes(); + QSizeF frameSize(const QSharedPointer &frame) const + { + return frameSize(frame.data()); + } + QSizeF frameSize(FrameData *frame) const; + + // paintBorder, paintCorder and paintCenter sizes are in device pixels + void paintBorder(QPainter &p, + const QSharedPointer &frame, + KSvg::FrameSvg::EnabledBorders border, + const QSizeF &originalSize, + const QRectF &output) const; + void paintCorner(QPainter &p, const QSharedPointer &frame, KSvg::FrameSvg::EnabledBorders border, const QRectF &output) const; + void paintCenter(QPainter &p, const QSharedPointer &frame, const QRectF &contentRect, const QSizeF &fullSize); + + QRectF contentGeometry(const QSharedPointer &frame, const QSizeF &size) const; + void updateFrameData(uint lastModified, UpdateType updateType = UpdateFrameAndMargins); + QSharedPointer lookupOrCreateMaskFrame(const QSharedPointer &frame, const QString &maskPrefix, const QString &maskRequestedPrefix); + + FrameSvg::LocationPrefix location = FrameSvg::Floating; + QString prefix; + // sometimes the prefix we requested is not available, so prefix will be empty + // keep track of the requested one anyways, we'll try again when the theme changes + QString requestedPrefix; + + FrameSvg *const q; + + QPointF overlayPos; + + QSharedPointer frame; + QSharedPointer maskFrame; + + // those can differ from frame->enabledBorders if we are in a transition + FrameSvg::EnabledBorders enabledBorders; + // this can differ from frame->frameSize if we are in a transition + QSizeF pendingFrameSize; + + static QHash>> s_sharedFrames; + + bool cacheAll : 1; + bool repaintBlocked : 1; +}; + +} + +#endif diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/imageset_p.cpp b/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/imageset_p.cpp new file mode 100644 index 0000000000..cdc7a143b3 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/imageset_p.cpp @@ -0,0 +1,774 @@ +/* + SPDX-FileCopyrightText: 2006-2007 Aaron Seigo + SPDX-FileCopyrightText: 2013 Marco Martin + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "imageset_p.h" +#include "debug_p.h" +#include "framesvg.h" +#include "framesvg_p.h" +#include "imageset.h" +#include "svg_p.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if defined(Q_OS_LINUX) +#include +#endif + +#define DEFAULT_CACHE_SIZE 16384 // value is from the old kconfigxt default value + +namespace KSvg +{ +const char ImageSetPrivate::defaultImageSet[] = "default"; + +ImageSetPrivate *ImageSetPrivate::globalImageSet = nullptr; +QHash ImageSetPrivate::themes = QHash(); +using QSP = QStandardPaths; + +KSharedConfig::Ptr configForImageSet(const QString &basePath, const QString &theme) +{ + const QString baseName = basePath % theme; + QString configPath = QSP::locate(QSP::GenericDataLocation, baseName + QLatin1String("/config")); + if (!configPath.isEmpty()) { + return KSharedConfig::openConfig(configPath, KConfig::SimpleConfig); + } + QString metadataPath = QSP::locate(QSP::GenericDataLocation, baseName + QLatin1String("/metadata.desktop")); + return KSharedConfig::openConfig(metadataPath, KConfig::SimpleConfig); +} + +KPluginMetaData metaDataForImageSet(const QString &basePath, const QString &theme) +{ + QString packageBasePath = basePath % theme; + QDir dir; + if (!dir.exists(packageBasePath)) { + packageBasePath = QSP::locate(QSP::GenericDataLocation, basePath % theme, QSP::LocateDirectory); + } + if (packageBasePath.isEmpty()) { + qWarning(LOG_KSVG) << "Could not locate KSvg image set" << theme << "in" << basePath << "using search path" + << QSP::standardLocations(QSP::GenericDataLocation); + return {}; + } + if (QFileInfo::exists(packageBasePath + QLatin1String("/metadata.json"))) { + return KPluginMetaData::fromJsonFile(packageBasePath + QLatin1String("/metadata.json")); + } else if (QFileInfo::exists(packageBasePath + QLatin1String("/metadata.desktop"))) { + QString metadataPath = packageBasePath + QLatin1String("/metadata.desktop"); + KConfigGroup cg(KSharedConfig::openConfig(packageBasePath + QLatin1String("/metadata.desktop"), KConfig::SimpleConfig), + QStringLiteral("Desktop Entry")); + QJsonObject obj = {}; + for (const QString &key : cg.keyList()) { + obj[key] = cg.readEntry(key); + } + qWarning(LOG_KSVG) << "The theme" << theme << "uses the legacy metadata.desktop. Consider contacting the author and asking them update it to use the newer JSON format."; + return KPluginMetaData(obj, packageBasePath + QLatin1String("/metadata.desktop")); + } else { + qCWarning(LOG_KSVG) << "Could not locate metadata for theme" << theme; + return {}; + } +} + +ImageSetPrivate::ImageSetPrivate(QObject *parent) + : QObject(parent) + , colorScheme(QPalette::Active, KColorScheme::Window, KSharedConfigPtr(nullptr)) + , selectionColorScheme(QPalette::Active, KColorScheme::Selection, KSharedConfigPtr(nullptr)) + , buttonColorScheme(QPalette::Active, KColorScheme::Button, KSharedConfigPtr(nullptr)) + , viewColorScheme(QPalette::Active, KColorScheme::View, KSharedConfigPtr(nullptr)) + , complementaryColorScheme(QPalette::Active, KColorScheme::Complementary, KSharedConfigPtr(nullptr)) + , headerColorScheme(QPalette::Active, KColorScheme::Header, KSharedConfigPtr(nullptr)) + , tooltipColorScheme(QPalette::Active, KColorScheme::Tooltip, KSharedConfigPtr(nullptr)) + , pixmapCache(nullptr) + , cacheSize(DEFAULT_CACHE_SIZE) + , cachesToDiscard(NoCache) + , isDefault(true) + , useGlobal(true) + , cacheImageSet(true) + , fixedName(false) + , apiMajor(1) + , apiMinor(0) + , apiRevision(0) +{ + const QString org = QCoreApplication::organizationName(); + if (!org.isEmpty()) { + basePath += u'/' + org; + } + const QString appName = QCoreApplication::applicationName(); + if (!appName.isEmpty()) { + basePath += u'/' + appName; + } + if (basePath.isEmpty()) { + basePath = QStringLiteral("ksvg"); + } + basePath += u"/svgtheme/"; + pixmapSaveTimer = new QTimer(this); + pixmapSaveTimer->setSingleShot(true); + pixmapSaveTimer->setInterval(600); + QObject::connect(pixmapSaveTimer, &QTimer::timeout, this, &ImageSetPrivate::scheduledCacheUpdate); + + updateNotificationTimer = new QTimer(this); + updateNotificationTimer->setSingleShot(true); + updateNotificationTimer->setInterval(100); + QObject::connect(updateNotificationTimer, &QTimer::timeout, this, &ImageSetPrivate::notifyOfChanged); + + QCoreApplication::instance()->installEventFilter(this); + + #if defined(Q_OS_LINUX) + struct sysinfo x; + if (sysinfo(&x) == 0) { + bootTime = QDateTime::currentSecsSinceEpoch() - x.uptime; + qCDebug(LOG_KSVG) << "ImageSetPrivate: Using boot time value" << bootTime; + } else { + // Should never happen, but just in case, fallback to a sane value + bootTime = QDateTime::currentSecsSinceEpoch(); + qCWarning(LOG_KSVG) << "ImageSetPrivate: Failed to get uptime from sysinfo. Using current time as boot time" << bootTime; + } + #endif +} + +ImageSetPrivate::~ImageSetPrivate() +{ + FrameSvgPrivate::s_sharedFrames.remove(this); + delete pixmapCache; +} + +bool ImageSetPrivate::useCache() +{ + bool cachesTooOld = false; + + if (cacheImageSet && !pixmapCache) { + if (cacheSize == 0) { + cacheSize = DEFAULT_CACHE_SIZE; + } + QString cacheFile = QLatin1String("plasma_theme_") + imageSetName; + + // clear any cached values from the previous theme cache + themeVersion.clear(); + + if (!themeMetadataPath.isEmpty()) { + KDirWatch::self()->removeFile(themeMetadataPath); + } + + themeMetadataPath = configForImageSet(basePath, imageSetName)->name(); + const QString cacheFileBase = cacheFile + QLatin1String("*.kcache"); + + QString currentCacheFileName; + if (!themeMetadataPath.isEmpty()) { + // now we record the theme version, if we can + const KPluginMetaData data = metaDataForImageSet(basePath, imageSetName); + if (data.isValid()) { + themeVersion = data.version(); + } + if (!themeVersion.isEmpty()) { + cacheFile += QLatin1String("_v") + themeVersion; + currentCacheFileName = cacheFile + QLatin1String(".kcache"); + } + } + + // now we check for, and remove if necessary, old caches + QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation)); + cacheDir.setNameFilters(QStringList({cacheFileBase})); + + const auto files = cacheDir.entryInfoList(); + for (const QFileInfo &file : files) { + if (currentCacheFileName.isEmpty() // + || !file.absoluteFilePath().endsWith(currentCacheFileName)) { + QFile::remove(file.absoluteFilePath()); + } + } + + // now we do a sanity check: if the metadata.desktop file is newer than the cache, drop the cache + if (!themeMetadataPath.isEmpty()) { + // now we check to see if the theme metadata file itself is newer than the pixmap cache + // this is done before creating the pixmapCache object since that can change the mtime + // on the cache file + + // FIXME: when using the system colors, if they change while the application is not running + // the cache should be dropped; we need a way to detect system color change when the + // application is not running. + // check for expired cache + const QString cacheFilePath = + QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1Char('/') + cacheFile + QLatin1String(".kcache"); + if (!cacheFilePath.isEmpty()) { + const QFileInfo cacheFileInfo(cacheFilePath); + const QFileInfo metadataFileInfo(themeMetadataPath); + const QFileInfo iconImageSetMetadataFileInfo(iconImageSetMetadataPath); + + cachesTooOld = (cacheFileInfo.lastModified().toSecsSinceEpoch() < metadataFileInfo.lastModified().toSecsSinceEpoch()) + || (cacheFileInfo.lastModified().toSecsSinceEpoch() < iconImageSetMetadataFileInfo.lastModified().toSecsSinceEpoch()); + } + } + + pixmapCache = new KImageCache(cacheFile, cacheSize * 1024); + pixmapCache->setEvictionPolicy(KSharedDataCache::EvictLeastRecentlyUsed); + + if (cachesTooOld) { + discardCache(PixmapCache | SvgElementsCache); + } + } + + return cacheImageSet; +} + +void ImageSetPrivate::onAppExitCleanup() +{ + pixmapsToCache.clear(); + delete pixmapCache; + pixmapCache = nullptr; + cacheImageSet = false; +} + +QString ImageSetPrivate::imagePath(const QString &theme, const QString &type, const QString &image) +{ + QString subdir = basePath % theme % type % image; + + if (QFileInfo::exists(subdir)) { + return subdir; + } else { + return QStandardPaths::locate(QStandardPaths::GenericDataLocation, subdir); + } +} + +QString ImageSetPrivate::findInImageSet(const QString &image, const QString &theme, bool cache) +{ + if (cache) { + auto it = discoveries.constFind(image); + if (it != discoveries.constEnd()) { + return it.value(); + } + } + + QString search; + + // TODO: use also QFileSelector::allSelectors? + // TODO: check if the theme supports selectors starting with + + for (const QString &type : std::as_const(selectors)) { + search = imagePath(theme, QLatin1Char('/') % type % QLatin1Char('/'), image); + if (!search.isEmpty()) { + break; + } + } + + // not found in selectors + if (search.isEmpty()) { + search = imagePath(theme, QStringLiteral("/"), image); + } + + if (cache && !search.isEmpty()) { + discoveries.insert(image, search); + } + + return search; +} + +void ImageSetPrivate::discardCache(CacheTypes caches) +{ + if (caches & PixmapCache) { + pixmapsToCache.clear(); + pixmapSaveTimer->stop(); + if (pixmapCache) { + pixmapCache->clear(); + } + } else { + // This deletes the object but keeps the on-disk cache for later use + delete pixmapCache; + pixmapCache = nullptr; + } + + cachedSvgStyleSheets.clear(); + cachedSelectedSvgStyleSheets.clear(); + cachedInactiveSvgStyleSheets.clear(); + + if (caches & SvgElementsCache) { + discoveries.clear(); + } +} + +void ImageSetPrivate::scheduledCacheUpdate() +{ + if (useCache()) { + QHashIterator it(pixmapsToCache); + while (it.hasNext()) { + it.next(); + pixmapCache->insertPixmap(idsToCache[it.key()], it.value()); + } + } + + pixmapsToCache.clear(); + keysToCache.clear(); + idsToCache.clear(); +} + +void ImageSetPrivate::colorsChanged() +{ + // in the case the theme follows the desktop settings, refetch the colorschemes + // and discard the svg pixmap cache + if (!colors) { + KSharedConfig::openConfig()->reparseConfiguration(); + } + colorScheme = KColorScheme(QPalette::Active, KColorScheme::Window, colors); + buttonColorScheme = KColorScheme(QPalette::Active, KColorScheme::Button, colors); + viewColorScheme = KColorScheme(QPalette::Active, KColorScheme::View, colors); + selectionColorScheme = KColorScheme(QPalette::Active, KColorScheme::Selection, colors); + complementaryColorScheme = KColorScheme(QPalette::Active, KColorScheme::Complementary, colors); + headerColorScheme = KColorScheme(QPalette::Active, KColorScheme::Header, colors); + tooltipColorScheme = KColorScheme(QPalette::Active, KColorScheme::Tooltip, colors); + scheduleImageSetChangeNotification(PixmapCache | SvgElementsCache); + Q_EMIT applicationPaletteChange(); +} + +void ImageSetPrivate::scheduleImageSetChangeNotification(CacheTypes caches) +{ + cachesToDiscard |= caches; + updateNotificationTimer->start(); +} + +void ImageSetPrivate::notifyOfChanged() +{ + // qCDebug(LOG_KSVG) << cachesToDiscard; + discardCache(cachesToDiscard); + cachesToDiscard = NoCache; + Q_EMIT imageSetChanged(imageSetName); +} + +QColor ImageSetPrivate::namedColor(Svg::StyleSheetColor colorName, const KSvg::Svg *svg) +{ + const KSvg::Svg::Status status = svg->status(); + KColorScheme *currentScheme = nullptr; + + switch (KColorScheme::ColorSet(svg->colorSet())) { + case KColorScheme::Button: + currentScheme = &buttonColorScheme; + break; + case KColorScheme::View: + currentScheme = &viewColorScheme; + break; + case KColorScheme::Complementary: + currentScheme = &complementaryColorScheme; + break; + case KColorScheme::Header: + currentScheme = &headerColorScheme; + break; + case KColorScheme::Tooltip: + currentScheme = &tooltipColorScheme; + break; + default: + currentScheme = &colorScheme; + } + + switch (colorName) { + case Svg::Text: + switch (status) { + case Svg::Status::Selected: + return selectionColorScheme.foreground(KColorScheme::NormalText).color(); + case Svg::Status::Inactive: + return currentScheme->foreground(KColorScheme::InactiveText).color(); + default: + return currentScheme->foreground(KColorScheme::NormalText).color(); + } + case Svg::Background: + if (status == Svg::Status::Selected) { + return selectionColorScheme.background(KColorScheme::NormalBackground).color(); + } else { + return colorScheme.background(KColorScheme::NormalBackground).color(); + } + case Svg::Highlight: + return selectionColorScheme.background(KColorScheme::NormalBackground).color(); + case Svg::HighlightedText: + return selectionColorScheme.foreground(KColorScheme::NormalText).color(); + case Svg::PositiveText: + return currentScheme->foreground(KColorScheme::PositiveText).color(); + case Svg::NeutralText: + return currentScheme->foreground(KColorScheme::NeutralText).color(); + case Svg::NegativeText: + return currentScheme->foreground(KColorScheme::NegativeText).color(); + + case Svg::ButtonText: + if (status == Svg::Status::Selected) { + return selectionColorScheme.foreground(KColorScheme::NormalText).color(); + } else { + return buttonColorScheme.foreground(KColorScheme::NormalText).color(); + } + case Svg::ButtonBackground: + if (status == Svg::Status::Selected) { + return selectionColorScheme.background(KColorScheme::NormalBackground).color(); + } else { + return buttonColorScheme.background(KColorScheme::NormalBackground).color(); + } + case Svg::ButtonHover: + return buttonColorScheme.decoration(KColorScheme::HoverColor).color(); + case Svg::ButtonFocus: + return buttonColorScheme.decoration(KColorScheme::FocusColor).color(); + case Svg::ButtonHighlightedText: + return selectionColorScheme.foreground(KColorScheme::NormalText).color(); + case Svg::ButtonPositiveText: + return buttonColorScheme.foreground(KColorScheme::PositiveText).color(); + case Svg::ButtonNeutralText: + return buttonColorScheme.foreground(KColorScheme::NeutralText).color(); + case Svg::ButtonNegativeText: + return buttonColorScheme.foreground(KColorScheme::NegativeText).color(); + + case Svg::ViewText: + if (status == Svg::Status::Selected) { + return selectionColorScheme.foreground(KColorScheme::NormalText).color(); + } else { + return viewColorScheme.foreground(KColorScheme::NormalText).color(); + } + case Svg::ViewBackground: + if (status == Svg::Status::Selected) { + return selectionColorScheme.background(KColorScheme::NormalBackground).color(); + } else { + return viewColorScheme.background(KColorScheme::NormalBackground).color(); + } + case Svg::ViewHover: + return viewColorScheme.decoration(KColorScheme::HoverColor).color(); + case Svg::ViewFocus: + return viewColorScheme.decoration(KColorScheme::FocusColor).color(); + case Svg::ViewHighlightedText: + return selectionColorScheme.foreground(KColorScheme::NormalText).color(); + case Svg::ViewPositiveText: + return viewColorScheme.foreground(KColorScheme::PositiveText).color(); + case Svg::ViewNeutralText: + return viewColorScheme.foreground(KColorScheme::NeutralText).color(); + case Svg::ViewNegativeText: + return viewColorScheme.foreground(KColorScheme::NegativeText).color(); + + case Svg::TooltipText: + if (status == Svg::Status::Selected) { + return selectionColorScheme.foreground(KColorScheme::NormalText).color(); + } else { + return tooltipColorScheme.foreground(KColorScheme::NormalText).color(); + } + case Svg::TooltipBackground: + if (status == Svg::Status::Selected) { + return selectionColorScheme.background(KColorScheme::NormalBackground).color(); + } else { + return tooltipColorScheme.background(KColorScheme::NormalBackground).color(); + } + case Svg::TooltipHover: + return tooltipColorScheme.decoration(KColorScheme::HoverColor).color(); + case Svg::TooltipFocus: + return tooltipColorScheme.decoration(KColorScheme::FocusColor).color(); + case Svg::TooltipHighlightedText: + return selectionColorScheme.foreground(KColorScheme::NormalText).color(); + case Svg::TooltipPositiveText: + return tooltipColorScheme.foreground(KColorScheme::PositiveText).color(); + case Svg::TooltipNeutralText: + return tooltipColorScheme.foreground(KColorScheme::NeutralText).color(); + case Svg::TooltipNegativeText: + return tooltipColorScheme.foreground(KColorScheme::NegativeText).color(); + + case Svg::ComplementaryText: + if (status == Svg::Status::Selected) { + return selectionColorScheme.foreground(KColorScheme::NormalText).color(); + } else { + return complementaryColorScheme.foreground(KColorScheme::NormalText).color(); + } + case Svg::ComplementaryBackground: + if (status == Svg::Status::Selected) { + return selectionColorScheme.background(KColorScheme::NormalBackground).color(); + } else { + return complementaryColorScheme.background(KColorScheme::NormalBackground).color(); + } + case Svg::ComplementaryHover: + return complementaryColorScheme.decoration(KColorScheme::HoverColor).color(); + case Svg::ComplementaryFocus: + return complementaryColorScheme.decoration(KColorScheme::FocusColor).color(); + case Svg::ComplementaryHighlightedText: + return selectionColorScheme.foreground(KColorScheme::NormalText).color(); + case Svg::ComplementaryPositiveText: + return complementaryColorScheme.foreground(KColorScheme::PositiveText).color(); + case Svg::ComplementaryNeutralText: + return complementaryColorScheme.foreground(KColorScheme::NeutralText).color(); + case Svg::ComplementaryNegativeText: + return complementaryColorScheme.foreground(KColorScheme::NegativeText).color(); + + case Svg::HeaderText: + if (status == Svg::Status::Selected) { + return selectionColorScheme.foreground(KColorScheme::NormalText).color(); + } else { + return headerColorScheme.foreground(KColorScheme::NormalText).color(); + } + case Svg::HeaderBackground: + if (status == Svg::Status::Selected) { + return selectionColorScheme.background(KColorScheme::NormalBackground).color(); + } else { + return headerColorScheme.background(KColorScheme::NormalBackground).color(); + } + case Svg::HeaderHover: + return headerColorScheme.decoration(KColorScheme::HoverColor).color(); + case Svg::HeaderFocus: + return headerColorScheme.decoration(KColorScheme::FocusColor).color(); + case Svg::HeaderHighlightedText: + return selectionColorScheme.foreground(KColorScheme::NormalText).color(); + case Svg::HeaderPositiveText: + return headerColorScheme.foreground(KColorScheme::PositiveText).color(); + case Svg::HeaderNeutralText: + return headerColorScheme.foreground(KColorScheme::NeutralText).color(); + case Svg::HeaderNegativeText: + return headerColorScheme.foreground(KColorScheme::NegativeText).color(); + default: + return {}; + } +} + +const QString ImageSetPrivate::svgStyleSheet(KSvg::Svg *svg) +{ + const KSvg::Svg::Status status = svg->status(); + const KColorScheme::ColorSet colorSet = KColorScheme::ColorSet(svg->colorSet()); + const bool useCache = svg->d->colorOverrides.isEmpty(); + QString stylesheet; + if (useCache) { + stylesheet = (status == Svg::Status::Selected) + ? cachedSelectedSvgStyleSheets.value(colorSet) + : (status == Svg::Status::Inactive ? cachedInactiveSvgStyleSheets.value(colorSet) : cachedSvgStyleSheets.value(colorSet)); + } + + if (stylesheet.isEmpty()) { + const QList namedColors({Svg::Text, + Svg::Background, + Svg::Highlight, + Svg::HighlightedText, + Svg::PositiveText, + Svg::NeutralText, + Svg::NegativeText, + + Svg::ButtonText, + Svg::ButtonBackground, + Svg::ButtonHover, + Svg::ButtonFocus, + Svg::ButtonHighlightedText, + Svg::ButtonPositiveText, + Svg::ButtonNeutralText, + Svg::ButtonNegativeText, + + Svg::ViewText, + Svg::ViewBackground, + Svg::ViewHover, + Svg::ViewFocus, + Svg::ViewHighlightedText, + Svg::ViewPositiveText, + Svg::ViewNeutralText, + Svg::ViewNegativeText, + + Svg::TooltipText, + Svg::TooltipBackground, + Svg::TooltipHover, + Svg::TooltipFocus, + Svg::TooltipHighlightedText, + Svg::TooltipPositiveText, + Svg::TooltipNeutralText, + Svg::TooltipNegativeText, + + Svg::ComplementaryText, + Svg::ComplementaryBackground, + Svg::ComplementaryHover, + Svg::ComplementaryFocus, + Svg::ComplementaryHighlightedText, + Svg::ComplementaryPositiveText, + Svg::ComplementaryNeutralText, + Svg::ComplementaryNegativeText, + + Svg::HeaderText, + Svg::HeaderBackground, + Svg::HeaderHover, + Svg::HeaderFocus, + Svg::HeaderHighlightedText, + Svg::HeaderPositiveText, + Svg::HeaderNeutralText, + Svg::HeaderNegativeText}); + const QString skel = QStringLiteral(".ColorScheme-%1{color:%2;}"); + const QMetaEnum metaEnum = QMetaEnum::fromType(); + + for (const auto colorName : std::as_const(namedColors)) { + stylesheet += skel.arg(QString::fromUtf8(metaEnum.valueToKey(colorName)), svg->color(colorName).name()); + } + + if (status == Svg::Status::Selected) { + cachedSelectedSvgStyleSheets.insert(colorSet, stylesheet); + } else if (status == Svg::Status::Inactive) { + cachedInactiveSvgStyleSheets.insert(colorSet, stylesheet); + } else { + cachedSvgStyleSheets.insert(colorSet, stylesheet); + } + } + + return stylesheet; +} + +bool ImageSetPrivate::findInCache(const QString &key, QPixmap &pix, unsigned int lastModified) +{ + if (!useCache()) { + return false; + } + + qint64 cacheLastModifiedTime = uint(pixmapCache->lastModifiedTime().toSecsSinceEpoch()); + if (lastModified > cacheLastModifiedTime) { + qCDebug(LOG_KSVG) << "ImageSetPrivate::findInCache: lastModified > cacheLastModifiedTime for" << key; + return false; + } + #if defined(Q_OS_LINUX) + // If the timestamp is the UNIX epoch (0) then we compare against the boot time instead. + // This is notably the case on ostree based systems such as Fedora Kinoite. + if (lastModified == 0 && bootTime > cacheLastModifiedTime) { + qCDebug(LOG_KSVG) << "ImageSetPrivate::findInCache: lastModified == 0 && bootTime > cacheLastModifiedTime for" << key; + return false; + } + #else + if (lastModified == 0) { + qCWarning(LOG_KSVG) << "findInCache with a lastModified timestamp of 0 is deprecated"; + return false; + } + #endif + + qCDebug(LOG_KSVG) << "ImageSetPrivate::findInCache: using cache for" << key; + const QString id = keysToCache.value(key); + const auto it = pixmapsToCache.constFind(id); + if (it != pixmapsToCache.constEnd()) { + pix = *it; + return !pix.isNull(); + } + + QPixmap temp; + if (pixmapCache->findPixmap(key, &temp) && !temp.isNull()) { + pix = temp; + return true; + } + + return false; +} + +void ImageSetPrivate::insertIntoCache(const QString &key, const QPixmap &pix) +{ + if (useCache()) { + pixmapCache->insertPixmap(key, pix); + } +} + +void ImageSetPrivate::insertIntoCache(const QString &key, const QPixmap &pix, const QString &id) +{ + if (useCache()) { + // Remove old key -> id mapping first + if (auto key = idsToCache.find(id); key != idsToCache.end()) { + keysToCache.remove(*key); + } + pixmapsToCache[id] = pix; + keysToCache[key] = id; + idsToCache[id] = key; + + // always start timer in pixmapSaveTimer's thread + QMetaObject::invokeMethod(pixmapSaveTimer, "start", Qt::QueuedConnection); + } +} + +void ImageSetPrivate::setImageSetName(const QString &tempImageSetName, bool emitChanged) +{ + QString theme = tempImageSetName; + if (theme.isEmpty() || theme == imageSetName) { + // let's try and get the default theme at least + if (imageSetName.isEmpty()) { + theme = QLatin1String(ImageSetPrivate::defaultImageSet); + } else { + return; + } + } + + KPluginMetaData data = metaDataForImageSet(basePath, theme); + if (!data.isValid()) { + data = metaDataForImageSet(basePath, QStringLiteral("default")); + if (!data.isValid()) { + return; + } + + theme = QLatin1String(ImageSetPrivate::defaultImageSet); + } + + // check again as ImageSetPrivate::defaultImageSet might be empty + if (imageSetName == theme) { + return; + } + + imageSetName = theme; + + // load the color scheme config + const QString colorsFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, basePath % theme % QLatin1String("/colors")); + // qCDebug(LOG_KSVG) << "we're going for..." << colorsFile << "*******************"; + + if (colorsFile.isEmpty()) { + colors = nullptr; + } else { + colors = KSharedConfig::openConfig(colorsFile); + } + + colorScheme = KColorScheme(QPalette::Active, KColorScheme::Window, colors); + selectionColorScheme = KColorScheme(QPalette::Active, KColorScheme::Selection, colors); + buttonColorScheme = KColorScheme(QPalette::Active, KColorScheme::Button, colors); + viewColorScheme = KColorScheme(QPalette::Active, KColorScheme::View, colors); + complementaryColorScheme = KColorScheme(QPalette::Active, KColorScheme::Complementary, colors); + headerColorScheme = KColorScheme(QPalette::Active, KColorScheme::Header, colors); + tooltipColorScheme = KColorScheme(QPalette::Active, KColorScheme::Tooltip, colors); + + pluginMetaData = metaDataForImageSet(basePath, theme); + KSharedConfigPtr metadata = configForImageSet(basePath, theme); + + KConfigGroup cg(metadata, QStringLiteral("Settings")); + QString fallback = cg.readEntry("FallbackImageSet", QString()); + + fallbackImageSets.clear(); + while (!fallback.isEmpty() && !fallbackImageSets.contains(fallback)) { + fallbackImageSets.append(fallback); + + KSharedConfigPtr metadata = configForImageSet(basePath, fallback); + KConfigGroup cg(metadata, QStringLiteral("Settings")); + fallback = cg.readEntry("FallbackImageSet", QString()); + } + + if (!fallbackImageSets.contains(QLatin1String(ImageSetPrivate::defaultImageSet))) { + fallbackImageSets.append(QLatin1String(ImageSetPrivate::defaultImageSet)); + } + + // Check for what Plasma version the theme has been done + // There are some behavioral differences between KDE4 Plasma and Plasma 5 + const QString apiVersion = pluginMetaData.value(QStringLiteral("X-Plasma-API")); + apiMajor = 1; + apiMinor = 0; + apiRevision = 0; + if (!apiVersion.isEmpty()) { + const QList parts = QStringView(apiVersion).split(QLatin1Char('.')); + if (!parts.isEmpty()) { + apiMajor = parts.value(0).toInt(); + } + if (parts.count() > 1) { + apiMinor = parts.value(1).toInt(); + } + if (parts.count() > 2) { + apiRevision = parts.value(2).toInt(); + } + } + + if (emitChanged) { + scheduleImageSetChangeNotification(PixmapCache | SvgElementsCache); + } +} + +bool ImageSetPrivate::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == QCoreApplication::instance()) { + if (event->type() == QEvent::ApplicationPaletteChange) { + colorsChanged(); + } + } + return QObject::eventFilter(watched, event); +} +} + +#include "moc_imageset_p.cpp" diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/imageset_p.h b/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/imageset_p.h new file mode 100644 index 0000000000..eaf3b23915 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/imageset_p.h @@ -0,0 +1,179 @@ +/* + SPDX-FileCopyrightText: 2006-2007 Aaron Seigo + SPDX-FileCopyrightText: 2013 Marco Martin + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KSVG_IMAGESET_P_H +#define KSVG_IMAGESET_P_H + +#include "imageset.h" +#include "svg.h" +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace KSvg +{ +class ImageSet; + +enum CacheType { + NoCache = 0, + PixmapCache = 1, + SvgElementsCache = 2, +}; +Q_DECLARE_FLAGS(CacheTypes, CacheType) +Q_DECLARE_OPERATORS_FOR_FLAGS(CacheTypes) + +class ImageSetPrivate : public QObject, public QSharedData +{ + Q_OBJECT + +public: + explicit ImageSetPrivate(QObject *parent = nullptr); + ~ImageSetPrivate() override; + + QString imagePath(const QString &theme, const QString &type, const QString &image); + QString findInImageSet(const QString &image, const QString &theme, bool cache = true); + void discardCache(CacheTypes caches); + void scheduleImageSetChangeNotification(CacheTypes caches); + bool useCache(); + void setImageSetName(const QString &themeName, bool emitChanged); + + QColor namedColor(Svg::StyleSheetColor colorName, const KSvg::Svg *svg); + const QString svgStyleSheet(KSvg::Svg *svg); + + /** + * Check if a pixmap already exists in the cache and compare the last modified + * timestamp of the file with the last modified date of the one in the cache to make sure + * the cache is still valid. + * + * On Linux systems only, if lastModified is not provided or set to 0, then this function + * uses the boot time as a reference instead. This is notably the case on ostree based + * systems such as Fedora Kinoite. + * + * TODO: timestamp shouldn't be user-provided + * + * @param key the name to use in the cache for this image + * @param pix the pixmap object to populate with the resulting data if found + * @param lastModified the timestamp of the file which will be compared with the last + * modified time of the entry in the cache + * + * @note Since KF 5.75, a lastModified value of 0 is deprecated on non-Linux systems. If + * used, it will now always return false. Use a proper file timestamp instead + * so modification can be properly tracked. + * + * @return true when pixmap was found and loaded from cache, false otherwise + **/ + bool findInCache(const QString &key, QPixmap &pix, unsigned int lastModified); + + /** + * Insert specified pixmap into the cache. + * If the cache already contains pixmap with the specified key then it is + * overwritten. + * + * @param key the name to use in the cache for this pixmap + * @param pix the pixmap data to store in the cache + **/ + void insertIntoCache(const QString &key, const QPixmap &pix); + + /** + * Insert specified pixmap into the cache. + * If the cache already contains pixmap with the specified key then it is + * overwritten. + * The actual insert is delayed for optimization reasons and the id + * parameter is used to discard repeated inserts in the delay time, useful + * when for instance the graphics to insert comes from a quickly resizing + * object: the frames between the start and destination sizes aren't + * useful in the cache and just cause overhead. + * + * @param key the name to use in the cache for this pixmap + * @param pix the pixmap data to store in the cache + * @param id a name that identifies the caller class of this function in an unique fashion. + * This is needed to limit disk writes of the cache. + * If an image with the same id changes quickly, + * only the last size where insertIntoCache was called is actually stored on disk + **/ + void insertIntoCache(const QString &key, const QPixmap &pix, const QString &id); + + void colorsChanged(); + +public Q_SLOTS: + void scheduledCacheUpdate(); + void onAppExitCleanup(); + void notifyOfChanged(); + +Q_SIGNALS: + void imageSetChanged(const QString &imageSetName); + void applicationPaletteChange(); + +public: + bool eventFilter(QObject *watched, QEvent *event) override; + + static const char defaultImageSet[]; + static const char themeRcFile[]; + + // Ref counting of ImageSetPrivate instances + static ImageSetPrivate *globalImageSet; + static QHash themes; + + QString imageSetName = QStringLiteral("default"); + QString basePath; + KPluginMetaData pluginMetaData; + QList fallbackImageSets; + KSharedConfigPtr colors; + KColorScheme colorScheme; + KColorScheme selectionColorScheme; + KColorScheme buttonColorScheme; + KColorScheme viewColorScheme; + KColorScheme complementaryColorScheme; + KColorScheme headerColorScheme; + KColorScheme tooltipColorScheme; + QStringList selectors; + KConfigGroup cfg; + KImageCache *pixmapCache; + QHash pixmapsToCache; + QHash keysToCache; + QHash idsToCache; + QHash cachedSvgStyleSheets; + QHash cachedSelectedSvgStyleSheets; + QHash cachedInactiveSvgStyleSheets; + QHash discoveries; + QTimer *pixmapSaveTimer; + QTimer *updateNotificationTimer; + unsigned cacheSize; + CacheTypes cachesToDiscard; + QString themeVersion; + QString themeMetadataPath; + QString iconImageSetMetadataPath; + + #if defined(Q_OS_LINUX) + // Store boot time to be able to compare it to the lastModifiedTime when the timestamp + // of files is the UNIX epoch. + time_t bootTime = 0; + #endif + + bool isDefault : 1; + bool useGlobal : 1; + bool cacheImageSet : 1; + bool fixedName : 1; + + // Version number of Plasma the ImageSet has been designed for + int apiMajor; + int apiMinor; + int apiRevision; +}; + +} + +#endif + +extern const QString s; diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/svg_p.h b/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/svg_p.h new file mode 100644 index 0000000000..818a4777d2 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/private/svg_p.h @@ -0,0 +1,176 @@ +/* + SPDX-FileCopyrightText: 2006-2010 Aaron Seigo + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KSVG_SVG_P_H +#define KSVG_SVG_P_H + +#include "svg.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace KSvg +{ +class SharedSvgRenderer : public QSvgRenderer, public QSharedData +{ + Q_OBJECT +public: + typedef QExplicitlySharedDataPointer Ptr; + + explicit SharedSvgRenderer(QObject *parent = nullptr); + SharedSvgRenderer(const QString &filename, const QString &styleSheet, QHash &interestingElements, QObject *parent = nullptr); + + SharedSvgRenderer(const QByteArray &contents, const QString &styleSheet, QHash &interestingElements, QObject *parent = nullptr); + + void reload(); + +private: + bool load(const QByteArray &contents, const QString &styleSheet, QHash &interestingElements); + + QString m_filename; + QString m_styleSheet; + QHash m_interestingElements; +}; + +class SvgPrivate +{ +public: + struct CacheId { + double width; + double height; + QString filePath; + QString elementName; + int status; + double scaleFactor; + int colorSet; + size_t styleSheet; // TODO: use that + uint extraFlags; // Not used here, used for enabledborders in FrameSvg + uint lastModified; + }; + + SvgPrivate(Svg *svg); + ~SvgPrivate(); + + size_t paletteId(const QPalette &palette, const QColor &positive, const QColor &neutral, const QColor &negative) const; + + // This function is meant for the rects cache + CacheId cacheId(QStringView elementId) const; + + // This function is meant for the pixmap cache + QString cachePath(const QString &path, const QSize &size) const; + + bool setImagePath(const QString &imagePath); + + ImageSet *actualImageSet(); + + QPixmap findInCache(const QString &elementId, qreal ratio, const QSizeF &s = QSizeF()); + + void createRenderer(); + void eraseRenderer(); + + QRectF elementRect(QStringView elementId); + QRectF findAndCacheElementRect(QStringView elementId); + + // Following two are utility functions to snap rendered elements to the pixel grid + // to and from are always 0 <= val <= 1 + qreal closestDistance(qreal to, qreal from); + + QRectF makeUniform(const QRectF &orig, const QRectF &dst); + + // Slots + void imageSetChanged(); + void colorsChanged(); + + static QHash s_renderers; + static QPointer s_systemColorsCache; + + Svg *q; + QPointer theme; + SharedSvgRenderer::Ptr renderer; + QString themePath; + QString path; + QSizeF size; + QSizeF naturalSize; + QChar styleCrc; + // We need colorOverrides.values() to have a stable order + QMap colorOverrides; + QString stylesheetOverride; + KColorScheme::ColorSet colorSet = KColorScheme::Window; + unsigned int lastModified; + qreal devicePixelRatio; + Svg::Status status; + QMetaObject::Connection imageSetChangedConnection; + + bool multipleImages : 1; + bool themed : 1; + bool fromCurrentImageSet : 1; + bool cacheRendering : 1; + bool themeFailed : 1; +}; + +class SvgRectsCache : public QObject +{ + Q_OBJECT +public: + SvgRectsCache(QObject *parent = nullptr); + + static SvgRectsCache *instance(); + + void insert(SvgPrivate::CacheId cacheId, const QRectF &rect, unsigned int lastModified); + void insert(size_t id, const QString &filePath, const QRectF &rect, unsigned int lastModified); + // Those 2 methods are the same, the second uses the integer id produced by hashed CacheId + bool findElementRect(SvgPrivate::CacheId cacheId, QRectF &rect); + bool findElementRect(size_t id, QStringView filePath, QRectF &rect); + + bool loadImageFromCache(const QString &path, uint lastModified); + void dropImageFromCache(const QString &path); + + void setNaturalSize(const QString &path, const QSizeF &size); + QSizeF naturalSize(const QString &path); + + QList sizeHintsForId(const QString &path, const QString &id); + void insertSizeHintForId(const QString &path, const QString &id, const QSizeF &size); + + QString iconThemePath(); + void setIconThemePath(const QString &path); + + QStringList cachedKeysForPath(const QString &path) const; + + unsigned int lastModifiedTimeFromCache(const QString &filePath); + + void updateLastModified(const QString &filePath, unsigned int lastModified); + + static const size_t s_seed; + +Q_SIGNALS: + void lastModifiedChanged(const QString &filePath, unsigned int lastModified); + +private: + QTimer *m_configSyncTimer = nullptr; + QString m_iconThemePath; + KSharedConfigPtr m_svgElementsCache; + /* + * We are indexing in the hash cache ids by their "digested" size_t out of qHash(CacheId) + * because we need to serialize it and unserialize it to a config file, + * which is more efficient to do that with the size_t directly rather than a CacheId struct serialization + */ + QHash m_localRectCache; + QHash> m_invalidElements; + QHash> m_sizeHintsForId; + QHash m_lastModifiedTimes; +}; +} + +size_t qHash(const KSvg::SvgPrivate::CacheId &id, size_t seed = 0); + +#endif diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/svg.cpp b/local/recipes/kde/kf6-ksvg/source/src/ksvg/svg.cpp new file mode 100644 index 0000000000..1bdafd6b69 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/svg.cpp @@ -0,0 +1,1159 @@ +/* + SPDX-FileCopyrightText: 2006-2007 Aaron Seigo + SPDX-FileCopyrightText: 2008-2010 Marco Martin + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#include "svg.h" +#include "framesvg.h" +#include "private/imageset_p.h" +#include "private/svg_p.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "debug_p.h" +#include "imageset.h" + +size_t qHash(const KSvg::SvgPrivate::CacheId &id, size_t seed) +{ + std::array parts = { + ::qHash(id.width), + ::qHash(id.height), + ::qHash(id.elementName), + ::qHash(id.filePath), + ::qHash(id.status), + ::qHash(id.scaleFactor), + ::qHash(id.colorSet), + ::qHash(id.styleSheet), + ::qHash(id.extraFlags), + ::qHash(id.lastModified), + }; + return qHashRange(parts.begin(), parts.end(), seed); +} + +size_t qHash(const QList &colors, size_t seed) +{ + std::vector parts; + for (const QColor &c : std::as_const(colors)) { + parts.push_back(::qHash(c.red())); + parts.push_back(::qHash(c.green())); + parts.push_back(::qHash(c.blue())); + parts.push_back(::qHash(c.alpha())); + } + return qHashRange(parts.begin(), parts.end(), seed); +} + +namespace KSvg +{ +class SvgRectsCacheSingleton +{ +public: + SvgRectsCache self; +}; + +Q_GLOBAL_STATIC(SvgRectsCacheSingleton, privateSvgRectsCacheSelf) + +const size_t SvgRectsCache::s_seed = 0x9e3779b9; + +SharedSvgRenderer::SharedSvgRenderer(QObject *parent) + : QSvgRenderer(parent) +{ +} + +SharedSvgRenderer::SharedSvgRenderer(const QString &filename, const QString &styleSheet, QHash &interestingElements, QObject *parent) + : QSvgRenderer(parent) +{ + KCompressionDevice file(filename, KCompressionDevice::GZip); + if (!file.open(QIODevice::ReadOnly)) { + return; + } + m_filename = filename; + m_styleSheet = styleSheet; + m_interestingElements = interestingElements; + load(file.readAll(), styleSheet, interestingElements); +} + +SharedSvgRenderer::SharedSvgRenderer(const QByteArray &contents, const QString &styleSheet, QHash &interestingElements, QObject *parent) + : QSvgRenderer(parent) +{ + load(contents, styleSheet, interestingElements); +} + +void SharedSvgRenderer::reload() +{ + KCompressionDevice file(m_filename, KCompressionDevice::GZip); + if (!file.open(QIODevice::ReadOnly)) { + return; + } + + load(file.readAll(), m_styleSheet, m_interestingElements); +} + +bool SharedSvgRenderer::load(const QByteArray &contents, const QString &styleSheet, QHash &interestingElements) +{ + // Apply the style sheet. + if (!styleSheet.isEmpty() && contents.contains("current-color-scheme")) { + QByteArray processedContents; + processedContents.reserve(contents.size()); + QXmlStreamReader reader(contents); + + QBuffer buffer(&processedContents); + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + while (!reader.atEnd()) { + if (reader.readNext() == QXmlStreamReader::StartElement && reader.qualifiedName() == QLatin1String("style") + && reader.attributes().value(QLatin1String("id")) == QLatin1String("current-color-scheme")) { + writer.writeStartElement(QLatin1String("style")); + writer.writeAttributes(reader.attributes()); + writer.writeCharacters(styleSheet); + writer.writeEndElement(); + while (reader.tokenType() != QXmlStreamReader::EndElement) { + reader.readNext(); + } + } else if (reader.tokenType() != QXmlStreamReader::Invalid) { + writer.writeCurrentToken(reader); + } + } + buffer.close(); + if (!QSvgRenderer::load(processedContents)) { + return false; + } + } else if (!QSvgRenderer::load(contents)) { + return false; + } + + // Search the SVG to find and store all ids that contain size hints. + const QString contentsAsString(QString::fromLatin1(contents)); + static const QRegularExpression idExpr(QLatin1String("id\\s*?=\\s*?(['\"])(\\d+?-\\d+?-.*?)\\1")); + Q_ASSERT(idExpr.isValid()); + + auto matchIt = idExpr.globalMatch(contentsAsString); + while (matchIt.hasNext()) { + auto match = matchIt.next(); + QString elementId = match.captured(2); + + QRectF elementRect = boundsOnElement(elementId); + if (elementRect.isValid()) { + interestingElements.insert(elementId, elementRect); + } + } + + return true; +} + +SvgRectsCache::SvgRectsCache(QObject *parent) + : QObject(parent) +{ + const QString svgElementsFile = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1Char('/') + QStringLiteral("ksvg-elements"); + m_svgElementsCache = KSharedConfig::openConfig(svgElementsFile, KConfig::SimpleConfig); + + m_configSyncTimer = new QTimer(this); + m_configSyncTimer->setSingleShot(true); + m_configSyncTimer->setInterval(5000); + connect(m_configSyncTimer, &QTimer::timeout, this, [this]() { + m_svgElementsCache->sync(); + }); +} + +SvgRectsCache *SvgRectsCache::instance() +{ + return &privateSvgRectsCacheSelf()->self; +} + +void SvgRectsCache::insert(KSvg::SvgPrivate::CacheId cacheId, const QRectF &rect, unsigned int lastModified) +{ + insert(qHash(cacheId, SvgRectsCache::s_seed), cacheId.filePath, rect, lastModified); +} + +void SvgRectsCache::insert(size_t id, const QString &filePath, const QRectF &rect, unsigned int lastModified) +{ + const unsigned int savedTime = lastModifiedTimeFromCache(filePath); + + if (savedTime == lastModified && m_localRectCache.contains(id)) { + return; + } + + m_localRectCache.insert(id, rect); + + KConfigGroup imageGroup(m_svgElementsCache, filePath); + + if (rect.isValid()) { + imageGroup.writeEntry(QString::number(id), rect); + } else { + m_invalidElements[filePath] << id; + imageGroup.writeEntry("Invalidelements", m_invalidElements[filePath].values()); + } + + QMetaObject::invokeMethod(m_configSyncTimer, qOverload<>(&QTimer::start)); + + if (savedTime != lastModified) { + m_lastModifiedTimes[filePath] = lastModified; + imageGroup.writeEntry("LastModified", lastModified); + Q_EMIT lastModifiedChanged(filePath, lastModified); + } +} + +bool SvgRectsCache::findElementRect(KSvg::SvgPrivate::CacheId cacheId, QRectF &rect) +{ + return findElementRect(qHash(cacheId, SvgRectsCache::s_seed), cacheId.filePath, rect); +} + +bool SvgRectsCache::findElementRect(size_t id, QStringView filePath, QRectF &rect) +{ + auto it = m_localRectCache.find(id); + + if (it == m_localRectCache.end()) { + auto elements = m_invalidElements.value(filePath.toString()); + if (elements.contains(id)) { + rect = QRectF(); + return true; + } + return false; + } + + rect = *it; + + return true; +} + +bool SvgRectsCache::loadImageFromCache(const QString &path, uint lastModified) +{ + if (path.isEmpty()) { + return false; + } + + KConfigGroup imageGroup(m_svgElementsCache, path); + + unsigned int savedTime = lastModifiedTimeFromCache(path); + + // Reload even if is older, to support downgrades + if (lastModified != savedTime) { + imageGroup.deleteGroup(); + QMetaObject::invokeMethod(m_configSyncTimer, qOverload<>(&QTimer::start)); + return false; + } + + auto &elements = m_invalidElements[path]; + if (elements.isEmpty()) { + auto list = imageGroup.readEntry("Invalidelements", QList()); + m_invalidElements[path] = QSet(list.begin(), list.end()); + + for (const auto &key : imageGroup.keyList()) { + bool ok = false; + uint keyUInt = key.toUInt(&ok); + if (ok) { + const QRectF rect = imageGroup.readEntry(key, QRectF()); + m_localRectCache.insert(keyUInt, rect); + } + } + } + return true; +} + +void SvgRectsCache::dropImageFromCache(const QString &path) +{ + KConfigGroup imageGroup(m_svgElementsCache, path); + imageGroup.deleteGroup(); + QMetaObject::invokeMethod(m_configSyncTimer, qOverload<>(&QTimer::start)); +} + +QList SvgRectsCache::sizeHintsForId(const QString &path, const QString &id) +{ + const QString pathId = path % id; + + auto it = m_sizeHintsForId.constFind(pathId); + if (it == m_sizeHintsForId.constEnd()) { + KConfigGroup imageGroup(m_svgElementsCache, path); + const QStringList &encoded = imageGroup.readEntry(id, QStringList()); + QList sizes; + for (const auto &token : encoded) { + const auto &parts = token.split(QLatin1Char('x')); + if (parts.size() != 2) { + continue; + } + QSize size = QSize(parts[0].toDouble(), parts[1].toDouble()); + if (!size.isEmpty()) { + sizes << size; + } + } + m_sizeHintsForId[pathId] = sizes; + return sizes; + } + + return *it; +} + +void SvgRectsCache::insertSizeHintForId(const QString &path, const QString &id, const QSizeF &size) +{ + // TODO: need to make this more efficient + auto sizeListToString = [](const QList &list) { + QString ret; + for (const auto &s : list) { + ret += QString::number(s.width()) % QLatin1Char('x') % QString::number(s.height()) % QLatin1Char(','); + } + return ret; + }; + m_sizeHintsForId[path % id].append(size); + KConfigGroup imageGroup(m_svgElementsCache, path); + imageGroup.writeEntry(id, sizeListToString(m_sizeHintsForId[path % id])); + QMetaObject::invokeMethod(m_configSyncTimer, qOverload<>(&QTimer::start)); +} + +QString SvgRectsCache::iconThemePath() +{ + if (!m_iconThemePath.isEmpty()) { + return m_iconThemePath; + } + + KConfigGroup imageGroup(m_svgElementsCache, QStringLiteral("General")); + m_iconThemePath = imageGroup.readEntry(QStringLiteral("IconThemePath"), QString()); + + return m_iconThemePath; +} + +void SvgRectsCache::setIconThemePath(const QString &path) +{ + m_iconThemePath = path; + KConfigGroup imageGroup(m_svgElementsCache, QStringLiteral("General")); + imageGroup.writeEntry(QStringLiteral("IconThemePath"), path); + QMetaObject::invokeMethod(m_configSyncTimer, qOverload<>(&QTimer::start)); +} + +void SvgRectsCache::setNaturalSize(const QString &path, const QSizeF &size) +{ + KConfigGroup imageGroup(m_svgElementsCache, path); + + // FIXME: needs something faster, perhaps even sprintf + imageGroup.writeEntry(QStringLiteral("NaturalSize"), size); + QMetaObject::invokeMethod(m_configSyncTimer, qOverload<>(&QTimer::start)); +} + +QSizeF SvgRectsCache::naturalSize(const QString &path) +{ + KConfigGroup imageGroup(m_svgElementsCache, path); + + // FIXME: needs something faster, perhaps even sprintf + return imageGroup.readEntry(QStringLiteral("NaturalSize"), QSizeF()); +} + +QStringList SvgRectsCache::cachedKeysForPath(const QString &path) const +{ + KConfigGroup imageGroup(m_svgElementsCache, path); + QStringList list = imageGroup.keyList(); + QStringList filtered; + + std::copy_if(list.begin(), list.end(), std::back_inserter(filtered), [](const QString element) { + bool ok; + element.toLong(&ok); + return ok; + }); + return filtered; +} + +unsigned int SvgRectsCache::lastModifiedTimeFromCache(const QString &filePath) +{ + const auto &i = m_lastModifiedTimes.constFind(filePath); + if (i != m_lastModifiedTimes.constEnd()) { + return i.value(); + } + + KConfigGroup imageGroup(m_svgElementsCache, filePath); + const unsigned int savedTime = imageGroup.readEntry("LastModified", 0); + m_lastModifiedTimes[filePath] = savedTime; + return savedTime; +} + +void SvgRectsCache::updateLastModified(const QString &filePath, unsigned int lastModified) +{ + KConfigGroup imageGroup(m_svgElementsCache, filePath); + const unsigned int savedTime = lastModifiedTimeFromCache(filePath); + + if (savedTime != lastModified) { + m_lastModifiedTimes[filePath] = lastModified; + imageGroup.writeEntry("LastModified", lastModified); + QMetaObject::invokeMethod(m_configSyncTimer, qOverload<>(&QTimer::start)); + Q_EMIT lastModifiedChanged(filePath, lastModified); + } +} + +SvgPrivate::SvgPrivate(Svg *svg) + : q(svg) + , renderer(nullptr) + , styleCrc(0) + , lastModified(0) + , devicePixelRatio(1.0) + , status(Svg::Status::Normal) + , multipleImages(false) + , themed(false) + , fromCurrentImageSet(false) + , cacheRendering(true) + , themeFailed(false) +{ +} + +SvgPrivate::~SvgPrivate() +{ + eraseRenderer(); +} + +size_t SvgPrivate::paletteId(const QPalette &palette, const QColor &positive, const QColor &neutral, const QColor &negative) const +{ + std::array parts = { + ::qHash(palette.cacheKey()), + ::qHash(positive.rgba()), + ::qHash(neutral.rgba()), + ::qHash(negative.rgba()), + }; + return qHashRange(parts.begin(), parts.end(), SvgRectsCache::s_seed); +} + +// This function is meant for the rects cache +SvgPrivate::CacheId SvgPrivate::cacheId(QStringView elementId) const +{ + auto idSize = size.isValid() && size != naturalSize ? size : QSizeF{-1.0, -1.0}; + return CacheId{idSize.width(), idSize.height(), path, elementId.toString(), status, devicePixelRatio, -1, 0, 0, lastModified}; +} + +// This function is meant for the pixmap cache +QString SvgPrivate::cachePath(const QString &id, const QSize &size) const +{ + std::vector parts; + const auto colors = colorOverrides.values(); + for (const QColor &c : std::as_const(colors)) { + parts.push_back(::qHash(c.red())); + parts.push_back(::qHash(c.green())); + parts.push_back(::qHash(c.blue())); + parts.push_back(::qHash(c.alpha())); + } + const size_t colorsHash = qHashRange(parts.begin(), parts.end(), SvgRectsCache::s_seed); + + auto cacheId = CacheId{double(size.width()), double(size.height()), path, id, status, devicePixelRatio, colorSet, colorsHash, 0, lastModified}; + return QString::number(qHash(cacheId, SvgRectsCache::s_seed)); +} + +bool SvgPrivate::setImagePath(const QString &imagePath) +{ + QString actualPath = imagePath; + bool isAbsoluteFile = QDir::isAbsolutePath(actualPath); + if (imagePath.startsWith(QLatin1String("file://"))) { + // length of file:// + actualPath.remove(0, 7); + isAbsoluteFile = true; + } + // If someone using the QML API uses Qt.resolvedUrl to get the absolute path inside of a QRC, + // the URI will look something like qrc:/artwork/file.svg + // In order for file IO to work it needs to be reformatted it needs to be :/artwork/file.svg + if (imagePath.startsWith(QLatin1String("qrc:/"))) { + actualPath.replace(QLatin1String("qrc:/"), QLatin1String(":/")); + isAbsoluteFile = true; + } + + bool isThemed = !actualPath.isEmpty() && !isAbsoluteFile; + + // lets check to see if we're already set to this file + if (isThemed == themed && ((themed && themePath == actualPath) || (!themed && path == actualPath))) { + return false; + } + + eraseRenderer(); + + // if we don't have any path right now and are going to set one, + // then lets not schedule a repaint because we are just initializing! + bool updateNeeded = true; //! path.isEmpty() || !themePath.isEmpty(); + + QObject::disconnect(imageSetChangedConnection); + + themed = isThemed; + path.clear(); + themePath.clear(); + + bool oldfromCurrentImageSet = fromCurrentImageSet; + fromCurrentImageSet = isThemed && actualImageSet()->currentImageSetHasImage(imagePath); + + if (fromCurrentImageSet != oldfromCurrentImageSet) { + Q_EMIT q->fromCurrentImageSetChanged(fromCurrentImageSet); + } + + if (themed) { + themePath = actualPath; + path = actualImageSet()->imagePath(themePath); + themeFailed = path.isEmpty(); + imageSetChangedConnection = QObject::connect(actualImageSet(), &ImageSet::imageSetChanged, q, [this]() { + imageSetChanged(); + }); + } else if (QFileInfo::exists(actualPath)) { + imageSetChangedConnection = QObject::connect(actualImageSet(), &ImageSet::imageSetChanged, q, [this]() { + imageSetChanged(); + }); + path = actualPath; + } else { +#ifndef NDEBUG + // qCDebug(LOG_KSVG) << "file '" << path << "' does not exist!"; +#endif + } + + QDateTime lastModifiedDate; + if (!path.isEmpty()) { + const QFileInfo info(path); + lastModifiedDate = info.lastModified(); + + lastModified = lastModifiedDate.toSecsSinceEpoch(); + + const bool imageWasCached = SvgRectsCache::instance()->loadImageFromCache(path, lastModified); + + if (!imageWasCached) { + auto i = s_renderers.constBegin(); + while (i != s_renderers.constEnd()) { + if (i.key().contains(path)) { + i.value()->reload(); + } + i++; + } + } + } + + // also images with absolute path needs to have a natural size initialized, + // even if looks a bit weird using ImageSet to store non-themed stuff + if ((themed && !path.isEmpty() && lastModifiedDate.isValid()) || QFileInfo::exists(actualPath)) { + naturalSize = SvgRectsCache::instance()->naturalSize(path); + if (naturalSize.isEmpty()) { + createRenderer(); + naturalSize = renderer->defaultSize(); + SvgRectsCache::instance()->setNaturalSize(path, naturalSize); + } + } + + q->resize(); + Q_EMIT q->imagePathChanged(); + + return updateNeeded; +} + +ImageSet *SvgPrivate::actualImageSet() +{ + if (!theme) { + theme = new KSvg::ImageSet(q); + } + + return theme.data(); +} + +QPixmap SvgPrivate::findInCache(const QString &elementId, qreal ratio, const QSizeF &s) +{ + QSize size; + QString actualElementId; + + // Look at the size hinted elements and try to find the smallest one with an + // identical aspect ratio. + if (s.isValid() && !elementId.isEmpty()) { + const QList elementSizeHints = SvgRectsCache::instance()->sizeHintsForId(path, elementId); + + if (!elementSizeHints.isEmpty()) { + QSizeF bestFit(-1, -1); + + for (const auto &hint : elementSizeHints) { + if (hint.width() >= s.width() * ratio && hint.height() >= s.height() * ratio + && (!bestFit.isValid() || (bestFit.width() * bestFit.height()) > (hint.width() * hint.height()))) { + bestFit = hint; + } + } + + if (bestFit.isValid()) { + actualElementId = QString::number(bestFit.width()) % QLatin1Char('-') % QString::number(bestFit.height()) % QLatin1Char('-') % elementId; + } + } + } + + if (elementId.isEmpty() || !q->hasElement(actualElementId)) { + actualElementId = elementId; + } + + if (elementId.isEmpty() || (multipleImages && s.isValid())) { + size = s.toSize() * ratio; + } else { + size = elementRect(actualElementId).size().toSize() * ratio; + } + + if (size.isEmpty()) { + return QPixmap(); + } + + const QString id = cachePath(actualElementId, size); + + QPixmap p; + if (cacheRendering && lastModified == SvgRectsCache::instance()->lastModifiedTimeFromCache(path) && actualImageSet()->d->findInCache(id, p, lastModified)) { + p.setDevicePixelRatio(ratio); + // qCDebug(LOG_PLASMA) << "found cached version of " << id << p.size(); + return p; + } + + createRenderer(); + + QRectF finalRect = makeUniform(renderer->boundsOnElement(actualElementId), QRect(QPoint(0, 0), size)); + + // don't alter the pixmap size or it won't match up properly to, e.g., FrameSvg elements + // makeUniform should never change the size so much that it gains or loses a whole pixel + p = QPixmap(size); + + p.fill(Qt::transparent); + QPainter renderPainter(&p); + + if (actualElementId.isEmpty()) { + renderer->render(&renderPainter, finalRect); + } else { + renderer->render(&renderPainter, actualElementId, finalRect); + } + + renderPainter.end(); + p.setDevicePixelRatio(ratio); + + if (cacheRendering) { + actualImageSet()->d->insertIntoCache(id, p, QString::number((qint64)q, 16) % QLatin1Char('_') % actualElementId); + } + + SvgRectsCache::instance()->updateLastModified(path, lastModified); + + return p; +} + +void SvgPrivate::createRenderer() +{ + if (renderer) { + return; + } + + if (themed && path.isEmpty() && !themeFailed) { + if (path.isEmpty()) { + path = actualImageSet()->imagePath(themePath); + themeFailed = path.isEmpty(); + if (themeFailed) { + qCWarning(LOG_KSVG) << "No image path found for" << themePath; + } + } + } + + QString styleSheet; + if (!colorOverrides.isEmpty()) { + if (stylesheetOverride.isEmpty()) { + stylesheetOverride = actualImageSet()->d->svgStyleSheet(q); + } + styleSheet = stylesheetOverride; + } else { + styleSheet = actualImageSet()->d->svgStyleSheet(q); + } + + styleCrc = qChecksum(QByteArrayView(styleSheet.toUtf8().constData(), styleSheet.size())); + + QHash::const_iterator it = s_renderers.constFind(styleCrc + path); + + if (it != s_renderers.constEnd()) { + renderer = it.value(); + } else { + if (path.isEmpty()) { + renderer = new SharedSvgRenderer(); + } else { + QHash interestingElements; + renderer = new SharedSvgRenderer(path, styleSheet, interestingElements); + + // Add interesting elements to the theme's rect cache. + QHashIterator i(interestingElements); + + QRegularExpression sizeHintedKeyExpr(QStringLiteral("^(\\d+)-(\\d+)-(.+)$")); + + while (i.hasNext()) { + i.next(); + const QString &elementId = i.key(); + QString originalId = i.key(); + const QRectF &elementRect = i.value(); + + originalId.replace(sizeHintedKeyExpr, QStringLiteral("\\3")); + SvgRectsCache::instance()->insertSizeHintForId(path, originalId, elementRect.size().toSize()); + + const CacheId cacheId{.width = -1.0, + .height = -1.0, + .filePath = path, + .elementName = elementId, + .status = status, + .scaleFactor = devicePixelRatio, + .colorSet = -1, + .styleSheet = 0, + .extraFlags = 0, + .lastModified = lastModified}; + SvgRectsCache::instance()->insert(cacheId, elementRect, lastModified); + } + } + + s_renderers[styleCrc + path] = renderer; + } + + if (size == QSizeF()) { + size = renderer->defaultSize(); + } +} + +void SvgPrivate::eraseRenderer() +{ + if (renderer && renderer->ref.loadRelaxed() == 2) { + // this and the cache reference it + s_renderers.erase(s_renderers.find(styleCrc + path)); + } + + renderer = nullptr; + styleCrc = QChar(0); +} + +QRectF SvgPrivate::elementRect(QStringView elementId) +{ + if (themed && path.isEmpty()) { + if (themeFailed) { + return QRectF(); + } + + path = actualImageSet()->imagePath(themePath); + themeFailed = path.isEmpty(); + + if (themeFailed) { + return QRectF(); + } + } + + if (path.isEmpty()) { + return QRectF(); + } + + QRectF rect; + const CacheId cacheId = SvgPrivate::cacheId(elementId); + bool found = SvgRectsCache::instance()->findElementRect(cacheId, rect); + // This is a corner case where we are *sure* the element is not valid + if (!found) { + rect = findAndCacheElementRect(elementId); + } + + return rect; +} + +QRectF SvgPrivate::findAndCacheElementRect(QStringView elementId) +{ + // we need to check the id before createRenderer(), otherwise it may generate a different id compared to the previous cacheId)( call + const CacheId cacheId = SvgPrivate::cacheId(elementId); + + createRenderer(); + + auto elementIdString = elementId.toString(); + + // This code will usually never be run because createRenderer already caches all the boundingRect in the elements in the svg + QRectF elementRect = renderer->elementExists(elementIdString) + ? renderer->transformForElement(elementIdString).map(renderer->boundsOnElement(elementIdString)).boundingRect() + : QRectF(); + + naturalSize = renderer->defaultSize(); + + qreal dx = size.width() / renderer->defaultSize().width(); + qreal dy = size.height() / renderer->defaultSize().height(); + + elementRect = QRectF(elementRect.x() * dx, elementRect.y() * dy, elementRect.width() * dx, elementRect.height() * dy); + SvgRectsCache::instance()->insert(cacheId, elementRect, lastModified); + + return elementRect; +} + +bool Svg::eventFilter(QObject *watched, QEvent *event) +{ + return QObject::eventFilter(watched, event); +} + +// Following two are utility functions to snap rendered elements to the pixel grid +// to and from are always 0 <= val <= 1 +qreal SvgPrivate::closestDistance(qreal to, qreal from) +{ + qreal a = to - from; + if (qFuzzyCompare(to, from)) { + return 0; + } else if (to > from) { + qreal b = to - from - 1; + return (qAbs(a) > qAbs(b)) ? b : a; + } else { + qreal b = 1 + to - from; + return (qAbs(a) > qAbs(b)) ? b : a; + } +} + +QRectF SvgPrivate::makeUniform(const QRectF &orig, const QRectF &dst) +{ + if (qFuzzyIsNull(orig.x()) || qFuzzyIsNull(orig.y())) { + return dst; + } + + QRectF res(dst); + qreal div_w = dst.width() / orig.width(); + qreal div_h = dst.height() / orig.height(); + + qreal div_x = dst.x() / orig.x(); + qreal div_y = dst.y() / orig.y(); + + // horizontal snap + if (!qFuzzyIsNull(div_x) && !qFuzzyCompare(div_w, div_x)) { + qreal rem_orig = orig.x() - (floor(orig.x())); + qreal rem_dst = dst.x() - (floor(dst.x())); + qreal offset = closestDistance(rem_dst, rem_orig); + res.translate(offset + offset * div_w, 0); + res.setWidth(res.width() + offset); + } + // vertical snap + if (!qFuzzyIsNull(div_y) && !qFuzzyCompare(div_h, div_y)) { + qreal rem_orig = orig.y() - (floor(orig.y())); + qreal rem_dst = dst.y() - (floor(dst.y())); + qreal offset = closestDistance(rem_dst, rem_orig); + res.translate(0, offset + offset * div_h); + res.setHeight(res.height() + offset); + } + + return res; +} + +void SvgPrivate::imageSetChanged() +{ + if (q->imagePath().isEmpty()) { + return; + } + + QString currentPath = themed ? themePath : path; + themePath.clear(); + eraseRenderer(); + setImagePath(currentPath); + q->resize(); + + // qCDebug(LOG_KSVG) << themePath << ">>>>>>>>>>>>>>>>>> theme changed"; + Q_EMIT q->repaintNeeded(); + Q_EMIT q->imageSetChanged(q->imageSet()); +} + +void SvgPrivate::colorsChanged() +{ + eraseRenderer(); + qCDebug(LOG_KSVG) << "repaint needed from colorsChanged"; + + Q_EMIT q->repaintNeeded(); +} + +QHash SvgPrivate::s_renderers; +QPointer SvgPrivate::s_systemColorsCache; + +Svg::Svg(QObject *parent) + : QObject(parent) + , d(new SvgPrivate(this)) +{ + connect(SvgRectsCache::instance(), &SvgRectsCache::lastModifiedChanged, this, [this](const QString &filePath, unsigned int lastModified) { + if (d->lastModified != lastModified && filePath == d->path) { + d->lastModified = lastModified; + Q_EMIT repaintNeeded(); + } + }); +} + +Svg::~Svg() +{ + delete d; +} + +void Svg::setDevicePixelRatio(qreal ratio) +{ + if (FrameSvg *f = qobject_cast(this)) { + f->clearCache(); + } + + d->devicePixelRatio = ratio; + + Q_EMIT repaintNeeded(); +} + +qreal Svg::devicePixelRatio() const +{ + return d->devicePixelRatio; +} + +QPixmap Svg::pixmap(const QString &elementID) +{ + if (elementID.isNull() || d->multipleImages) { + return d->findInCache(elementID, d->devicePixelRatio, size()); + } else { + return d->findInCache(elementID, d->devicePixelRatio); + } +} + +QImage Svg::image(const QSize &size, const QString &elementID) +{ + QPixmap pix(d->findInCache(elementID, d->devicePixelRatio, size)); + return pix.toImage(); +} + +void Svg::paint(QPainter *painter, const QPointF &point, const QString &elementID) +{ + Q_ASSERT(painter->device()); + const qreal ratio = painter->device()->devicePixelRatio(); + QPixmap pix((elementID.isNull() || d->multipleImages) ? d->findInCache(elementID, ratio, size()) : d->findInCache(elementID, ratio)); + + if (pix.isNull()) { + return; + } + + painter->drawPixmap(QRectF(point, size()), pix, QRectF(QPointF(0, 0), pix.size())); +} + +void Svg::paint(QPainter *painter, int x, int y, const QString &elementID) +{ + paint(painter, QPointF(x, y), elementID); +} + +void Svg::paint(QPainter *painter, const QRectF &rect, const QString &elementID) +{ + Q_ASSERT(painter->device()); + const qreal ratio = painter->device()->devicePixelRatio(); + QPixmap pix(d->findInCache(elementID, ratio, rect.size())); + + painter->drawPixmap(rect, pix, QRect(QPoint(0, 0), pix.size())); +} + +void Svg::paint(QPainter *painter, int x, int y, int width, int height, const QString &elementID) +{ + Q_ASSERT(painter->device()); + const qreal ratio = painter->device()->devicePixelRatio(); + QPixmap pix(d->findInCache(elementID, ratio, QSizeF(width, height))); + painter->drawPixmap(x, y, pix, 0, 0, pix.size().width(), pix.size().height()); +} + +QSizeF Svg::size() const +{ + if (d->size.isEmpty()) { + d->size = d->naturalSize; + } + + return {std::round(d->size.width()), std::round(d->size.height())}; +} + +void Svg::resize(qreal width, qreal height) +{ + resize(QSize(width, height)); +} + +void Svg::resize(const QSizeF &size) +{ + if (qFuzzyCompare(size.width(), d->size.width()) && qFuzzyCompare(size.height(), d->size.height())) { + return; + } + + d->size = size; + Q_EMIT sizeChanged(); +} + +void Svg::resize() +{ + if (qFuzzyCompare(d->naturalSize.width(), d->size.width()) && qFuzzyCompare(d->naturalSize.height(), d->size.height())) { + return; + } + + d->size = d->naturalSize; + Q_EMIT sizeChanged(); +} + +QSizeF Svg::elementSize(const QString &elementId) const +{ + const QSizeF s = d->elementRect(elementId).size(); + return {std::round(s.width()), std::round(s.height())}; +} + +QSizeF Svg::elementSize(QStringView elementId) const +{ + const QSizeF s = d->elementRect(elementId).size(); + return {std::round(s.width()), std::round(s.height())}; +} + +QRectF Svg::elementRect(const QString &elementId) const +{ + return d->elementRect(elementId); +} + +QRectF Svg::elementRect(QStringView elementId) const +{ + return d->elementRect(elementId); +} + +bool Svg::hasElement(const QString &elementId) const +{ + return hasElement(QStringView(elementId)); +} + +bool Svg::hasElement(QStringView elementId) const +{ + if (elementId.isEmpty() || (d->path.isNull() && d->themePath.isNull())) { + return false; + } + + return d->elementRect(elementId).isValid(); +} + +bool Svg::isValid() const +{ + if (d->path.isNull() && d->themePath.isNull()) { + return false; + } + + // try very hard to avoid creation of a parser + QSizeF naturalSize = SvgRectsCache::instance()->naturalSize(d->path); + if (!naturalSize.isEmpty()) { + return true; + } + + if (d->path.isEmpty() || !QFileInfo::exists(d->path)) { + return false; + } + d->createRenderer(); + return d->renderer->isValid(); +} + +void Svg::setContainsMultipleImages(bool multiple) +{ + d->multipleImages = multiple; +} + +bool Svg::containsMultipleImages() const +{ + return d->multipleImages; +} + +void Svg::setImagePath(const QString &svgFilePath) +{ + if (d->setImagePath(svgFilePath)) { + Q_EMIT repaintNeeded(); + } +} + +QString Svg::imagePath() const +{ + return d->themed ? d->themePath : d->path; +} + +void Svg::setUsingRenderingCache(bool useCache) +{ + d->cacheRendering = useCache; + Q_EMIT repaintNeeded(); +} + +bool Svg::isUsingRenderingCache() const +{ + return d->cacheRendering; +} + +bool Svg::fromCurrentImageSet() const +{ + return d->fromCurrentImageSet; +} + +void Svg::setImageSet(KSvg::ImageSet *theme) +{ + if (!theme || theme == d->theme.data()) { + return; + } + + if (d->theme) { + disconnect(d->theme.data(), nullptr, this, nullptr); + } + + d->theme = theme; + connect(theme, SIGNAL(imageSetChanged(QString)), this, SLOT(imageSetChanged())); + d->imageSetChanged(); +} + +ImageSet *Svg::imageSet() const +{ + return d->actualImageSet(); +} + +void Svg::setStatus(KSvg::Svg::Status status) +{ + if (status == d->status) { + return; + } + + d->status = status; + d->eraseRenderer(); + Q_EMIT statusChanged(status); + Q_EMIT repaintNeeded(); +} + +Svg::Status Svg::status() const +{ + return d->status; +} + +void Svg::setColorSet(KSvg::Svg::ColorSet colorSet) +{ + const KColorScheme::ColorSet convertedSet = KColorScheme::ColorSet(colorSet); + if (convertedSet == d->colorSet) { + return; + } + + d->colorSet = convertedSet; + d->eraseRenderer(); + Q_EMIT colorSetChanged(colorSet); + Q_EMIT repaintNeeded(); +} + +Svg::ColorSet Svg::colorSet() const +{ + return Svg::ColorSet(d->colorSet); +} + +QColor Svg::color(StyleSheetColor colorName) const +{ + auto it = d->colorOverrides.constFind(colorName); + if (it != d->colorOverrides.constEnd()) { + return *it; + } + return d->actualImageSet()->d->namedColor(colorName, this); +} + +void Svg::setColor(StyleSheetColor colorName, const QColor &color) +{ + if (d->colorOverrides.value(colorName) == color) { + return; + } + + if (color.isValid()) { + d->colorOverrides[colorName] = color; + } else { + d->colorOverrides.remove(colorName); + } + d->stylesheetOverride.clear(); + + d->eraseRenderer(); + Q_EMIT repaintNeeded(); +} + +void Svg::clearColorOverrides() +{ + d->colorOverrides.clear(); + d->stylesheetOverride.clear(); + d->eraseRenderer(); + Q_EMIT repaintNeeded(); +} + +} // KSvg namespace + +#include "moc_svg.cpp" +#include "private/moc_svg_p.cpp" diff --git a/local/recipes/kde/kf6-ksvg/source/src/ksvg/svg.h b/local/recipes/kde/kf6-ksvg/source/src/ksvg/svg.h new file mode 100644 index 0000000000..8809f07e48 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/ksvg/svg.h @@ -0,0 +1,567 @@ +/* + SPDX-FileCopyrightText: 2006-2007 Aaron Seigo + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +#ifndef KSVG_SVG_H +#define KSVG_SVG_H + +#include +#include + +#include +#include + +class QPainter; +class QPoint; +class QPointF; +class QRect; +class QRectF; +class QSize; +class QSizeF; +class QMatrix; + +/** + * The KSvg namespace. + */ +namespace KSvg +{ +class FrameSvgPrivate; +class SvgPrivate; + +/** + * @class Svg ksvg/svg.h + * + * @short A theme aware image-centric SVG class + * + * KSvg::Svg provides a class for rendering SVG images to a QPainter in a + * convenient manner. Unless an absolute path to a file is provided, it loads + * the SVG document using KSvg::ImageSet. It also provides a number of internal + * optimizations to help lower the cost of painting SVGs, such as caching. + * + * @see KSvg::FrameSvg + **/ +class KSVG_EXPORT Svg : public QObject +{ + Q_OBJECT + Q_PROPERTY(QSizeF size READ size WRITE resize NOTIFY sizeChanged) + Q_PROPERTY(bool multipleImages READ containsMultipleImages WRITE setContainsMultipleImages) + Q_PROPERTY(QString imagePath READ imagePath WRITE setImagePath NOTIFY imagePathChanged) + Q_PROPERTY(bool usingRenderingCache READ isUsingRenderingCache WRITE setUsingRenderingCache) + Q_PROPERTY(bool fromCurrentImageSet READ fromCurrentImageSet NOTIFY fromCurrentImageSetChanged) + Q_PROPERTY(KSvg::Svg::Status status READ status WRITE setStatus NOTIFY statusChanged) + Q_PROPERTY(KSvg::Svg::ColorSet colorSet READ colorSet WRITE setColorSet NOTIFY colorSetChanged) + +public: + enum Status { + Normal = 0, + Selected, + Inactive, + }; + Q_ENUM(Status) + + // FIXME? Those are copied from KColorScheme because is needed to make it a Q_ENUM + enum ColorSet { View, Window, Button, Selection, Tooltip, Complementary, Header }; + Q_ENUM(ColorSet) + + enum StyleSheetColor { + Text, + Background, + Highlight, + HighlightedText, + PositiveText, + NeutralText, + NegativeText, + + ButtonText, + ButtonBackground, + ButtonHover, + ButtonFocus, + ButtonHighlightedText, + ButtonPositiveText, + ButtonNeutralText, + ButtonNegativeText, + + ViewText, + ViewBackground, + ViewHover, + ViewFocus, + ViewHighlightedText, + ViewPositiveText, + ViewNeutralText, + ViewNegativeText, + + TooltipText, + TooltipBackground, + TooltipHover, + TooltipFocus, + TooltipHighlightedText, + TooltipPositiveText, + TooltipNeutralText, + TooltipNegativeText, + + ComplementaryText, + ComplementaryBackground, + ComplementaryHover, + ComplementaryFocus, + ComplementaryHighlightedText, + ComplementaryPositiveText, + ComplementaryNeutralText, + ComplementaryNegativeText, + + HeaderText, + HeaderBackground, + HeaderHover, + HeaderFocus, + HeaderHighlightedText, + HeaderPositiveText, + HeaderNeutralText, + HeaderNegativeText + }; + Q_ENUM(StyleSheetColor); + + /** + * @brief This method constructs an SVG object that implicitly shares and + * caches rendering. + * + * Unlike QSvgRenderer, which this class uses internally, + * KSvg::Svg represents an image generated from an SVG. As such, it has a + * related size and transform matrix (the latter being provided by the + * painter used to paint the image). + * + * The size is initialized to be the SVG's native size. + * + * @param parent options QObject to parent this to + * + * @related KSvg::ImageSet + */ + explicit Svg(QObject *parent = nullptr); + ~Svg() override; + + /** + * @brief This method sets the device pixel ratio for the Svg. + * + * This is the ratio between image pixels and device-independent pixels. The + * SVG will produce pixmaps scaled by devicePixelRatio, but all the sizes + * and element rects will not be altered. The default value is 1.0 and the + * scale will be done rounded to the floor integer. + * + * Setting it to something higher will make all the elements of this SVG + * appear bigger. + */ + void setDevicePixelRatio(qreal factor); + + /** + * @brief This method returns the device pixel ratio for this Svg. + */ + qreal devicePixelRatio() const; + + /** + * @brief This method returns a pixmap of the SVG represented by this + * object. + * + * The size of the pixmap will be the size of this Svg object (size()) if + * containsMultipleImages is @c true; otherwise, it will be the size of the + * requested element after the whole SVG has been scaled to size(). + * + * @param elementId the ID string of the element to render, or an empty + * string for the whole SVG (the default) + * @return a QPixmap of the rendered SVG + */ + Q_INVOKABLE QPixmap pixmap(const QString &elementID = QString()); + + /** + * @brief This method returns an image of the SVG represented by this + * object. + * + * The size of the image will be the size of this Svg object (size()) if + * containsMultipleImages is @c true; otherwise, it will be the size of the + * requested element after the whole SVG has been scaled to size(). + * + * @param elementId the ID string of the element to render, or an empty + * string for the whole SVG (the default) + * @return a QPixmap of the rendered SVG + */ + Q_INVOKABLE QImage image(const QSize &size, const QString &elementID = QString()); + + /** + * @brief This method paints all or part of the SVG represented by this + * object. + * + * The size of the painted area will be the size of this Svg object (size()) + * if containsMultipleImages is @c true; otherwise, it will be the size of + * the requested element after the whole SVG has been scaled to size(). + * + * @param painter the QPainter to use + * @param point the position to start drawing; the entire svg will be + * drawn starting at this point. + * @param elementId the ID string of the element to render, or an empty + * string for the whole SVG (the default) + */ + Q_INVOKABLE void paint(QPainter *painter, const QPointF &point, const QString &elementID = QString()); + + /** + * @brief This method paints all or part of the SVG represented by this + * object. + * + * The size of the painted area will be the size of this Svg object (size()) + * if containsMultipleImages is @c true; otherwise, it will be the size of + * the requested element after the whole SVG has been scaled to size(). + * + * @param painter the QPainter to use + * @param x the horizontal coordinate to start painting from + * @param y the vertical coordinate to start painting from + * @param elementId the ID string of the element to render, or an empty + * string for the whole SVG (the default) + */ + Q_INVOKABLE void paint(QPainter *painter, int x, int y, const QString &elementID = QString()); + + /** + * @brief This method paints all or part of the SVG represented by this + * object. + * + * @param painter the QPainter to use + * @param rect the rect to draw into; if smaller than the current size + * the drawing is starting at this point. + * @param elementId the ID string of the element to render, or an empty + * string for the whole SVG (the default) + */ + Q_INVOKABLE void paint(QPainter *painter, const QRectF &rect, const QString &elementID = QString()); + + /** + * @brief This method paints all or part of the SVG represented by this + * object. + * + * @param painter the QPainter to use + * @param x the horizontal coordinate to start painting from + * @param y the vertical coordinate to start painting from + * @param width the width of the element to draw + * @param height the height of the element do draw + * @param elementId the ID string of the element to render, or an empty + * string for the whole SVG (the default) + */ + Q_INVOKABLE void paint(QPainter *painter, int x, int y, int width, int height, const QString &elementID = QString()); + + /** + * @brief This method returns the size of the SVG. + * + * If the SVG has been resized with resize(), that size will be returned; + * otherwise, the natural size of the SVG will be returned. + * + * If containsMultipleImages is @c true, each element of the SVG will be + * rendered at this size by default. + * + * @return the current size of the SVG + **/ + QSizeF size() const; + + /** + * @brief This method resizes the rendered image. + * + * Rendering will actually take place on the next call to paint. + * + * If containsMultipleImages is @c true, each element of the SVG will be + * rendered at this size by default; otherwise, the entire image will be + * scaled to this size and each element will be scaled appropriately. + * + * @param width the new width + * @param height the new height + **/ + Q_INVOKABLE void resize(qreal width, qreal height); + + /** + * @brief This method resizes the rendered image. + * + * Rendering will actually take place on the next call to paint. + * + * If containsMultipleImages is @c true, each element of the SVG will be + * rendered at this size by default; otherwise, the entire image will be + * scaled to this size and each element will be scaled appropriately. + * + * @param size the new size of the image + **/ + Q_INVOKABLE void resize(const QSizeF &size); + + /** + * @brief This method resizes the rendered image to the natural size of the + * SVG. + * + * Rendering will actually take place on the next call to paint. + **/ + Q_INVOKABLE void resize(); + + /** + * @brief This method returns the size of a given element. + * + * This is the size of the element with ID @p elementId after the SVG + * has been scaled (see resize()). Note that this is unaffected by + * the containsMultipleImages property. + * + * @param elementId the id of the element to check + * @return the size of a given element, given the current size of the SVG + **/ + Q_INVOKABLE QSizeF elementSize(const QString &elementId) const; + + QSizeF elementSize(QStringView elementId) const; + + /** + * @brief This method returns the bounding rect of a given element. + * + * This is the bounding rect of the element with ID @p elementId after the + * SVG has been scaled (see resize()). Note that this is unaffected by the + * containsMultipleImages property. + * + * @param elementId the id of the element to check + * @return the current rect of a given element, given the current size of the SVG + **/ + Q_INVOKABLE QRectF elementRect(const QString &elementId) const; + + QRectF elementRect(QStringView elementId) const; + + /** + * @brief This method checks whether an element exists in the loaded SVG. + * + * @param elementId the id of the element to check for + * @return @c true if the element is defined in the SVG, otherwise @c false + **/ + Q_INVOKABLE bool hasElement(const QString &elementId) const; + + bool hasElement(QStringView elementId) const; + + /** + * @brief This method checks whether this object is backed by a valid SVG + * file. + * + * This method can be expensive as it causes disk access. + * + * @return @c true if the SVG file exists and the document is valid, + * otherwise @c false. + **/ + Q_INVOKABLE bool isValid() const; + + /** + * @brief This method sets whether the SVG contains a single image or + * multiple ones. + * + * If this is set to @c true, the SVG will be treated as a collection of + * related images, rather than a consistent drawing. + * + * In particular, when individual elements are rendered, this affects + * whether the elements are resized to size() by default. See paint() and + * pixmap(). + * + * @see ::paint() + * @see ::pixmap() + * + * @param multiple true if the svg contains multiple images + */ + void setContainsMultipleImages(bool multiple); + + /** + * @brief This method returns whether the SVG contains multiple images. + * + * If this is @c true, the SVG will be treated as a collection of related + * images, rather than a consistent drawing. + * + * @return @c true if the SVG will be treated as containing multiple images, + * @c false if it will be treated as a coherent image. + */ + bool containsMultipleImages() const; + + /** + * @brief This method sets the SVG file to render. + * + * Relative paths are looked for in the current Svg theme, and should not + * include the file extension (.svg and .svgz files will be searched for). + * include the file extension; files with the .svg and .svgz extensions will be + * found automatically. + * + * @see ImageSet::imagePath() + * + * If the parent object of this Svg is a KSvg::Applet, relative paths will + * be searched for in the applet's package first. + * + * @param svgFilePath either an absolute path to an SVG file, or an image + * name. + */ + virtual void setImagePath(const QString &svgFilePath); + + /** + * @brief This method returns the SVG file to render. + * + * If this SVG is themed, this will be a relative path, and will not + * include a file extension. + * + * @return either an absolute path to an SVG file, or an image name + * @see ImageSet::imagePath() + */ + QString imagePath() const; + + /** + * @brief This method sets whether or not to cache the results of rendering + * to pixmaps. + * + * If the SVG is resized and re-rendered often (and does not keep using the + * same small set of pixmap dimensions), then it may be less efficient to do + * disk caching. A good example might be a progress meter that uses an Svg + * object to paint itself: the meter will be changing often enough, with + * enough unpredictability and without re-use of the previous pixmaps to + * not get a gain from caching. + * + * Most Svg objects should use the caching feature, however. + * Therefore, the default is to use the render cache. + * + * @param useCache true to cache rendered pixmaps + * @since 4.3 + */ + void setUsingRenderingCache(bool useCache); + + /** + * Whether the rendering cache is being used. + * + * @brief This method returns whether the Svg object is using caching for + * rendering results. + * + * @since 4.3 + */ + bool isUsingRenderingCache() const; + + /** + * @brief This method returns whether the current theme has this SVG, + * without having to fall back to the default theme. + * + * @return true if the svg is loaded from the current theme + * @see ImageSet::currentImageSetHasImage + */ + bool fromCurrentImageSet() const; + + /** + * @brief This method sets the KSvg::ImageSet to use with this Svg object. + * + * By default, Svg objects use KSvg::ImageSet::default(). + * + * This determines how relative image paths are interpreted. + * + * @param theme the theme object to use + * @since 4.3 + */ + void setImageSet(KSvg::ImageSet *theme); + + /** + * @brief This method returns the KSvg::ImageSet used by this Svg object. + * + * This determines how relative image paths are interpreted. + * + * @return the theme used by this Svg + */ + ImageSet *imageSet() const; + + /** + * @brief This method sets the image in a selected status. + * + * SVGs can be colored with system color themes. If ``status`` is selected, + * TextColor will become HighlightedText color, and BackgroundColor will + * become HighlightColor. This can be used to make SVG-based graphics such + * as symbolic icons look correct together. Supported statuses are Normal + * and Selected. + * @since 5.23 + */ + void setStatus(Svg::Status status); + + /** + * @brief This method returns the Svg object's status. + * @since 5.23 + */ + Svg::Status status() const; + + /** + * @brief This method sets a color set for the SVG. + * Set a color set for the Svg. + * if the Svg uses stylesheets and has elements + * that are either TextColor or BackgroundColor class, + * make them use ButtonTextColor/ButtonBackgroundColor + * or ViewTextColor/ViewBackgroundColor + */ + void setColorSet(ColorSet colorSet); + + /** + * @return the color set for this Svg + */ + KSvg::Svg::ColorSet colorSet() const; + + QColor color(StyleSheetColor colorName) const; + void setColor(StyleSheetColor colorName, const QColor &color); + + void clearColorOverrides(); + +Q_SIGNALS: + /** + * @brief This signal is emitted whenever the SVG data has changed in such a + * way that a repaint is required. + * + * Any usage of an SVG object that does the painting itself must connect to + * this signal and respond by updating the painting. Note that connecting to + * ImageSet::imageSetChanged is incorrect in such a use case as the SVG + * itself may not be updated yet nor may theme change be the only case when + * a repaint is needed. Also note that classes or QML code which take Svg + * objects as parameters for their own painting all respond to this signal + * so that in those cases manually responding to the signal is unnecessary; + * ONLY when direct, manual painting with an Svg object is done in + * application code is this signal used. + */ + void repaintNeeded(); + + /** + * @brief This signal is emitted whenever the size has changed. + * @see ::resize() + */ + void sizeChanged(); + + /** + * @brief This signal is emitted whenever the image path has changed. + */ + void imagePathChanged(); + + /** + * @brief This signal is emitted whenever the color hint has changed. + */ + void colorHintChanged(); + + /** + * @brief This signal is emitted when the value of fromCurrentImageSet() + * has changed. + */ + void fromCurrentImageSetChanged(bool fromCurrentImageSet); + + /** + * @brief This signal is emitted when the status has changed. + */ + void statusChanged(KSvg::Svg::Status status); + + /** + * @brief This signal is emitted when the color set has changed. + */ + void colorSetChanged(KSvg::Svg::ColorSet colorSet); + + /** + * @brief This signal is emitted when the image set has changed. + */ + void imageSetChanged(ImageSet *imageSet); + +private: + SvgPrivate *const d; + bool eventFilter(QObject *watched, QEvent *event) override; + + Q_PRIVATE_SLOT(d, void imageSetChanged()) + Q_PRIVATE_SLOT(d, void colorsChanged()) + + friend class SvgPrivate; + friend class FrameSvgPrivate; + friend class FrameSvg; + friend class ImageSetPrivate; +}; + +} // KSvg namespace + +#endif // multiple inclusion guard diff --git a/local/recipes/kde/kf6-ksvg/source/src/tools/CMakeLists.txt b/local/recipes/kde/kf6-ksvg/source/src/tools/CMakeLists.txt new file mode 100644 index 0000000000..f096af4385 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/tools/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(split-plasma-svgs) diff --git a/local/recipes/kde/kf6-ksvg/source/src/tools/apply-stylesheet.sh b/local/recipes/kde/kf6-ksvg/source/src/tools/apply-stylesheet.sh new file mode 100755 index 0000000000..516e5c66b4 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/tools/apply-stylesheet.sh @@ -0,0 +1,287 @@ +#!/bin/bash + +PARSED_OPTIONS=$(getopt -n "$0" -o hf: --long "file:,TextFrom:,TextTo:,BackgroundFrom:,BackgroundTo:,HighlightFrom:,HighlightTo:,ViewTextFrom:,ViewTextTo:,ViewBackgroundFrom:,ViewBackgroundTo:,ViewHoverFrom:,ViewHoverTo:,ViewFocusFrom:,ViewFocusTo:,ButtonTextFrom:,ButtonTextTo:,ButtonBackgroundFrom:,ButtonBackgroundTo:,ButtonHoverFrom:,ButtonHoverTo:,ButtonFocusFrom:,ButtonFocusTo:" -- "$@") + +if [ $? -ne 0 ]; +then + exit 1 +fi + +eval set -- "$PARSED_OPTIONS" + +textFrom=\#31363b +backgroundFrom=\#eff0f1 +highlightFrom=\#3daee9 +viewTextFrom=\#31363b +viewBackgroundFrom=\#fcfcfc +viewHoverFrom=\#93cee9 +viewFocusFrom=\#3daee9 +buttonTextFrom=\#31363b +buttonBackgroundFrom=\#eff0f1 +buttonHoverFrom=\#93cee9 +buttonFocusFrom=\#3daee9 + +textTo=\#31363b +backgroundTo=\#eff0f1 +highlightTo=\#3daee9 +viewTextTo=\#31363b +viewBackgroundTo=\#fcfcfc +viewHoverTo=\#93cee9 +viewFocusTo=\#3daee9 +buttonTextTo=\#31363b +buttonBackgroundTo=\#eff0f1 +buttonHoverTo=\#93cee9 +buttonFocusTo=\#3daee9 + +file='' + +while true; +do + case "$1" in + + -h|--help) + echo "usage $0 [-h|options] -f file.svgz" + echo "Where options can be:" + echo " --TextFrom=color html encoded color to replace with the ColorScheme-Text from the stylesheet" + echo " --TextTo=color html encoded that the ColorScheme-Text class will have" + echo + echo " --BackgroundFrom=color html encoded color to replace with the ColorScheme-Background from the stylesheet" + echo " --BackgroundTo=color html encoded that the ColorScheme-Background class will have" + echo + echo " --HighlightFrom=color html encoded color to replace with the ColorScheme-Highlight from the stylesheet" + echo " --HighlightTo=color html encoded that the ColorScheme-Highlight class will have" + echo + echo " --ViewTextFrom=color html encoded color to replace with the ColorScheme-ViewText from the stylesheet" + echo " --ViewTextTo=color html encoded that the ColorScheme-ViewText class will have" + echo + echo " --ViewBackgroundFrom=color html encoded color to replace with the ColorScheme-ViewBackground from the stylesheet" + echo " --ViewBackgroundTo=color html encoded that the ColorScheme-ViewBackground class will have" + echo + echo " --ViewHoverFrom=color html encoded color to replace with the ColorScheme-ViewHover from the stylesheet" + echo " --ViewHoverTo=color html encoded that the ColorScheme-ViewHover class will have" + echo + echo " --ViewFocusFrom=color html encoded color to replace with the ColorScheme-ViewFocus from the stylesheet" + echo " --ViewFocusTo=color html encoded that the ColorScheme-ViewFocus class will have" + echo + echo " --ButtonTextFrom=color html encoded color to replace with the ColorScheme-ButtonText from the stylesheet" + echo " --ButtonTextTo=color html encoded that the ColorScheme-ButtonText class will have" + echo + echo " --ButtonBackgroundFrom=color html encoded color to replace with the ColorScheme-ButtonBackground from the stylesheet" + echo " --ButtonBackgroundTo=color html encoded that the ColorScheme-ButtonBackground class will have" + echo + echo " --ButtonHoverFrom=color html encoded color to replace with the ColorScheme-ButtonHover from the stylesheet" + echo " --ButtonHoverTo=color html encoded that the ColorScheme-ButtonHover class will have" + echo + echo " --ButtonFocusFrom=color html encoded color to replace with the ColorScheme-ButtonFocus from the stylesheet" + echo " --ButtonFocusTo=color html encoded that the ColorScheme-ButtonFocus class will have" + echo + echo "All the colors have default values conformant to the Breeze color palette" + echo + exit + shift;; + + --TextFrom) + textFrom=$2 + shift 2;; + --TextTo) + textTo=$2 + shift 2;; + + --BackgroundFrom) + backgroundFrom=$2 + shift 2;; + --BackgroundTo) + backgroundTo=$2 + shift 2;; + + --HighlightFrom) + highlightFrom=$2 + shift 2;; + --HighlightTo) + highlightTo=$2 + shift 2;; + + --ViewTextFrom) + viewTextFrom=$2 + shift 2;; + --ViewTextTo) + viewTextTo=$2 + shift 2;; + + --ViewBackgroundFrom) + viewBackgroundFrom=$2 + shift 2;; + --ViewBackgroundTo) + viewBackgroundTo=$2 + shift 2;; + + --ViewHoverFrom) + viewHoverFrom=$2 + shift 2;; + --ViewHoverTo) + viewHoverTo=$2 + shift 2;; + + --ViewFocusFrom) + viewFocusFrom=$2 + shift 2;; + --ViewFocusTo) + viewFocusTo=$2 + shift 2;; + + --ButtonTextFrom) + buttonTextFrom=$2 + shift 2;; + --ButtonTextTo) + buttonTextTo=$2 + shift 2;; + + --ButtonBackgroundFrom) + buttonBackgroundFrom=$2 + shift 2;; + --ButtonBackgroundTo) + buttonBackgroundTo=$2 + shift 2;; + + --ButtonHoverFrom) + buttonHoverFrom=$2 + shift 2;; + --ButtonHoverTo) + buttonHoverTo=$2 + shift 2;; + + --ButtonFocusFrom) + buttonFocusFrom=$2 + shift 2;; + --ButtonFocusTo) + buttonFocusTo=$2 + shift 2;; + + -f|--file) + file=`echo $2 | cut -d'.' --complement -f2-` + shift 2;; + + --) + shift + break;; + esac +done + + +if [ -z "$file" ]; + then echo missing svg file + exit 1 +fi + +isSvgz=0 + +if [ ! -f $file.svgz ] && [ ! -f $file.svg ]; then + echo "you must specify a valid svg" + exit 1 +fi + +if [ -f $file.svgz ]; then + isSvgz=1 +fi + + +if [ $isSvgz = 1 ]; then + mv $file.svgz $file.svg.gz + gunzip $file.svg.gz +fi + +echo Processing $file + +stylesheet=" + .ColorScheme-Text { + color:$textTo; + } + .ColorScheme-Background { + color:$backgroundTo; + } + .ColorScheme-Highlight { + color:$highlightTo; + } + .ColorScheme-ViewText { + color:$viewTextTo; + } + .ColorScheme-ViewBackground { + color:$viewBackgroundTo; + } + .ColorScheme-ViewHover { + color:$viewHoverTo; + } + .ColorScheme-ViewFocus{ + color:$viewFocusTo; + } + .ColorScheme-ButtonText { + color:$buttonTextTo; + } + .ColorScheme-ButtonBackground { + color:$buttonBackgroundTo; + } + .ColorScheme-ButtonHover { + color:$buttonHoverTo; + } + .ColorScheme-ButtonFocus{ + color:$buttonFocusTo; + } + " +colors=($textFrom $backgroundFrom $highlightFrom $viewTextFrom $viewBackgroundFrom $viewHoverFrom $viewFocusFrom $buttonTextFrom $buttonBackgroundFrom $buttonHoverFrom $buttonFocusFrom) +colorNames=(ColorScheme-Text ColorScheme-Background ColorScheme-Highlight ColorScheme-ViewText ColorScheme-ViewBackground ColorScheme-ViewHover ColorScheme-ViewFocus ColorScheme-ButtonText ColorScheme-ButtonBackground ColorScheme-ButtonHover ColorScheme-ButtonFocus) + +reorderXslt=' + + + + + + + + + + + + + + + + + + + + +' +echo $reorderXslt > transform.xsl + +if grep -q '"current-color-scheme"' $file.svg; then + echo replacing the stylesheet + xmlstarlet ed --update "/svg:svg/svg:defs/_:style" -v "$stylesheet" $file.svg > temp.svg +else + echo adding the stylesheet +xmlstarlet ed --subnode "/svg:svg/svg:defs" -t elem -n "style" -v "$stylesheet"\ + --subnode "/svg:svg/svg:defs/style" -t attr -n "type" -v "text/css"\ + --subnode "/svg:svg/svg:defs/style" -t attr -n "id" -v "current-color-scheme" $file.svg > temp.svg +fi + +xmlstarlet tr transform.xsl temp.svg > temp2.svg +mv temp2.svg temp.svg + +for i in ${!colors[@]} +do + xmlstarlet ed --subnode "//*/*[contains(@style, '${colors[i]}') and not (@class)]" -t attr -n "class" -v "${colorNames[i]}" temp.svg > temp2.svg + + mv temp2.svg temp.svg + + sed -i 's/\(style=".*\)fill:'${colors[i]}'/\1fill:currentColor/g' temp.svg + sed -i 's/\(style=".*\)stop-color:'${colors[i]}'/\1stop-color:currentColor/g' temp.svg +done + +rm transform.xsl + +mv temp.svg $file.svg +if [ $isSvgz = 1 ]; then + gzip -n $file.svg + mv $file.svg.gz $file.svgz +fi diff --git a/local/recipes/kde/kf6-ksvg/source/src/tools/currentColorFillFix.sh b/local/recipes/kde/kf6-ksvg/source/src/tools/currentColorFillFix.sh new file mode 100755 index 0000000000..80fa2402a0 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/tools/currentColorFillFix.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +if [ $# -ne 1 ]; + then echo Usage: $0 file.svgz + exit 1 +fi + +if [ ! -f $1 ]; then + echo "you must specify a valid svg" + exit 1 +fi + + +file=`echo $1 | cut -d'.' --complement -f2-` +mv $1 $file.svg.gz +gunzip $file.svg.gz + +echo Processing $file + +/usr/bin/perl -p -i -e "s/color:#[^;]*;(.*)fill:currentColor/\1fill:currentColor/g" $file.svg + +gzip -n $file.svg +mv $file.svg.gz $file.svgz \ No newline at end of file diff --git a/local/recipes/kde/kf6-ksvg/source/src/tools/inkscape extensions/plasmarename.inx b/local/recipes/kde/kf6-ksvg/source/src/tools/inkscape extensions/plasmarename.inx new file mode 100644 index 0000000000..dc5102e455 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/tools/inkscape extensions/plasmarename.inx @@ -0,0 +1,15 @@ + + + PlasmaRename + notmart.filter.plasmarename + + + all + + + + + + diff --git a/local/recipes/kde/kf6-ksvg/source/src/tools/inkscape extensions/plasmarename.py b/local/recipes/kde/kf6-ksvg/source/src/tools/inkscape extensions/plasmarename.py new file mode 100644 index 0000000000..f3f4733de5 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/tools/inkscape extensions/plasmarename.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 + +''' +SPDX-FileCopyrightText: 2009 Marco Martin + +SPDX-License-Identifier: GPL-2.0-or-later +''' + +import inkex + +import pathmodifier + + +class PlasmaNamesEffect(pathmodifier.PathModifier): + """ + Renames 9 selected elements as a plasma theme frame + """ + + def add_arguments(self, pars): + pars.add_argument('--prefix', type=str, default='World', help='Prefix of the selected elements') + + def effect(self): + # Get script's "--prefix" option value. + prefix = self.options.prefix + + # 9 elements: is a frame. 4 elements: is a border hint + positions = [] + if len(self.svg.selection) == 9: + positions = ['topleft', 'left', 'bottomleft', 'top', 'center', 'bottom', 'topright', 'right', 'bottomright'] + elif len(self.svg.selection) == 4: + positions = ['hint-left-margin', 'hint-top-margin', 'hint-bottom-margin', 'hint-right-margin'] + else: + raise inkex.AbortExtension('This extension requires 4 or 9 selected elements.') + + # some heuristics to normalize the values, find the least coords and size + minX = 9999 + minY = 9999 + minWidth = 9999 + minHeight = 9999 + for node in self.svg.selection.values(): + bbox = node.bounding_box() + minX = min(minX, bbox.x.minimum) + minY = min(minY, bbox.y.minimum) + minWidth = min(minWidth, bbox.width) + minHeight = min(minHeight, bbox.height) + + nodedictionary = {} + for node in self.svg.selection.values(): + bbox = node.bounding_box() + x = bbox.x.minimum/minWidth - minX + y = bbox.y.minimum/minHeight - minY + nodedictionary[x*1000 + y] = node + + i = 0 + for _, node in sorted(nodedictionary.items()): + if prefix: + name = '%s-%s' % (prefix, positions[i]) + else: + name = '%s' % (positions[i]) + node.set('id', name) + i += 1 + + +if __name__ == '__main__': + PlasmaNamesEffect().run() diff --git a/local/recipes/kde/kf6-ksvg/source/src/tools/split-plasma-svgs/CMakeLists.txt b/local/recipes/kde/kf6-ksvg/source/src/tools/split-plasma-svgs/CMakeLists.txt new file mode 100644 index 0000000000..13d06d66c6 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/tools/split-plasma-svgs/CMakeLists.txt @@ -0,0 +1,16 @@ +add_executable(split-plasma-svgs) + +target_sources(split-plasma-svgs PRIVATE + split-plasma-svgs.cpp +) + +target_link_libraries(split-plasma-svgs +PRIVATE + Qt6::Core + Qt6::Gui + Qt6::Svg + KF6::Archive + KF6::CoreAddons + KF6::Svg +) + diff --git a/local/recipes/kde/kf6-ksvg/source/src/tools/split-plasma-svgs/split-plasma-svgs.cpp b/local/recipes/kde/kf6-ksvg/source/src/tools/split-plasma-svgs/split-plasma-svgs.cpp new file mode 100644 index 0000000000..a5f0915c8e --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/src/tools/split-plasma-svgs/split-plasma-svgs.cpp @@ -0,0 +1,304 @@ +/* SPDX-FileCopyrightText: 2023 Noah Davis + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Qt::Literals::StringLiterals; // for ""_L1 + +static KSvg::Svg s_ksvg; +static QSvgRenderer s_renderer; + +// https://developer.mozilla.org/en-US/docs/Web/SVG/Element#renderable_elements +static const QStringList s_renderableElements = { + "a"_L1, "circle"_L1, "ellipse"_L1, "foreignObject"_L1, "g"_L1, "image"_L1, + "line"_L1, "path"_L1, "polygon"_L1, "polyline"_L1, "rect"_L1, // excluding + "switch"_L1, "symbol"_L1, "text"_L1, "textPath"_L1, "tspan"_L1, "use"_L1 +}; + +QString joinedStrings(const QStringList &strings) +{ + return strings.join("\", \""_L1).prepend("\""_L1).append("\""_L1); +} + +// Translate the current element to (0,0) if possible. +// FIXME: Does not necessarily translate to (0,0) in one go. +void writeElementTranslation(QXmlStreamReader &reader, QXmlStreamWriter &writer, qreal dx, qreal dy) +{ + if ((qIsFinite(dx) && dx != 0) || (qIsFinite(dy) && dy != 0)) { + writer.writeStartElement(reader.qualifiedName()); // The thing reader has currently read. + auto attributes = reader.attributes(); + bool wasTranslated = false; + QString svgTranslate = "translate(%1,%2)"_L1.arg(QString::number(dx), QString::number(dy)); + for (int i = 0; i < attributes.size(); ++i) { + if (attributes[i].qualifiedName() == "transform"_L1) { + auto svgTransform = attributes[i].value().toString(); + if (!svgTransform.isEmpty()) { + svgTransform += " "_L1; + } + attributes[i] = {"transform"_L1, svgTransform + svgTranslate}; + wasTranslated = true; + } + writer.writeAttribute(attributes[i]); + } + if (!wasTranslated) { + writer.writeAttribute("transform"_L1, svgTranslate); + } + } else { + writer.writeCurrentToken(reader); // The thing reader has currently read. + } +} + +QMap splitSvg(const QString &inputArg, const QByteArray &inputContents) +{ + s_renderer.load(inputContents); + QMap outputMap; // filename, contents + QXmlStreamReader reader(inputContents); + reader.setNamespaceProcessing(false); + + QString stylesheet; + + while (!reader.atEnd() && !reader.hasError()) { + reader.readNextStartElement(); + if (reader.hasError()) { + break; + } + + const auto qualifiedName = reader.qualifiedName(); + const auto attributes = reader.attributes(); + QString id = attributes.value("id"_L1).toString(); + + // Skip elements without IDs since they aren't icons. + // Make sure you don't miss children when you make the output contents though. + // Also skip hints and groups with the layer1 ID + if (id.isEmpty() || id.startsWith("hint-"_L1) || (qualifiedName == "g"_L1 && id == "layer1"_L1)) { + continue; + } + + // Some SVGs have multiple stylesheets. + // They really shouldn't, but that's just how it is sometimes. + // The last stylesheet with the correct ID is the one we will use. + static const auto s_stylesheetId = "current-color-scheme"_L1; + if (qualifiedName == "style"_L1 && id == s_stylesheetId) { + reader.readNext(); + auto text = reader.text(); + if (!text.isEmpty()) { + stylesheet = text.toString(); + } + continue; + } + + // ignore non-renderable elements + if (!s_renderableElements.contains(qualifiedName)) { + continue; + } + + // NOTE: Does not include its own transform. + QTransform transform = s_renderer.transformForElement(id); + QRectF mappedRect = transform.mapRect(s_renderer.boundsOnElement(id)); + + // Skip invisible renderable elements. + if (mappedRect.isEmpty()) { + continue; + } + + QString outputFilename = id + ".svg"_L1; + QByteArray outputContents; + QXmlStreamWriter writer(&outputContents); + // Start writing document + writer.setAutoFormatting(true); + writer.writeStartDocument(); + + // + writer.writeStartElement("svg"_L1); + writer.writeDefaultNamespace("http://www.w3.org/2000/svg"_L1); + writer.writeNamespace("http://www.w3.org/1999/xlink"_L1, "xlink"_L1); + writer.writeNamespace("http://creativecommons.org/ns#"_L1, "cc"_L1); + writer.writeNamespace("http://purl.org/dc/elements/1.1/"_L1, "dc"_L1); + writer.writeNamespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#"_L1, "rdf"_L1); + writer.writeNamespace("http://www.inkscape.org/namespaces/inkscape"_L1, "inkscape"_L1); + writer.writeNamespace("http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"_L1, "sodipodi"_L1); + writer.writeAttribute("width"_L1, QString::number(mappedRect.width())); + writer.writeAttribute("height"_L1, QString::number(mappedRect.height())); + + // + + // Translation via parent + auto dx = -mappedRect.x(); + auto dy = -mappedRect.y(); + writeElementTranslation(reader, writer, dx, dy); + + // Write contents until we're no longer writing the current element or any of its children. + int depth = 0; + while (depth >= 0 && !reader.atEnd() && !reader.hasError()) { + reader.readNext(); + if (reader.isStartElement()) { + ++depth; + } + if (reader.isEndElement()) { + --depth; + } + writer.writeCurrentToken(reader); + } + + if (reader.hasError()) { + qWarning() << inputArg << "has an error:" << reader.errorString(); + break; + } + + writer.writeEndElement(); + // + + writer.writeEndDocument(); + + if (!outputFilename.isEmpty() && !outputContents.isEmpty()) { + outputMap.insert(outputFilename, outputContents); + } + } + return outputMap; +} + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + KAboutData aboutData(app.applicationName(), app.applicationName(), "1.0"_L1, + "Splits Plasma/KSVG SVGs into individual SVGs"_L1, + KAboutLicense::LGPL_V2, "2023 Noah Davis"_L1); + aboutData.addAuthor("Noah Davis"_L1, {}, "noahadvs@gmail.com"_L1); + KAboutData::setApplicationData(aboutData); + + QCommandLineParser commandLineParser; + commandLineParser.addPositionalArgument("inputs"_L1, "Input files (separated by spaces)"_L1, "inputs..."_L1); + commandLineParser.addPositionalArgument("output"_L1, "Output folder (optional, must exist). The default output folder is the current working directory."_L1, "[output]"_L1); + aboutData.setupCommandLine(&commandLineParser); + + commandLineParser.process(app); + aboutData.processCommandLine(&commandLineParser); + + const QStringList &positionalArguments = commandLineParser.positionalArguments(); + if (positionalArguments.isEmpty()) { + qWarning() << "The arguments are missing."; + return 1; + } + + QFileInfo lastArgInfo(positionalArguments.last()); + if (positionalArguments.size() == 1 && lastArgInfo.isDir()) { + qWarning() << "Input file arguments are missing."; + return 1; + } + + QDir outputDir = lastArgInfo.isDir() ? lastArgInfo.absoluteFilePath() : QDir::currentPath(); + QFileInfo outputDirInfo(outputDir.absolutePath()); + if (!outputDirInfo.isWritable()) { + // Using the arg instead of just path or filename so the user sees what they typed. + auto output = lastArgInfo.isDir() ? positionalArguments.last() : QDir::currentPath(); + qWarning() << output << "is not a writable output folder."; + return 1; + } + + QStringList inputArgs; + QStringList ignoredArgs; + for (int i = 0; i < positionalArguments.size() - lastArgInfo.isDir(); ++i) { + if (!QFileInfo::exists(positionalArguments[i])) { + ignoredArgs << positionalArguments[i]; + continue; + } + inputArgs << positionalArguments[i]; + } + + if (inputArgs.isEmpty()) { + qWarning() << "None of the input files could be found."; + return 1; + } + + if (!ignoredArgs.isEmpty()) { + // Using the arg instead of path or filename so the user sees what they typed. + qWarning() << "The following input files could not be found:"; + qWarning().noquote() << joinedStrings(ignoredArgs); + } + + bool wasAnyFileWritten = false; + for (const QString &inputArg : inputArgs) { + QFileInfo inputInfo(inputArg); + + const QString &absoluteInputPath = inputInfo.absoluteFilePath(); + // Avoid reading from a theme with relative paths by accident. + s_ksvg.setImagePath(absoluteInputPath); + if (!s_ksvg.isValid()) { + qWarning() << inputArg << "is not a valid Plasma theme SVG."; + continue; + } + + KCompressionDevice inputFile(absoluteInputPath, KCompressionDevice::GZip); + if (!inputFile.open(QIODevice::ReadOnly)) { + qWarning() << inputArg << "could not be read."; + continue; + } + const auto outputMap = splitSvg(inputArg, inputFile.readAll()); + inputFile.close(); + + if (outputMap.isEmpty()) { + qWarning() << inputArg << "could not be split."; + continue; + } + + const auto outputSubDirPath = outputDir.absoluteFilePath(inputInfo.baseName()); + outputDir.mkpath(outputSubDirPath); + QDir outputSubDir(outputSubDirPath); + QStringList unwrittenFiles; + QStringList invalidSvgs; + for (auto it = outputMap.cbegin(); it != outputMap.cend(); ++it) { + const QString &key = it.key(); + const QByteArray &value = it.value(); + if (key.isEmpty() || value.isEmpty()) { + unwrittenFiles << key; + continue; + } + const auto absoluteOutputPath = outputSubDir.absoluteFilePath(key); + QFile outputFile(absoluteOutputPath); + if (!outputFile.open(QIODevice::WriteOnly)) { + unwrittenFiles << key; + continue; + } + wasAnyFileWritten |= outputFile.write(value); + outputFile.close(); + s_renderer.load(absoluteOutputPath); + if (!s_renderer.isValid()) { + // Write it even if it isn't valid so that the user can examine the output. + invalidSvgs << key; + } + } + if (unwrittenFiles.size() == outputMap.size()) { + qWarning().nospace() << "No files could be written for " << inputArg << "."; + } else if (!unwrittenFiles.isEmpty()) { + qWarning().nospace() << "The following files could not be written for " << inputArg << ":"; + qWarning().noquote() << joinedStrings(unwrittenFiles); + } + if (!invalidSvgs.isEmpty()) { + qWarning().nospace() << "The following files written for " << inputArg << " are not valid SVGs:"; + qWarning().noquote() << joinedStrings(invalidSvgs); + } + } + + return wasAnyFileWritten ? 0 : 1; +} diff --git a/local/recipes/kde/kf6-ksvg/source/tests/frames.qml b/local/recipes/kde/kf6-ksvg/source/tests/frames.qml new file mode 100644 index 0000000000..3edea960ad --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/tests/frames.qml @@ -0,0 +1,40 @@ +/* + SPDX-FileCopyrightText: 2020 David Edmundson + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + + +import QtQuick 2.0 +import QtQuick.Layouts 1.1 + +import org.kde.plasma.core as PlasmaCore + +Item +{ + width: 500 + height: 500 + + + + Grid { + anchors.fill: parent + columns: 3 + + Repeater { + model: ["widgets/background", + "widgets/panel-background", + "opaque/widgets/panel-background", + "widgets/tooltip", + "opaque/widgets/tooltip" + ] + + delegate: PlasmaCore.FrameSvgItem { + width: 100 + height: 100 + imagePath: modelData + } + } + } +} + diff --git a/local/recipes/kde/kf6-ksvg/source/tests/selected_svg.qml b/local/recipes/kde/kf6-ksvg/source/tests/selected_svg.qml new file mode 100644 index 0000000000..43ee95ef69 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/tests/selected_svg.qml @@ -0,0 +1,35 @@ +/* + SPDX-FileCopyrightText: 2016 Marco Martin + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +import QtQuick 2.2 +import QtQuick.Controls 2.15 as Controls +import org.kde.ksvg 1.0 as KSvg + +KSvg.FrameSvgItem { + id: root + imagePath: "widgets/background" + state: KSvg.Svg.Normal + width: 600 + height: 800 + + Column { + anchors.centerIn: parent + spacing: 4 + + Controls.Button { + text: "Switch Selected State" + onClicked: root.state = (root.state == KSvg.Svg.Selected ? KSvg.Svg.Normal : KSvg.Svg.Selected) + } + + KSvg.SvgItem { + svg: KSvg.Svg { + id: svg + imagePath: "icons/phone" + state: root.state + } + } + } +} diff --git a/local/recipes/kde/kf6-ksvg/source/tests/shadows.qml b/local/recipes/kde/kf6-ksvg/source/tests/shadows.qml new file mode 100644 index 0000000000..dfdaf4a086 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/tests/shadows.qml @@ -0,0 +1,44 @@ +/* + SPDX-FileCopyrightText: 2021 Arjen Hiemstra + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +import QtQuick 2.15 +import QtQuick.Layouts 1.15 + +import org.kde.ksvg 1.0 as KSvg + +Rectangle { + color: "white" + width: 600 + height: 600 + + GridLayout { + anchors.fill: parent + columns: 3 + + Repeater { + model: [ + "shadow-topleft", + "shadow-top", + "shadow-topright", + "shadow-left", + "shadow-middle", + "shadow-right", + "shadow-bottomleft", + "shadow-bottom", + "shadow-bottomright" + ] + + KSvg.SvgItem { + elementId: modelData + + svg: KSvg.Svg { + imagePath: "dialogs/background" + } + } + } + } +} + diff --git a/local/recipes/kde/kf6-ksvg/source/tests/testborders.qml b/local/recipes/kde/kf6-ksvg/source/tests/testborders.qml new file mode 100644 index 0000000000..715730f549 --- /dev/null +++ b/local/recipes/kde/kf6-ksvg/source/tests/testborders.qml @@ -0,0 +1,93 @@ +/* + SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + + +import QtQuick 2.0 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.15 + +import org.kde.plasma.core as PlasmaCore + +Item +{ + width: 500 + height: 500 + + PlasmaCore.FrameSvgItem { + id: theItem + + imagePath: "widgets/background" + anchors { + fill: parent + margins: 10 + } + + Button { + text: "left" + checkable: true + checked: true + anchors { + horizontalCenterOffset: -50 + centerIn: parent + } + onClicked: { + if (checked) + theItem.enabledBorders |= PlasmaCore.FrameSvg.LeftBorder; + else + theItem.enabledBorders &=~PlasmaCore.FrameSvg.LeftBorder; + } + } + Button { + text: "right" + checkable: true + checked: true + + anchors { + horizontalCenterOffset: 50 + centerIn: parent + } + onClicked: { + if (checked) + theItem.enabledBorders |= PlasmaCore.FrameSvg.RightBorder; + else + theItem.enabledBorders &=~PlasmaCore.FrameSvg.RightBorder; + } + } + Button { + text: "top" + checkable: true + checked: true + + anchors { + verticalCenterOffset: -50 + centerIn: parent + } + onClicked: { + if (checked) + theItem.enabledBorders |= PlasmaCore.FrameSvg.TopBorder; + else + theItem.enabledBorders &=~PlasmaCore.FrameSvg.TopBorder; + } + } + Button { + text: "bottom" + checkable: true + checked: true + + anchors { + verticalCenterOffset: 50 + centerIn: parent + } + onClicked: { + if (checked) + theItem.enabledBorders |= PlasmaCore.FrameSvg.BottomBorder; + else + theItem.enabledBorders &=~PlasmaCore.FrameSvg.BottomBorder; + } + } + } +} + diff --git a/local/recipes/kde/kf6-ktextwidgets/source/CMakeLists.txt b/local/recipes/kde/kf6-ktextwidgets/source/CMakeLists.txt index 0b0308d1c7..0e64d935dd 100644 --- a/local/recipes/kde/kf6-ktextwidgets/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-ktextwidgets/source/CMakeLists.txt @@ -88,6 +88,8 @@ find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) +find_package(Qt6GuiPrivate ${REQUIRED_QT_VERSION} REQUIRED) if (WITH_TEXT_TO_SPEECH) find_package(Qt6 ${REQUIRED_QT_VERSION} CONFIG REQUIRED TextToSpeech) diff --git a/local/recipes/kde/kf6-kxmlgui/source/src/kswitchlanguagedialog_p.cpp b/local/recipes/kde/kf6-kxmlgui/source/src/kswitchlanguagedialog_p.cpp index 1c03f3fb87..8e3a00a714 100644 --- a/local/recipes/kde/kf6-kxmlgui/source/src/kswitchlanguagedialog_p.cpp +++ b/local/recipes/kde/kf6-kxmlgui/source/src/kswitchlanguagedialog_p.cpp @@ -74,10 +74,10 @@ void initializeLanguages() // Ideally setting the LANGUAGE would change the default QLocale too // but unfortunately this is too late since the QCoreApplication constructor // already created a QLocale at this stage so we need to set the reset it -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // by triggering the creation and destruction of a QSystemLocale +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // by triggering the creation and destruction of a QSystemLocale // this is highly dependent on Qt internals, so may break, but oh well -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// QSystemLocale *dummy = new QSystemLocale(); -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// delete dummy; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// QSystemLocale *dummy = new QSystemLocale(); +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// delete dummy; } } diff --git a/local/recipes/kde/kf6-pty/source/CMakeLists.txt b/local/recipes/kde/kf6-pty/source/CMakeLists.txt index 95721aecb8..827bf39577 100644 --- a/local/recipes/kde/kf6-pty/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-pty/source/CMakeLists.txt @@ -65,9 +65,9 @@ ecm_set_disabled_deprecation_versions( ) add_subdirectory( src ) -####if (BUILD_TESTING) -#### add_subdirectory( autotests ) -####endif() +######if (BUILD_TESTING) +###### add_subdirectory( autotests ) +######endif() if (BUILD_QCH) ecm_install_qch_export( diff --git a/local/recipes/kde/kf6-solid/source/CMakeLists.txt b/local/recipes/kde/kf6-solid/source/CMakeLists.txt index f025e2e28d..0bce0cdfce 100644 --- a/local/recipes/kde/kf6-solid/source/CMakeLists.txt +++ b/local/recipes/kde/kf6-solid/source/CMakeLists.txt @@ -78,7 +78,7 @@ set_package_properties(PList PROPERTIES if (CMAKE_SYSTEM_NAME MATCHES Linux) # Used by the UDisks backend on Linux - #######################################################################find_package(LibMount) + #########################################################################find_package(LibMount) set_package_properties(LibMount PROPERTIES TYPE REQUIRED) endif() diff --git a/recipes/kde/kf6-ksvg b/recipes/kde/kf6-ksvg new file mode 120000 index 0000000000..24ec6b73a9 --- /dev/null +++ b/recipes/kde/kf6-ksvg @@ -0,0 +1 @@ +../../local/recipes/kde/kf6-ksvg \ No newline at end of file