├── .tag ├── tests ├── manual │ ├── hellorhi │ │ ├── qt.png │ │ └── CMakeLists.txt │ ├── shared │ │ ├── quitlogo.png │ │ └── painthelper.h │ ├── hellorhi2 │ │ ├── color.frag │ │ ├── color.vert │ │ └── CMakeLists.txt │ ├── CMakeLists.txt │ ├── itemtest │ │ ├── main.cpp │ │ ├── CMakeLists.txt │ │ ├── itemtest.h │ │ └── main.qml │ └── widgettest │ │ ├── CMakeLists.txt │ │ ├── widgettest.cpp │ │ └── widgettest.h ├── CMakeLists.txt └── auto │ ├── CMakeLists.txt │ ├── qcbrush │ └── CMakeLists.txt │ ├── qcpainterpath │ ├── CMakeLists.txt │ └── tst_qcpainterpath.cpp │ └── qcrhiplumbing │ └── CMakeLists.txt ├── tools ├── CMakeLists.txt └── qcshadergen │ ├── shader_includes │ ├── common.glsl │ ├── customvert.glsl │ └── customfrag.glsl │ ├── CMakeLists.txt │ ├── qcshadergen.cpp │ └── Qt6CanvasPainterMacros.cmake ├── examples ├── canvaspainter │ ├── gallery │ │ ├── fonts │ │ │ └── Pacifico.ttf │ │ ├── images │ │ │ ├── pattern1.png │ │ │ ├── pattern2.png │ │ │ ├── pattern3.png │ │ │ ├── face-smile-bw.png │ │ │ └── qt_development_white.png │ │ ├── doc │ │ │ ├── images │ │ │ │ └── gallery-example.webp │ │ │ └── src │ │ │ │ └── qtcanvaspainter-examples-gallery.qdoc │ │ ├── brush3.frag │ │ ├── main.cpp │ │ ├── galleryitem.cpp │ │ ├── brush4.frag │ │ ├── brush3.vert │ │ ├── brush2.frag │ │ ├── CMakeLists.txt │ │ ├── galleryitem.h │ │ ├── brush1.frag │ │ ├── galleryitemrenderer.h │ │ ├── main.qml │ │ └── TopBar.qml │ ├── hellowidget │ │ ├── qt-translucent.png │ │ ├── doc │ │ │ ├── images │ │ │ │ └── hellowidget-example.webp │ │ │ └── src │ │ │ │ └── qtcanvaspainter-examples-hellowidget.qdoc │ │ ├── canvaswidget.h │ │ ├── CMakeLists.txt │ │ ├── main.cpp │ │ └── canvaswidget.cpp │ ├── compacthealth │ │ ├── images │ │ │ ├── icon_run_dark.png │ │ │ ├── icon_run_light.png │ │ │ ├── icon_random_dark.png │ │ │ ├── icon_random_light.png │ │ │ ├── icon_theme_dark.png │ │ │ ├── icon_theme_light.png │ │ │ ├── icon_settings_dark.png │ │ │ └── icon_settings_light.png │ │ ├── doc │ │ │ ├── images │ │ │ │ └── compacthealth-example.webp │ │ │ └── src │ │ │ │ └── qtcanvaspainter-examples-compacthealth.qdoc │ │ ├── theme.h │ │ ├── CMakeLists.txt │ │ ├── painterwindow.h │ │ ├── ecggraph.h │ │ ├── main.cpp │ │ ├── theme.cpp │ │ └── mainwindow.h │ └── CMakeLists.txt └── CMakeLists.txt ├── src ├── canvaspainter │ ├── doc │ │ ├── images │ │ │ ├── hello_qcpainter.png │ │ │ ├── image_example_1.png │ │ │ ├── boxgradient_example_1.png │ │ │ ├── gridpattern_example_1.png │ │ │ ├── imagepattern_example_1.png │ │ │ ├── examples_css_box_shadow.png │ │ │ ├── lineargradient_example_1.png │ │ │ ├── radialgradient_example_1.png │ │ │ ├── conicalgradient_example_1.png │ │ │ └── examples_qcpainter_box_shadow.png │ │ ├── src │ │ │ ├── qtcanvaspainter-examples.qdoc │ │ │ ├── qtcanvaspainter-cppmodule.qdoc │ │ │ └── qtcanvaspainter-index.qdoc │ │ ├── qtcanvaspainter-toc.qdoc │ │ ├── snippets │ │ │ ├── widget-ex-1.cpp │ │ │ ├── item-ex-1.cpp │ │ │ ├── widget-canvas-ex-1.cpp │ │ │ ├── renderer-ex-1.cpp │ │ │ └── paintdriver-ex-1.cpp │ │ └── qtcanvaspainter.qdocconf │ ├── engine │ │ ├── REUSE.toml │ │ ├── qt_attribution.json │ │ ├── LICENSE.NanoVG.txt │ │ ├── qcpainter.vert │ │ ├── qcareaallocator_p.h │ │ ├── qctextlayout_p.h │ │ ├── qctextlayout.cpp │ │ ├── qcdistancefieldglyphcache_p.h │ │ └── qcrhidistancefieldglyphcache_p.h │ ├── qtcanvaspainterglobal.h │ ├── qtcanvaspainterglobal_p.h │ ├── qcconicalgradient.h │ ├── qcimage_p.h │ ├── qclineargradient.h │ ├── qcbrush_p.h │ ├── qcboxgradient.h │ ├── qcpainterfactory_p.h │ ├── qcoffscreencanvas_p.h │ ├── qcradialgradient.h │ ├── qcdebug_p.h │ ├── qquickcpainteritem_p.h │ ├── qcpainterwidget_p.h │ ├── qcrhipaintdriver_p.h │ ├── qcpainterfactory.h │ ├── qquickcpainteritem.h │ ├── qcrhipaintdriver.h │ ├── qccustombrush.h │ ├── qcpainterwidget.h │ ├── qcimagepattern_p.h │ ├── qcgradient.h │ ├── qcimage.h │ ├── qcgridpattern_p.h │ ├── qcbrush.h │ ├── qquickcpainterrenderer.h │ ├── qquickcpainterrenderer_p.h │ ├── qcpainterpath_p.h │ ├── qcboxshadow_p.h │ ├── qcgradient_p.h │ ├── qcimagepattern.h │ ├── qcoffscreencanvas.h │ ├── qcboxshadow.h │ ├── qccustombrush_p.h │ ├── qcgridpattern.h │ ├── qcbrush.cpp │ ├── qcpainter_p.h │ ├── qcpainterpath.h │ └── qcdebug.cpp └── CMakeLists.txt ├── .cmake.conf ├── dependencies.yaml ├── LICENSES ├── LicenseRef-Qt-Commercial.txt ├── Qt-GPL-exception-1.0.txt ├── BSD-3-Clause.txt └── Zlib.txt ├── coin ├── module_config.yaml └── axivion │ └── ci_config_linux.json ├── CMakeLists.txt └── licenseRule.json /.tag: -------------------------------------------------------------------------------- 1 | 12cb3cba81153cb409c32e37b1bb85c485acf3f7 2 | -------------------------------------------------------------------------------- /tests/manual/hellorhi/qt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/tests/manual/hellorhi/qt.png -------------------------------------------------------------------------------- /tests/manual/shared/quitlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/tests/manual/shared/quitlogo.png -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | add_subdirectory(qcshadergen) 5 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/fonts/Pacifico.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/gallery/fonts/Pacifico.ttf -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/images/pattern1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/gallery/images/pattern1.png -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/images/pattern2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/gallery/images/pattern2.png -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/images/pattern3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/gallery/images/pattern3.png -------------------------------------------------------------------------------- /src/canvaspainter/doc/images/hello_qcpainter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/src/canvaspainter/doc/images/hello_qcpainter.png -------------------------------------------------------------------------------- /src/canvaspainter/doc/images/image_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/src/canvaspainter/doc/images/image_example_1.png -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/images/face-smile-bw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/gallery/images/face-smile-bw.png -------------------------------------------------------------------------------- /examples/canvaspainter/hellowidget/qt-translucent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/hellowidget/qt-translucent.png -------------------------------------------------------------------------------- /src/canvaspainter/doc/images/boxgradient_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/src/canvaspainter/doc/images/boxgradient_example_1.png -------------------------------------------------------------------------------- /src/canvaspainter/doc/images/gridpattern_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/src/canvaspainter/doc/images/gridpattern_example_1.png -------------------------------------------------------------------------------- /src/canvaspainter/doc/images/imagepattern_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/src/canvaspainter/doc/images/imagepattern_example_1.png -------------------------------------------------------------------------------- /src/canvaspainter/doc/images/examples_css_box_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/src/canvaspainter/doc/images/examples_css_box_shadow.png -------------------------------------------------------------------------------- /src/canvaspainter/doc/images/lineargradient_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/src/canvaspainter/doc/images/lineargradient_example_1.png -------------------------------------------------------------------------------- /src/canvaspainter/doc/images/radialgradient_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/src/canvaspainter/doc/images/radialgradient_example_1.png -------------------------------------------------------------------------------- /src/canvaspainter/doc/images/conicalgradient_example_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/src/canvaspainter/doc/images/conicalgradient_example_1.png -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/images/icon_run_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/compacthealth/images/icon_run_dark.png -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/images/icon_run_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/compacthealth/images/icon_run_light.png -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/doc/images/gallery-example.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/gallery/doc/images/gallery-example.webp -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/images/qt_development_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/gallery/images/qt_development_white.png -------------------------------------------------------------------------------- /src/canvaspainter/doc/images/examples_qcpainter_box_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/src/canvaspainter/doc/images/examples_qcpainter_box_shadow.png -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/images/icon_random_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/compacthealth/images/icon_random_dark.png -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/images/icon_random_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/compacthealth/images/icon_random_light.png -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/images/icon_theme_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/compacthealth/images/icon_theme_dark.png -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/images/icon_theme_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/compacthealth/images/icon_theme_light.png -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/images/icon_settings_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/compacthealth/images/icon_settings_dark.png -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/images/icon_settings_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/compacthealth/images/icon_settings_light.png -------------------------------------------------------------------------------- /examples/canvaspainter/hellowidget/doc/images/hellowidget-example.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/hellowidget/doc/images/hellowidget-example.webp -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/doc/images/compacthealth-example.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qt/qtcanvaspainter/dev/examples/canvaspainter/compacthealth/doc/images/compacthealth-example.webp -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | if(TARGET Qt::Gui AND TARGET Qt::qsb) 5 | add_subdirectory(canvaspainter) 6 | endif() 7 | -------------------------------------------------------------------------------- /tests/manual/hellorhi2/color.frag: -------------------------------------------------------------------------------- 1 | #version 440 2 | 3 | layout(location = 0) in vec3 v_color; 4 | layout(location = 0) out vec4 fragColor; 5 | 6 | void main() 7 | { 8 | fragColor = vec4(v_color, 1.0); 9 | } 10 | -------------------------------------------------------------------------------- /tests/manual/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | add_subdirectory(hellorhi) 5 | add_subdirectory(hellorhi2) 6 | add_subdirectory(widgettest) 7 | add_subdirectory(itemtest) 8 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | qt_examples_build_begin(EXTERNAL_BUILD) 5 | 6 | add_subdirectory(canvaspainter) 7 | 8 | qt_examples_build_end() 9 | -------------------------------------------------------------------------------- /src/canvaspainter/engine/REUSE.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[annotations]] 4 | path = ["qcpainterengine.cpp", "qcpainterrhirenderer.cpp", "qcpainter.frag"] 5 | precedence = "aggregate" 6 | SPDX-FileCopyrightText = "Copyright (c) 2013 Mikko Mononen" 7 | SPDX-License-Identifier = "Zlib" 8 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | if(QT_BUILD_STANDALONE_TESTS) 5 | # Add qt_find_package calls for extra dependencies that need to be found when building 6 | # the standalone tests here. 7 | endif() 8 | qt_build_tests() 9 | -------------------------------------------------------------------------------- /.cmake.conf: -------------------------------------------------------------------------------- 1 | set(QT_REPO_MODULE_VERSION "6.12.0") 2 | set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1") 3 | 4 | set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_LEAN_HEADERS=1") 5 | list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_AS_CONST=1") 6 | list(APPEND QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_NO_FOREACH=1") 7 | -------------------------------------------------------------------------------- /dependencies.yaml: -------------------------------------------------------------------------------- 1 | dependencies: 2 | ../qtbase: 3 | ref: df1292e2b96aab02ad6df778d8336e7958ad5d1c 4 | required: true 5 | ../qtdeclarative: 6 | ref: 7ef1d06ce70fa360613dca0b5ff03365ebbc9883 7 | required: true 8 | ../qtshadertools: 9 | ref: cff6953e790086bbbc69a05570e99049c98f33fd 10 | required: true 11 | -------------------------------------------------------------------------------- /src/canvaspainter/doc/src/qtcanvaspainter-examples.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \group canvaspainter-examples 6 | \title Qt Canvas Painter Examples and Tutorials 7 | \brief List of all examples and tutorials for Qt Canvas Painter. 8 | */ 9 | -------------------------------------------------------------------------------- /tests/manual/hellorhi2/color.vert: -------------------------------------------------------------------------------- 1 | #version 440 2 | 3 | layout(location = 0) in vec4 position; 4 | layout(location = 1) in vec3 color; 5 | 6 | layout(location = 0) out vec3 v_color; 7 | 8 | layout(std140, binding = 0) uniform buf { 9 | mat4 mvp; 10 | }; 11 | 12 | void main() 13 | { 14 | v_color = color; 15 | gl_Position = mvp * position; 16 | } 17 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/brush3.frag: -------------------------------------------------------------------------------- 1 | #version 440 2 | 3 | QC_INCLUDE "customfrag.glsl" 4 | 5 | void main() 6 | { 7 | float a = 0.6 + 0.2 * sin(0.1 * fragCoord.x + 4.0 * iTime); 8 | vec4 color = vec4(a, a, a, 1.0); 9 | fragColor = sdfFontAlpha() * globalAlpha * color; 10 | // Note: Disable this if you don't want color effects to affect. 11 | applyColorEffects(fragColor); 12 | } 13 | -------------------------------------------------------------------------------- /src/canvaspainter/qtcanvaspainterglobal.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QTCANVASPAINTERGLOBAL_H 5 | #define QTCANVASPAINTERGLOBAL_H 6 | 7 | #include 8 | #include 9 | 10 | #ifdef Q_QDOC 11 | #define Q_CANVASPAINTER_EXPORT 12 | #endif 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /src/canvaspainter/doc/qtcanvaspainter-toc.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \page qtcanvaspainter-toc.html 6 | \title Qt Canvas Painter module topics 7 | 8 | The following list has links to all the individual topics (HTML files) 9 | in the Qt Canvas Painter module. 10 | 11 | \list 12 | \li \l ... 13 | \endlist 14 | 15 | */ 16 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | QGuiApplication app(argc, argv); 11 | QQmlApplicationEngine engine; 12 | engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 13 | return app.exec(); 14 | } 15 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/galleryitem.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 4 | 5 | #include "galleryitem.h" 6 | 7 | GalleryItem::GalleryItem(QQuickItem *parent) 8 | : QQuickCPainterItem(parent) 9 | { 10 | } 11 | 12 | QQuickCPainterRenderer* GalleryItem::createItemRenderer() const 13 | { 14 | return new GalleryItemRenderer(); 15 | } 16 | 17 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/doc/src/qtcanvaspainter-examples-gallery.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \example gallery 6 | \ingroup canvaspainter-examples 7 | \title Qt Canvas Painter - Gallery Example 8 | \examplecategory {Graphics} 9 | \brief Demonstrates the QCPainter features in a Qt Quick application. 10 | 11 | \image gallery-example.webp 12 | */ 13 | -------------------------------------------------------------------------------- /LICENSES/LicenseRef-Qt-Commercial.txt: -------------------------------------------------------------------------------- 1 | Licensees holding valid commercial Qt licenses may use this software in 2 | accordance with the the terms contained in a written agreement between 3 | you and The Qt Company. Alternatively, the terms and conditions that were 4 | accepted by the licensee when buying and/or downloading the 5 | software do apply. 6 | 7 | For the latest licensing terms and conditions, see https://www.qt.io/terms-conditions. 8 | For further information use the contact form at https://www.qt.io/contact-us. 9 | -------------------------------------------------------------------------------- /coin/module_config.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | accept_configuration: 3 | condition: property 4 | property: features 5 | not_contains_value: Disable 6 | 7 | instructions: 8 | Build: 9 | - type: EnvironmentVariable 10 | variableName: VERIFY_SOURCE_SBOM 11 | variableValue: "ON" 12 | - !include "{{qt/qtbase}}/coin_module_build_template_v2.yaml" 13 | 14 | Test: 15 | - !include "{{qt/qtbase}}/coin_module_test_template_v3.yaml" 16 | - !include "{{qt/qtbase}}/coin_module_test_docs.yaml" 17 | -------------------------------------------------------------------------------- /tests/auto/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For now, don't built auto tests when QT_BUILD_MINIMAL_STATIC_TEST 2 | # is specified and the build is targeting iOS. QT_BUILD_MINIMAL_STATIC_TEST is used in our CI. 3 | # Regular non-cmake build tests shouldn't be built because the CI will try to run them and fail 4 | # due to missing simulator support. 5 | if(IOS AND QT_BUILD_MINIMAL_STATIC_TESTS) 6 | return() 7 | endif() 8 | 9 | add_subdirectory(qcbrush) 10 | add_subdirectory(qcrhiplumbing) 11 | add_subdirectory(qcpainterpath) 12 | -------------------------------------------------------------------------------- /src/canvaspainter/doc/src/qtcanvaspainter-cppmodule.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \module QtCanvasPainter 6 | \title Qt Canvas Painter C++ Classes 7 | \brief Provides classes for Qt Canvas Painter application development. 8 | 9 | Qt Canvas Painter provides the following C++ types: 10 | 11 | \section1 QtCanvasPainter C++ Types 12 | 13 | \generatelist classesbymodule QtCanvasPainter 14 | 15 | \noautolist 16 | */ 17 | -------------------------------------------------------------------------------- /tests/auto/qcbrush/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 5 | cmake_minimum_required(VERSION 3.16) 6 | project(tst_qcbrush LANGUAGES CXX) 7 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 8 | endif() 9 | 10 | qt_internal_add_test(tst_qcbrush 11 | SOURCES 12 | tst_qcbrush.cpp 13 | LIBRARIES 14 | Qt::Gui 15 | Qt::GuiPrivate 16 | Qt::CanvasPainter 17 | ) 18 | -------------------------------------------------------------------------------- /tests/auto/qcpainterpath/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 5 | cmake_minimum_required(VERSION 3.16) 6 | project(tst_qcbrush LANGUAGES CXX) 7 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 8 | endif() 9 | 10 | qt_internal_add_test(tst_qcpainterpath 11 | SOURCES 12 | tst_qcpainterpath.cpp 13 | LIBRARIES 14 | Qt::Gui 15 | Qt::GuiPrivate 16 | Qt::CanvasPainter 17 | ) 18 | -------------------------------------------------------------------------------- /tests/auto/qcrhiplumbing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 5 | cmake_minimum_required(VERSION 3.16) 6 | project(tst_qcrhiplumbing LANGUAGES CXX) 7 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 8 | endif() 9 | 10 | qt_internal_add_test(tst_qcrhiplumbing 11 | SOURCES 12 | tst_qcrhiplumbing.cpp 13 | LIBRARIES 14 | Qt::Gui 15 | Qt::GuiPrivate 16 | Qt::CanvasPainter 17 | ) 18 | -------------------------------------------------------------------------------- /examples/canvaspainter/hellowidget/canvaswidget.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #ifndef CANVASWIDGET_H 5 | #define CANVASWIDGET_H 6 | 7 | #include 8 | #include 9 | 10 | //![0] 11 | class CanvasWidget : public QCPainterWidget 12 | { 13 | public: 14 | CanvasWidget(); 15 | void initializeResources(QCPainter *p) override; 16 | void paint(QCPainter *p) override; 17 | void graphicsResourcesInvalidated() override; 18 | 19 | private: 20 | QCImage m_image; 21 | }; 22 | //![0] 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/canvaspainter/qtcanvaspainterglobal_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QTCANVASPAINTERGLOBAL_P_H 5 | #define QTCANVASPAINTERGLOBAL_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include "qtcanvaspainterglobal.h" 19 | #include 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /tests/manual/hellorhi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 5 | cmake_minimum_required(VERSION 3.16) 6 | project(hellorhi LANGUAGES CXX) 7 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 8 | endif() 9 | 10 | qt_internal_add_manual_test(hellorhi 11 | SOURCES 12 | hellorhi.cpp 13 | LIBRARIES 14 | Qt::Gui 15 | Qt::GuiPrivate 16 | Qt::CanvasPainter 17 | ) 18 | 19 | qt_internal_add_resource(hellorhi "hellorhi" 20 | PREFIX 21 | / 22 | FILES 23 | qt.png 24 | ) 25 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/brush4.frag: -------------------------------------------------------------------------------- 1 | #version 440 2 | 3 | QC_INCLUDE "customfrag.glsl" 4 | 5 | void main() 6 | { 7 | float a = 0.3 * sin(0.025 * fragCoord.x + 0.8 * iTime); 8 | vec4 color1 = vec4(1.0, 0.6 + a, 0.0, 1.0); 9 | vec4 color2 = data1; 10 | float a1 = 0.2 + 0.2 * sin(0.1 * fragCoord.y + 0.01 * fragCoord.x - 2.5 * iTime); 11 | float fontAlpha = sdfFontAlphaRaw(); 12 | vec4 f1 = color1 * smoothstep(a1, fontAlphaMin + a1, fontAlpha); 13 | vec4 f2 = color2 * smoothstep(fontAlphaMin, fontAlphaMax, fontAlpha); 14 | fragColor = mix(f1, f2, f2.a) * globalAlpha; 15 | // Note: Disable this if you don't want color effects to affect. 16 | applyColorEffects(fragColor); 17 | } 18 | -------------------------------------------------------------------------------- /examples/canvaspainter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | if(TARGET Qt::Gui) 5 | qt_internal_add_example(compacthealth) 6 | endif() 7 | 8 | if(TARGET Qt::Quick) 9 | qt_internal_add_example(gallery) 10 | endif() 11 | 12 | if(TARGET Qt::Widgets) 13 | qt_internal_add_example(hellowidget) 14 | endif() 15 | 16 | foreach(target IN LISTS reused_dir_targets) 17 | if(TARGET ${target}) 18 | qt_autogen_tools(${target} ENABLE_AUTOGEN_TOOLS moc rcc) 19 | if(TARGET Qt6::Widgets) 20 | qt_autogen_tools(${target} ENABLE_AUTOGEN_TOOLS uic) 21 | endif() 22 | endif() 23 | endforeach() 24 | -------------------------------------------------------------------------------- /tests/manual/itemtest/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #include 6 | #include 7 | #include 8 | #include "itemtest.h" 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | QGuiApplication app(argc, argv); 13 | 14 | #ifdef Q_OS_WIN 15 | qputenv("QT_QUICK_CONTROLS_STYLE", "FluentWinUI3"); 16 | #endif 17 | 18 | QQmlApplicationEngine engine; 19 | qmlRegisterType("HelloItem", 1, 0, "HelloItem"); 20 | engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 21 | 22 | return app.exec(); 23 | } 24 | -------------------------------------------------------------------------------- /tests/manual/hellorhi2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 5 | cmake_minimum_required(VERSION 3.16) 6 | project(hellorhi2 LANGUAGES CXX) 7 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 8 | endif() 9 | 10 | qt_internal_add_manual_test(hellorhi2 11 | SOURCES 12 | hellorhi2.cpp 13 | LIBRARIES 14 | Qt::Gui 15 | Qt::GuiPrivate 16 | Qt::Widgets 17 | Qt::CanvasPainter 18 | ) 19 | 20 | qt_add_shaders(hellorhi2 "hellorhi2_shaders" 21 | PREFIX 22 | /shaders 23 | FILES 24 | color.vert 25 | color.frag 26 | ) 27 | -------------------------------------------------------------------------------- /tests/manual/widgettest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 5 | cmake_minimum_required(VERSION 3.16) 6 | project(widgettest LANGUAGES CXX) 7 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 8 | endif() 9 | 10 | qt_internal_add_manual_test(widgettest 11 | SOURCES 12 | widgettest.cpp 13 | LIBRARIES 14 | Qt::Gui 15 | Qt::Widgets 16 | Qt::CanvasPainter 17 | ) 18 | 19 | qt_internal_add_resource(widgettest "widgettest" 20 | PREFIX 21 | / 22 | BASE 23 | ../shared 24 | FILES 25 | ../shared/quitlogo.png 26 | ) 27 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/brush3.vert: -------------------------------------------------------------------------------- 1 | #version 440 2 | 3 | QC_INCLUDE "customvert.glsl" 4 | 5 | void main() 6 | { 7 | texCoord = tcoord; 8 | fragCoord = vertex; 9 | vec2 v = (vertMatrix * vec3(vertex, 1.0)).xy; 10 | 11 | // TODO: Why something like this causes nothing to be rendered? 12 | // Some data alignment issue? 13 | //v.y += 0.0 * sin(iTime); 14 | 15 | if (ndcIsYDown != 0) 16 | gl_Position = vec4(2.0 * (v.x + viewRect.x) / viewRect.z - 1.0, -1.0 + 2.0 * (v.y + viewRect.y) / viewRect.w, 0.0, 1.0); 17 | else 18 | gl_Position = vec4(2.0 * (v.x + viewRect.x) / viewRect.z - 1.0, 1.0 - 2.0 * (v.y + viewRect.y) / viewRect.w, 0.0, 1.0); 19 | gl_Position.y += (0.05 * sin(iTime + 0.02 * fragCoord.x)); 20 | } 21 | -------------------------------------------------------------------------------- /src/canvaspainter/doc/snippets/widget-ex-1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | //![0] 5 | class MyWidget : public QCPainterWidget 6 | { 7 | public: 8 | void initializeResources(QCPainter *p) override 9 | { 10 | // load assets 11 | if (m_image.isNull()) 12 | m_image = p->addImage(QImage("image.png"), QCPainter::ImageFlag::Repeat); 13 | } 14 | 15 | void paint(QCPainter *p) override 16 | { 17 | // ... draw using m_image 18 | } 19 | 20 | void graphicsResourcesInvalidated() override 21 | { 22 | // textures are lost, indicate the need for reload 23 | m_image = {}; 24 | } 25 | 26 | QCImage m_image; 27 | }; 28 | //![0] 29 | -------------------------------------------------------------------------------- /src/canvaspainter/engine/qt_attribution.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Id": "nanovg", 4 | "Name": "NanoVG", 5 | "QDocModule": "qtcanvaspainter", 6 | "Description": "NanoVG is small antialiased vector graphics rendering library modeled after the HTML5 canvas API.", 7 | "QtUsage": "Qt Canvas Painter's renderer is based on NanoVG.", 8 | 9 | "Homepage": "https://github.com/memononen/nanovg", 10 | "PURL": [ 11 | "pkg:github/memononen/nanovg@$" 12 | ], 13 | "Comment": "No relevant CPE found", 14 | "Version": "f93799c", 15 | "License": "zlib License", 16 | "LicenseId": "Zlib", 17 | "LicenseFile": "LICENSE.NanoVG.txt", 18 | "Copyright": "Copyright (c) 2013 Mikko Mononen" 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /tools/qcshadergen/shader_includes/common.glsl: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 3 | 4 | #define PI 3.14159265359 5 | 6 | layout(std140, binding = 1) uniform fragUBuf { 7 | mat3 scissorMat; 8 | vec2 scissorExt; 9 | vec2 scissorScale; 10 | float alphaMult; 11 | float strokeThr; 12 | float fontAlphaMin; 13 | float fontAlphaMax; 14 | vec4 colorEffects; 15 | int texType; 16 | int type; 17 | // Take these into use when needed 18 | float globalAlpha; 19 | int unused1; 20 | // Custom data starts 21 | mat3 paintMat; 22 | vec4 innerCol; 23 | vec4 outerCol; 24 | vec2 extent; 25 | float radius; 26 | float feather; 27 | // Take these into use when needed 28 | vec4 unused3; 29 | }; 30 | -------------------------------------------------------------------------------- /tools/qcshadergen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | qt_get_tool_target_name(target_name qcshadergen) 5 | qt_internal_add_tool(${target_name} 6 | TOOLS_TARGET 7 | CanvasPainter 8 | SOURCES 9 | qcshadergen.cpp 10 | LIBRARIES 11 | Qt::Core 12 | EXTRA_CMAKE_FILES 13 | "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}CanvasPainterMacros.cmake" 14 | EXTRA_CMAKE_INCLUDES 15 | "${QT_CMAKE_EXPORT_NAMESPACE}CanvasPainterMacros.cmake" 16 | ) 17 | qt_internal_return_unless_building_tools() 18 | 19 | qt_add_resources(${target_name} 20 | PREFIX 21 | / 22 | BASE 23 | shader_includes 24 | FILES 25 | shader_includes/common.glsl 26 | shader_includes/customvert.glsl 27 | shader_includes/customfrag.glsl 28 | ) 29 | -------------------------------------------------------------------------------- /tests/manual/itemtest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) 5 | cmake_minimum_required(VERSION 3.16) 6 | project(itemtest LANGUAGES CXX) 7 | find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) 8 | endif() 9 | 10 | qt_internal_add_manual_test(itemtest 11 | SOURCES 12 | main.cpp 13 | itemtest.h 14 | LIBRARIES 15 | Qt::Gui 16 | Qt::Qml 17 | Qt::Quick 18 | Qt::CanvasPainter 19 | ) 20 | 21 | qt_internal_add_resource(itemtest "itemtest" 22 | PREFIX 23 | / 24 | BASE 25 | ../shared 26 | FILES 27 | ../shared/quitlogo.png 28 | ) 29 | 30 | qt_internal_add_resource(itemtest "itemtest_qml" 31 | PREFIX 32 | / 33 | FILES 34 | main.qml 35 | ) 36 | -------------------------------------------------------------------------------- /src/canvaspainter/qcconicalgradient.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCCONICALGRADIENT_H 5 | #define QCCONICALGRADIENT_H 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | QT_BEGIN_NAMESPACE 12 | 13 | class Q_CANVASPAINTER_EXPORT QCConicalGradient : public QCGradient 14 | { 15 | public: 16 | QCConicalGradient(); 17 | QCConicalGradient(float centerX, float centerY, float startAngle); 18 | QCConicalGradient(QPointF center, float startAngle); 19 | ~QCConicalGradient(); 20 | 21 | QPointF centerPosition() const; 22 | void setCenterPosition(float x, float y); 23 | void setCenterPosition(QPointF center); 24 | float angle() const; 25 | void setAngle(float angle); 26 | }; 27 | 28 | QT_END_NAMESPACE 29 | 30 | #endif // QCCONICALGRADIENT_H 31 | -------------------------------------------------------------------------------- /src/canvaspainter/engine/LICENSE.NanoVG.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Mikko Mononen memon@inside.org 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 2. Altered source versions must be plainly marked as such, and must not be 16 | misrepresented as being the original software. 17 | 3. This notice may not be removed or altered from any source distribution. 18 | 19 | -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/doc/src/qtcanvaspainter-examples-compacthealth.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \example compacthealth 6 | \ingroup canvaspainter-examples 7 | \title Qt Canvas Painter - Compact Health Example 8 | \examplecategory {Graphics} 9 | \brief Demonstrates the use of QCPainter in a QWindow. 10 | 11 | \image compacthealth-example.webp 12 | 13 | This example demonstrates using Qt Canvas Painter in a pure QWindow 14 | application. Qt Quick or QWidget are not used at all, and there is no 15 | dependency on Qt modules other than Core, Gui, and Canvas Painter. 16 | 17 | The application sets up accelerated 3D rendering using QRhi, and renders all 18 | content in the window with QCPainter. The rendering and QCPainter's 19 | integration with QRhi is managed via QCRhiPaintDriver. 20 | */ 21 | -------------------------------------------------------------------------------- /src/canvaspainter/doc/snippets/item-ex-1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | //![0] 5 | class MyItem : public QQuickCPainterItem 6 | { 7 | Q_OBJECT 8 | QML_NAMED_ELEMENT(MyItem) // exposed to QML, instantiate as MyItem { ... } 9 | 10 | // a custom property 11 | Q_PROPERTY(float value READ value WRITE setValue NOTIFY valueChanged) 12 | 13 | public: 14 | HelloItem(QQuickItem *parent = nullptr) 15 | : QQuickCPainterItem(parent) 16 | { 17 | } 18 | 19 | QQuickCPainterRenderer *createItemRenderer() const override 20 | { 21 | return new MyRenderer; 22 | } 23 | 24 | float value() const { return m_value; } 25 | void setValue(float newValue) 26 | { 27 | if (m_value != newValue) { 28 | m_value = newValue; 29 | emit valueChanged(); 30 | } 31 | } 32 | float m_value = 0.0f; 33 | }; 34 | //![0] 35 | -------------------------------------------------------------------------------- /src/canvaspainter/qcimage_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCIMAGE_P_H 5 | #define QCIMAGE_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include 19 | #include 20 | 21 | QT_BEGIN_NAMESPACE 22 | 23 | class QCImagePrivate : public QSharedData 24 | { 25 | public: 26 | QCImagePrivate(); 27 | 28 | enum class DataType { 29 | Unknown, 30 | GradientTexture, 31 | UserTexture 32 | }; 33 | 34 | int id; 35 | int width; 36 | int height; 37 | DataType type; 38 | qsizetype size; 39 | QColor tintColor; 40 | }; 41 | 42 | QT_END_NAMESPACE 43 | 44 | #endif // QCIMAGE_P_H 45 | -------------------------------------------------------------------------------- /src/canvaspainter/engine/qcpainter.vert: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #version 440 5 | 6 | QC_INCLUDE "common.glsl" 7 | 8 | layout(location = 0) in vec2 vertex; 9 | layout(location = 1) in vec2 tcoord; 10 | layout(location = 0) out vec2 texCoord; 11 | layout(location = 1) out vec2 fragCoord; 12 | 13 | layout(std140, binding = 0) uniform vertUBuf { 14 | vec4 viewRect; 15 | int ndcIsYDown; 16 | }; 17 | 18 | layout(std140, binding = 4) uniform vertUBuf2 { 19 | mat3 vertMatrix; 20 | }; 21 | 22 | void main() 23 | { 24 | texCoord = tcoord; 25 | fragCoord = vertex; 26 | vec2 v = (vertMatrix * vec3(vertex, 1.0)).xy; 27 | if (ndcIsYDown != 0) 28 | gl_Position = vec4(2.0 * (v.x + viewRect.x) / viewRect.z - 1.0, -1.0 + 2.0 * (v.y + viewRect.y) / viewRect.w, 0.0, 1.0); 29 | else 30 | gl_Position = vec4(2.0 * (v.x + viewRect.x) / viewRect.z - 1.0, 1.0 - 2.0 * (v.y + viewRect.y) / viewRect.w, 0.0, 1.0); 31 | } 32 | -------------------------------------------------------------------------------- /src/canvaspainter/qclineargradient.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef QCLINEARGRADIENT_H 6 | #define QCLINEARGRADIENT_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | 14 | class Q_CANVASPAINTER_EXPORT QCLinearGradient : public QCGradient 15 | { 16 | public: 17 | QCLinearGradient(); 18 | QCLinearGradient(float startX, float startY, float endX, float endY); 19 | QCLinearGradient(QPointF start, QPointF end); 20 | ~QCLinearGradient(); 21 | 22 | QPointF startPosition() const; 23 | void setStartPosition(float x, float y); 24 | void setStartPosition(QPointF start); 25 | QPointF endPosition() const; 26 | void setEndPosition(float x, float y); 27 | void setEndPosition(QPointF end); 28 | }; 29 | 30 | QT_END_NAMESPACE 31 | 32 | #endif // QCLINEARGRADIENT_H 33 | -------------------------------------------------------------------------------- /LICENSES/Qt-GPL-exception-1.0.txt: -------------------------------------------------------------------------------- 1 | The Qt Company GPL Exception 1.0 2 | 3 | Exception 1: 4 | 5 | As a special exception you may create a larger work which contains the 6 | output of this application and distribute that work under terms of your 7 | choice, so long as the work is not otherwise derived from or based on 8 | this application and so long as the work does not in itself generate 9 | output that contains the output from this application in its original 10 | or modified form. 11 | 12 | Exception 2: 13 | 14 | As a special exception, you have permission to combine this application 15 | with Plugins licensed under the terms of your choice, to produce an 16 | executable, and to copy and distribute the resulting executable under 17 | the terms of your choice. However, the executable must be accompanied 18 | by a prominent notice offering all users of the executable the entire 19 | source code to this application, excluding the source code of the 20 | independent modules, but including any changes you have made to this 21 | application, under the terms of this license. 22 | 23 | -------------------------------------------------------------------------------- /src/canvaspainter/qcbrush_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCBRUSH_P_H 5 | #define QCBRUSH_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include "qcbrush.h" 19 | 20 | QT_BEGIN_NAMESPACE 21 | 22 | class QCBrushPrivate : public QSharedData 23 | { 24 | public: 25 | QCBrushPrivate(QCBrush::BrushType t) : type(t) {} 26 | virtual ~QCBrushPrivate() = default; 27 | QCBrush::BrushType type; 28 | virtual QCBrushPrivate *clone() = 0; 29 | virtual QCPaint createPaint(QCPainter *painter) const = 0; 30 | }; 31 | 32 | template <> 33 | inline QCBrushPrivate *QExplicitlySharedDataPointer::clone() 34 | { 35 | return d ? d->clone() : nullptr; 36 | } 37 | 38 | QT_END_NAMESPACE 39 | 40 | #endif // QCBRUSH_P_H 41 | -------------------------------------------------------------------------------- /src/canvaspainter/qcboxgradient.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef QCBOXGRADIENT_H 6 | #define QCBOXGRADIENT_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | 14 | class Q_CANVASPAINTER_EXPORT QCBoxGradient : public QCGradient 15 | { 16 | public: 17 | QCBoxGradient(); 18 | QCBoxGradient(float x, float y, float width, float height, float feather, float radius = 0.0f); 19 | QCBoxGradient(const QRectF &rect, float feather, float radius = 0.0f); 20 | ~QCBoxGradient(); 21 | 22 | QRectF rect() const; 23 | void setRect(float x, float y, float width, float height); 24 | void setRect(const QRectF &rect); 25 | float feather() const; 26 | void setFeather(float feather); 27 | float radius() const; 28 | void setRadius(float radius); 29 | }; 30 | 31 | QT_END_NAMESPACE 32 | 33 | #endif // QCBOXGRADIENT_H 34 | -------------------------------------------------------------------------------- /src/canvaspainter/doc/snippets/widget-canvas-ex-1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | //![0] 5 | class MyWidget : public QCPainterWidget 6 | { 7 | public: 8 | QCOffscreenCanvas canvas; 9 | QCImage canvasImage; 10 | 11 | void graphicsResourcesInvalidated() override 12 | { 13 | canvas = {}; // so that the next prePaint() will recreate and redraw the canvas 14 | } 15 | 16 | void prePaint(QCPainter *p) override 17 | { 18 | if (canvas.isNull()) { 19 | canvas = p->createCanvas(QSize(320, 240)); 20 | beginCanvasPainting(canvas); 21 | p->beginPath(); 22 | p->circle(160, 120, 20); 23 | p->setFillStyle(Qt::red); 24 | p->fill(); 25 | endCanvasPainting(); 26 | canvasImage = p->addImage(canvas, QCPainter::ImageFlag::Repeat); 27 | } 28 | } 29 | 30 | void paint(QCPainter *p) override 31 | { 32 | // use canvasImage as a brush or with drawImage() 33 | } 34 | }; 35 | //![0] 36 | -------------------------------------------------------------------------------- /src/canvaspainter/qcpainterfactory_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCPAINTERFACTORY_P_H 5 | #define QCPAINTERFACTORY_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include "qcpainterfactory.h" 19 | #include "qcrhipaintdriver.h" 20 | #include "engine/qcpainterrhirenderer_p.h" 21 | 22 | QT_BEGIN_NAMESPACE 23 | 24 | class QCPainterFactoryPrivate 25 | { 26 | public: 27 | static const QCPainterFactoryPrivate *get(const QCPainterFactory *obj) { return obj->d; } 28 | static QCPainterFactoryPrivate *get(QCPainterFactory *obj) { return obj->d; } 29 | 30 | std::unique_ptr paintDriver; 31 | std::unique_ptr painter; 32 | QCPainterRhiRenderer renderer; 33 | }; 34 | 35 | QT_END_NAMESPACE 36 | 37 | #endif // QCPAINTERFACTORY_P_H 38 | -------------------------------------------------------------------------------- /src/canvaspainter/qcoffscreencanvas_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCOFFSCREENCANVAS_P_H 5 | #define QCOFFSCREENCANVAS_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include 19 | #include 20 | #include "qcoffscreencanvas.h" 21 | #include "engine/qcpainterrhirenderer_p.h" 22 | 23 | QT_BEGIN_NAMESPACE 24 | 25 | class QCOffscreenCanvasPrivate : public QSharedData 26 | { 27 | public: 28 | static QCOffscreenCanvasPrivate *get(QCOffscreenCanvas *canvas) { return canvas->d.get(); } 29 | static const QCOffscreenCanvasPrivate *get(const QCOffscreenCanvas *canvas) { return canvas->d.get(); } 30 | 31 | QCRhiCanvas rhiCanvas; 32 | QColor fillColor = {0, 0, 0, 0}; 33 | }; 34 | 35 | QT_END_NAMESPACE 36 | 37 | #endif // QCOFFSCREENCANVAS_P_H 38 | -------------------------------------------------------------------------------- /src/canvaspainter/qcradialgradient.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef QCRADIALGRADIENT_H 6 | #define QCRADIALGRADIENT_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | 14 | class Q_CANVASPAINTER_EXPORT QCRadialGradient : public QCGradient 15 | { 16 | public: 17 | QCRadialGradient(); 18 | QCRadialGradient(float centerX, float centerY, float outerRadius, float innerRadius = 0.0f); 19 | QCRadialGradient(QPointF center, float outerRadius, float innerRadius = 0.0f); 20 | ~QCRadialGradient(); 21 | 22 | QPointF centerPosition() const; 23 | void setCenterPosition(float x, float y); 24 | void setCenterPosition(QPointF center); 25 | float outerRadius() const; 26 | void setOuterRadius(float radius); 27 | float innerRadius() const; 28 | void setInnerRadius(float radius); 29 | }; 30 | 31 | QT_END_NAMESPACE 32 | 33 | #endif // QCRADIALGRADIENT_H 34 | -------------------------------------------------------------------------------- /src/canvaspainter/qcdebug_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2018 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef QCDEBUG_H 6 | #define QCDEBUG_H 7 | 8 | // 9 | // W A R N I N G 10 | // ------------- 11 | // 12 | // This file is not part of the Qt API. It exists purely as an 13 | // implementation detail. This header file may change from version to 14 | // version without notice, or even be removed. 15 | // 16 | // We mean it. 17 | // 18 | 19 | #include "engine/qcpainterengineutils_p.h" 20 | #include "qcpainter.h" 21 | #include 22 | #include 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QCDebug 27 | { 28 | public: 29 | QCDebug(); 30 | void start(); 31 | void paintDrawDebug(QCPainter *painter, float width, float height); 32 | 33 | private: 34 | QCDrawDebug m_drawDebug; 35 | QElapsedTimer m_debugTimer; 36 | QElapsedTimer m_debugUpdateTimer; 37 | qint64 m_debugNsElapsed; 38 | qint64 m_debugCounter; 39 | QString m_debugMsElapsed; 40 | }; 41 | 42 | QT_END_NAMESPACE 43 | 44 | #endif // QCDEBUG_H 45 | -------------------------------------------------------------------------------- /src/canvaspainter/qquickcpainteritem_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCQUICKITEM_P_H 5 | #define QCQUICKITEM_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include "qquickcpainteritem.h" 19 | #include 20 | #include 21 | 22 | QT_BEGIN_NAMESPACE 23 | 24 | struct QCDrawDebug; 25 | 26 | class QQuickCPainterItemPrivate : public QQuickRhiItemPrivate 27 | { 28 | Q_DECLARE_PUBLIC(QQuickCPainterItem) 29 | public: 30 | void updateDebugData(QCDrawDebug drawDebug); 31 | void updateDebug(); 32 | 33 | QQuickCPainterRenderer *m_renderer = nullptr; 34 | QColor m_fillColor = Qt::black; 35 | QVariantMap m_debug; 36 | QTimer m_debugUpdateTimer; 37 | bool m_debugDataChanged = false; 38 | }; 39 | 40 | QT_END_NAMESPACE 41 | 42 | #endif // QCQUICKITEM_P_H 43 | -------------------------------------------------------------------------------- /tools/qcshadergen/shader_includes/customvert.glsl: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 3 | 4 | layout(location = 0) in vec2 vertex; 5 | layout(location = 1) in vec2 tcoord; 6 | layout(location = 0) out vec2 texCoord; 7 | layout(location = 1) out vec2 fragCoord; 8 | 9 | layout(std140, binding = 0) uniform vertUBuf { 10 | vec4 viewRect; 11 | int ndcIsYDown; 12 | }; 13 | 14 | layout(std140, binding = 4) uniform vertUBuf2 { 15 | mat3 vertMatrix; 16 | }; 17 | 18 | // Custom brushes use binding 1 19 | layout(std140, binding = 1) uniform commonUBuf { 20 | mat3 scissorMat; 21 | vec2 scissorExt; 22 | vec2 scissorScale; 23 | float alphaMult; 24 | float strokeThr; 25 | float fontAlphaMin; 26 | float fontAlphaMax; 27 | vec4 colorEffects; 28 | int texType; 29 | int type; 30 | float globalAlpha; 31 | int unused1; 32 | // Custom input 33 | float iTime; 34 | int alphaIsRed; 35 | float unused2; 36 | float unused3; 37 | vec4 data1; 38 | vec4 data2; 39 | vec4 data3; 40 | vec4 data4; 41 | vec4 unused4[2]; 42 | }; 43 | -------------------------------------------------------------------------------- /coin/axivion/ci_config_linux.json: -------------------------------------------------------------------------------- 1 | { 2 | "Project": { 3 | "BuildSystemIntegration": { 4 | "child_order": [ 5 | "GCCSetup", 6 | "CMake", 7 | "LinkLibraries" 8 | ] 9 | }, 10 | "CMake": { 11 | "_active": true, 12 | "_copy_from": "CMakeIntegration", 13 | "build_environment": {}, 14 | "build_options": "-j4", 15 | "generate_options": "--fresh", 16 | "generator": "Ninja" 17 | }, 18 | "GCCSetup": { 19 | "_active": true, 20 | "_copy_from": "Command", 21 | "build_command": "gccsetup --cc gcc --cxx g++ --config ../../../axivion/" 22 | }, 23 | "LinkLibraries": { 24 | "_active": true, 25 | "_copy_from": "AxivionLinker", 26 | "input_files": [ 27 | "build/lib/lib*.so*.ir" 28 | ], 29 | "ir": "build/$(env:TESTED_MODULE_COIN).ir" 30 | } 31 | }, 32 | "_Format": "1.0", 33 | "_Version": "7.6.2", 34 | "_VersionNum": [ 35 | 7, 36 | 6, 37 | 2, 38 | 12725 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/brush2.frag: -------------------------------------------------------------------------------- 1 | #version 440 2 | 3 | QC_INCLUDE "customfrag.glsl" 4 | 5 | void main() 6 | { 7 | //vec4 plasmaColors = vec4(1.0, 0.0, 0.0, 1.0); 8 | vec4 plasmaColors = data1; 9 | // These could also be taken from data inputs 10 | float plasmaScale = 0.1; 11 | float time = iTime * 0.1; 12 | vec2 resolution = vec2(400, 400); 13 | vec2 a = vec2(resolution.x / resolution.y, 1.0); 14 | vec2 c = 0.01 * fragCoord.xy * a * 2.0 + time * 0.45; 15 | float k = 0.25 + cos(c.y + sin(.148 - time)) + 3.2 * time; 16 | float w = 0.9 + sin(c.x + cos(.628 + time)) - 1.2 * time; 17 | float d = length(c); 18 | float s = (2.0 / (plasmaScale + 0.02)) * cos(d+w) * sin(k+w); 19 | vec4 plasma = vec4(0.5 + 0.5 * cos(s + plasmaColors.rgb), 1.0); 20 | // Note: If you don't need clipping support, remove clipMask(). 21 | // Note: If you don't need antialiasing support, remove antialiasingAlpha(). 22 | //fragColor = plasma * globalAlpha * antialiasingAlpha() * clipMask(); 23 | fragColor = plasma * globalAlpha * antialiasingAlpha(); 24 | 25 | // Note: Disable this if you don't want color effects to affect. 26 | applyColorEffects(fragColor); 27 | } 28 | -------------------------------------------------------------------------------- /examples/canvaspainter/hellowidget/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | project(hellowidget LANGUAGES CXX) 6 | 7 | find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets CanvasPainter) 8 | 9 | qt_standard_project_setup(REQUIRES 6.11) 10 | 11 | qt_add_executable(canvaspainterhellowidget 12 | WIN32 13 | MACOSX_BUNDLE 14 | main.cpp 15 | canvaswidget.cpp canvaswidget.h 16 | ) 17 | 18 | target_link_libraries(canvaspainterhellowidget PRIVATE 19 | Qt6::Core 20 | Qt6::Gui 21 | Qt6::Widgets 22 | Qt6::CanvasPainter 23 | ) 24 | 25 | qt_add_resources(canvaspainterhellowidget "canvaspainterhellowidget" 26 | PREFIX 27 | / 28 | FILES 29 | qt-translucent.png 30 | ) 31 | 32 | install(TARGETS canvaspainterhellowidget 33 | BUNDLE DESTINATION . 34 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 35 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 36 | ) 37 | 38 | qt_generate_deploy_app_script( 39 | TARGET canvaspainterhellowidget 40 | OUTPUT_SCRIPT deploy_script 41 | NO_UNSUPPORTED_PLATFORM_ERROR 42 | ) 43 | install(SCRIPT ${deploy_script}) 44 | -------------------------------------------------------------------------------- /src/canvaspainter/qcpainterwidget_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCPAINTERWIDGET_P_H 5 | #define QCPAINTERWIDGET_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include 19 | #include "qcpainterwidget.h" 20 | #include "engine/qcpainterengineutils_p.h" 21 | #include "qcdebug_p.h" 22 | #include 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QCPainterFactory; 27 | 28 | class QCPainterWidgetPrivate : public QRhiWidgetPrivate 29 | { 30 | Q_DECLARE_PUBLIC(QCPainterWidget) 31 | 32 | public: 33 | bool m_sharedPainter = true; 34 | QCPainterFactory *m_factory = nullptr; 35 | QColor m_fillColor = Qt::black; 36 | QCDebug m_debug; 37 | bool m_firstRender = true; 38 | QRhiCommandBuffer *m_currentCb = nullptr; 39 | static QAtomicInt m_rendered; 40 | }; 41 | 42 | QT_END_NAMESPACE 43 | 44 | #endif // QCPAINTERWIDGET_P_H 45 | -------------------------------------------------------------------------------- /tests/manual/widgettest/widgettest.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #include 5 | #include 6 | #include "widgettest.h" 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | QApplication app(argc, argv); 11 | 12 | HelloWidget *widget = new HelloWidget; 13 | widget->resize(400, 400); 14 | 15 | QWidget *tlw = nullptr; 16 | 17 | QPushButton *btn = new QPushButton("Make it a child widget", widget); 18 | QObject::connect(btn, &QPushButton::clicked, widget, [&] { 19 | if (!tlw) { 20 | btn->setText("Make it a top-level"); 21 | tlw = new QWidget; 22 | tlw->resize(600, 600); 23 | widget->setParent(tlw); 24 | widget->move(0, 0); // why is this needed? 25 | widget->show(); 26 | tlw->show(); 27 | widget->update(); 28 | } else { 29 | btn->setText("Make it a child widget"); 30 | widget->setParent(nullptr); 31 | widget->show(); 32 | delete tlw; 33 | tlw = nullptr; 34 | } 35 | }); 36 | 37 | widget->show(); 38 | 39 | int r = app.exec(); 40 | 41 | if (!widget->parent()) 42 | delete widget; 43 | 44 | return r; 45 | } 46 | -------------------------------------------------------------------------------- /src/canvaspainter/qcrhipaintdriver_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCRHIPAINTPAINTDRIVER_P_H 5 | #define QCRHIPAINTPAINTDRIVER_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include "qcrhipaintdriver.h" 19 | #include "engine/qcpainterrhirenderer_p.h" 20 | #include 21 | 22 | QT_BEGIN_NAMESPACE 23 | 24 | class QCRhiPaintDriverPrivate 25 | { 26 | public: 27 | static const QCRhiPaintDriverPrivate *get(const QCRhiPaintDriver *obj) { return obj->d; } 28 | static QCRhiPaintDriverPrivate *get(QCRhiPaintDriver *obj) { return obj->d; } 29 | 30 | QCPainter *painter = nullptr; 31 | QCPainterRhiRenderer *renderer = nullptr; 32 | QRhiCommandBuffer *currentCb = nullptr; 33 | QRhiRenderTarget *currentRt = nullptr; 34 | float mainLogicalWidth = 0.0f; 35 | float mainLogicalHeight = 0.0f; 36 | float mainDpr = 1.0f; 37 | QColor mainFillColor; 38 | QCOffscreenCanvas currentCanvas; 39 | }; 40 | 41 | QT_END_NAMESPACE 42 | 43 | #endif // QCRHIPAINTPAINTDRIVER_P_H 44 | -------------------------------------------------------------------------------- /src/canvaspainter/qcpainterfactory.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2018 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef QCPAINTERFACTORY_H 6 | #define QCPAINTERFACTORY_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | class QCPainter; 16 | class QCPainterFactoryPrivate; 17 | class QCRhiPaintDriver; 18 | class QRhi; 19 | 20 | // A factory owns a set of painter (+ engine) + renderer. 21 | // 22 | // sharedInstance possibly returns an already initialized factory with all 23 | // these, if it was called for the same QRhi before. 24 | 25 | class Q_CANVASPAINTER_EXPORT QCPainterFactory 26 | { 27 | public: 28 | QCPainterFactory(); 29 | ~QCPainterFactory(); 30 | 31 | static QCPainterFactory *sharedInstance(QRhi *rhi); 32 | 33 | bool isValid() const; 34 | QCPainter *create(QRhi *rhi); 35 | void destroy(); 36 | QCPainter *painter(); 37 | 38 | QCRhiPaintDriver *paintDriver(); 39 | 40 | private: 41 | Q_DISABLE_COPY(QCPainterFactory) 42 | QCPainterFactoryPrivate *d = nullptr; 43 | friend class QCPainterFactoryPrivate; 44 | }; 45 | 46 | QT_END_NAMESPACE 47 | 48 | #endif // QCPAINTERFACTORY_H 49 | -------------------------------------------------------------------------------- /tests/manual/widgettest/widgettest.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef WIDGETTEST_H 5 | #define WIDGETTEST_H 6 | 7 | #include "qcpainterwidget.h" 8 | #include "qcpainter.h" 9 | #include "../shared/painthelper.h" 10 | 11 | class HelloWidget : public QCPainterWidget 12 | { 13 | 14 | public: 15 | HelloWidget() 16 | { 17 | setFillColor("#000000"); 18 | } 19 | 20 | void initializeResources(QCPainter *p) override 21 | { 22 | // Provide our own QCImage, to verify that a "load-if-not-yet-done" 23 | // logic works as expected, and it does not break down when the widget 24 | // is moved between windows (and so changes QRhis, losing all graphics 25 | // resources in the process). 26 | static QImage logoImage(":/quitlogo.png"); 27 | if (logo.isNull()) 28 | logo = p->addImage(logoImage, QCPainter::ImageFlag::Repeat); 29 | } 30 | 31 | void paint(QCPainter *p) override 32 | { 33 | paintHelloItem(p, width(), height(), &logo); 34 | } 35 | 36 | QCImage logo; 37 | 38 | void graphicsResourcesInvalidated() override 39 | { 40 | qWarning("graphicsResourcesInvalidated"); 41 | 42 | logo = {}; // textures are lost, indicate the need for reload 43 | } 44 | }; 45 | 46 | #endif // WIDGETTEST_H 47 | -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/theme.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #ifndef THEME_H 5 | #define THEME_H 6 | 7 | #include 8 | #include "qclineargradient.h" 9 | 10 | class Theme 11 | { 12 | public: 13 | Theme(); 14 | void switchTheme(); 15 | bool isDark() const; 16 | QColor background1() const; 17 | QColor background2() const; 18 | QColor foreground1() const; 19 | QColor foreground2() const; 20 | QColor foreground3() const; 21 | QColor highlight() const; 22 | QColor warning() const; 23 | QColor graph1() const; 24 | QColor graph2() const; 25 | QCLinearGradient gradient1() const; 26 | QCLinearGradient gradient2() const; 27 | 28 | private: 29 | 30 | void initThemes(); 31 | 32 | struct ThemeVars { 33 | QColor background1; 34 | QColor background2; 35 | QColor foreground1; 36 | QColor foreground2; 37 | QColor foreground3; 38 | QColor highlight; 39 | QColor warning; 40 | QColor graph1; 41 | QColor graph2; 42 | QCLinearGradient gradient1; 43 | QCLinearGradient gradient2; 44 | }; 45 | 46 | ThemeVars m_theme; 47 | ThemeVars m_previousTheme; 48 | ThemeVars m_darkTheme; 49 | ThemeVars m_lightTheme; 50 | bool m_isDarkTheme = true; 51 | }; 52 | 53 | #endif // THEME_H 54 | -------------------------------------------------------------------------------- /src/canvaspainter/engine/qcareaallocator_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCAREAALLOCATOR_H 5 | #define QCAREAALLOCATOR_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists for the convenience 12 | // of other Qt classes. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | // 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | QT_BEGIN_NAMESPACE 24 | 25 | struct QCAreaAllocatorNode; 26 | class Qpoint; 27 | 28 | class QCAreaAllocator 29 | { 30 | public: 31 | QCAreaAllocator(QSize size); 32 | ~QCAreaAllocator(); 33 | 34 | QRect allocate(QSize size); 35 | bool deallocate(QRect rect); 36 | bool isEmpty() const { return m_root == nullptr; } 37 | QSize size() const { return m_size; } 38 | 39 | private: 40 | bool allocateInNode( 41 | QSize size, QPoint &result, QRect currentRect, QCAreaAllocatorNode *node); 42 | bool deallocateInNode(QPoint pos, QCAreaAllocatorNode *node); 43 | void mergeNodeWithNeighbors(QCAreaAllocatorNode *node); 44 | 45 | QCAreaAllocatorNode *m_root = nullptr; 46 | QSize m_size; 47 | }; 48 | 49 | QT_END_NAMESPACE 50 | 51 | #endif // QCAREAALLOCATOR_H 52 | -------------------------------------------------------------------------------- /src/canvaspainter/doc/snippets/renderer-ex-1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | //![0] 5 | class MyRenderer : public QQuickCPainterRenderer 6 | { 7 | public: 8 | void synchronize(QQuickCPainterItem *item) override 9 | { 10 | // copy a custom property value from item in a thread-safe manner 11 | m_value = static_cast(item)->value(); 12 | } 13 | 14 | void initializeResources(QCPainter *p) override 15 | { 16 | // load assets 17 | if (m_image.isNull()) 18 | m_image = p->addImage(QImage("image.png"), QCPainter::ImageFlag::Repeat); 19 | } 20 | 21 | void prePaint(QCPainter *p) override 22 | { 23 | // this is where offscreen canvases are drawn into 24 | if (m_canvas.isNull()) { 25 | m_canvas = p->createCanvas(QSize(640, 480)); 26 | beginCanvasPainting(m_canvas); 27 | // ... draw into the offscreen canvas 28 | endCanvasPainting(m_canvas); 29 | m_canvasImage = p->addImage(m_canvas); 30 | } 31 | } 32 | 33 | void paint(QCPainter *p) override 34 | { 35 | QPointF center(width() / 2, height() / 2); 36 | // ... draw using m_value, m_image, and m_canvasImage 37 | } 38 | 39 | QCImage m_image; 40 | QCOffscreenCanvas m_canvas; 41 | QCImage m_canvasImage; 42 | float m_value; 43 | }; 44 | //![0] 45 | -------------------------------------------------------------------------------- /LICENSES/BSD-3-Clause.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) . 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 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. 7 | 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. 8 | 9 | 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. 10 | -------------------------------------------------------------------------------- /src/canvaspainter/qquickcpainteritem.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef QCQUICKITEM_H 6 | #define QCQUICKITEM_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | class QQuickCPainterRenderer; 18 | class QQuickCPainterItemPrivate; 19 | 20 | class Q_CANVASPAINTER_EXPORT QQuickCPainterItem : public QQuickRhiItem 21 | { 22 | Q_OBJECT 23 | Q_PROPERTY(QColor fillColor READ fillColor WRITE setFillColor NOTIFY fillColorChanged FINAL) 24 | Q_PROPERTY(QVariantMap debug READ debug NOTIFY debugChanged FINAL) 25 | 26 | public: 27 | 28 | QQuickCPainterItem(QQuickItem *parent = nullptr); 29 | ~QQuickCPainterItem() override; 30 | 31 | QColor fillColor() const; 32 | void setFillColor(const QColor &color); 33 | 34 | QVariantMap debug(); 35 | 36 | protected: 37 | virtual QQuickCPainterRenderer* createItemRenderer() const = 0; 38 | 39 | QQuickRhiItemRenderer *createRenderer() final; 40 | 41 | Q_SIGNALS: 42 | void fillColorChanged(); 43 | void debugChanged(); 44 | 45 | private: 46 | friend class QQuickCPainterRenderer; 47 | Q_DECLARE_PRIVATE(QQuickCPainterItem) 48 | }; 49 | 50 | QT_END_NAMESPACE 51 | 52 | #endif // QCQUICKITEM_H 53 | -------------------------------------------------------------------------------- /LICENSES/Zlib.txt: -------------------------------------------------------------------------------- 1 | This software is provided 'as-is', without any express or implied 2 | warranty. In no event will the authors be held liable for any damages 3 | arising from the use of this software. 4 | 5 | Permission is granted to anyone to use this software for any purpose, 6 | including commercial applications, and to alter it and redistribute it 7 | freely, subject to the following restrictions: 8 | 9 | 1. The origin of this software must not be misrepresented; you must not 10 | claim that you wrote the original software. If you use this software 11 | in a product, an acknowledgment in the product documentation would be 12 | appreciated but is not required. 13 | 2. Altered source versions must be plainly marked as such, and must not be 14 | misrepresented as being the original software. 15 | 3. This notice may not be removed or altered from any source distribution. 16 | 17 | Jean-loup Gailly Mark Adler 18 | jloup@gzip.org madler@alumni.caltech.edu 19 | 20 | If you use the zlib library in a product, we would appreciate *not* receiving 21 | lengthy legal documents to sign. The sources are provided for free but without 22 | warranty of any kind. The library has been entirely written by Jean-loup 23 | Gailly and Mark Adler; it does not include third-party code. 24 | 25 | If you redistribute modified sources, we would appreciate that you include in 26 | the file ChangeLog history information documenting your changes. Please read 27 | the FAQ for more information on the distribution of modified source versions. 28 | 29 | -------------------------------------------------------------------------------- /examples/canvaspainter/hellowidget/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "canvaswidget.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | class MainWindow : public QMainWindow 16 | { 17 | public: 18 | MainWindow(); 19 | 20 | private: 21 | void createCanvasWidget(); 22 | 23 | QMdiArea *mdi; 24 | }; 25 | 26 | MainWindow::MainWindow() 27 | { 28 | mdi = new QMdiArea; 29 | setCentralWidget(mdi); 30 | 31 | createCanvasWidget(); 32 | 33 | QMenu *fileMenu = menuBar()->addMenu(tr("&File")); 34 | fileMenu->addAction(tr("&New widget"), 35 | QKeySequence(QKeySequence::StandardKey::New), 36 | this, &MainWindow::createCanvasWidget); 37 | fileMenu->addAction(tr("E&xit"), 38 | QKeySequence(QKeySequence::StandardKey::Quit), 39 | qApp, &QCoreApplication::quit); 40 | } 41 | 42 | void MainWindow::createCanvasWidget() 43 | { 44 | CanvasWidget *canvasWidget = new CanvasWidget; 45 | mdi->addSubWindow(canvasWidget)->resize(500, 500); 46 | canvasWidget->show(); 47 | } 48 | 49 | int main(int argc, char *argv[]) 50 | { 51 | QApplication app(argc, argv); 52 | 53 | MainWindow mainWindow; 54 | mainWindow.resize(1280, 720); 55 | mainWindow.show(); 56 | 57 | return QCoreApplication::exec(); 58 | } 59 | -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | project(compacthealth LANGUAGES CXX) 6 | 7 | find_package(Qt6 REQUIRED COMPONENTS Core Gui CanvasPainter OPTIONAL_COMPONENTS GuiPrivate) 8 | 9 | qt_standard_project_setup(REQUIRES 6.11) 10 | 11 | qt_add_executable(compacthealthexample 12 | WIN32 13 | MACOSX_BUNDLE 14 | main.cpp 15 | painterwindow.cpp painterwindow.h 16 | mainwindow.cpp mainwindow.h 17 | ecggraph.cpp ecggraph.h 18 | theme.h theme.cpp 19 | ) 20 | 21 | target_link_libraries(compacthealthexample PRIVATE 22 | Qt6::Core 23 | Qt6::Gui 24 | Qt6::GuiPrivate 25 | Qt6::CanvasPainter 26 | ) 27 | 28 | qt_add_resources(compacthealthexample "compacthealthexample" 29 | PREFIX 30 | / 31 | FILES 32 | images/icon_random_dark.png 33 | images/icon_random_light.png 34 | images/icon_theme_dark.png 35 | images/icon_theme_light.png 36 | images/icon_run_dark.png 37 | images/icon_run_light.png 38 | images/icon_settings_dark.png 39 | images/icon_settings_light.png 40 | ) 41 | 42 | install(TARGETS compacthealthexample 43 | BUNDLE DESTINATION . 44 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 45 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 46 | ) 47 | 48 | qt_generate_deploy_app_script( 49 | TARGET compacthealthexample 50 | OUTPUT_SCRIPT deploy_script 51 | NO_UNSUPPORTED_PLATFORM_ERROR 52 | ) 53 | install(SCRIPT ${deploy_script}) 54 | -------------------------------------------------------------------------------- /src/canvaspainter/qcrhipaintdriver.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2018 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef QCRHIPAINTPAINTDRIVER_H 6 | #define QCRHIPAINTPAINTDRIVER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | class QRhi; 16 | class QRhiCommandBuffer; 17 | class QRhiRenderTarget; 18 | class QCRhiPaintDriverPrivate; 19 | 20 | class Q_CANVASPAINTER_EXPORT QCRhiPaintDriver 21 | { 22 | public: 23 | enum class EndPaintFlag { 24 | DoNotRecordRenderPass = 0x01 25 | }; 26 | Q_DECLARE_FLAGS(EndPaintFlags, EndPaintFlag) 27 | 28 | QCRhiPaintDriver(); 29 | ~QCRhiPaintDriver(); 30 | 31 | void resetForNewFrame(); 32 | void beginPaint(QRhiCommandBuffer *cb, QRhiRenderTarget *rt, const QColor &fillColor = Qt::black, QSize logicalSize = QSize(), float dpr = 1.0f); 33 | void beginPaint(QCOffscreenCanvas &canvas, QRhiCommandBuffer *cb); 34 | void endPaint(EndPaintFlags flags = {}); 35 | void renderPaint(); 36 | void grabCanvas(const QCOffscreenCanvas &canvas, std::function callback); 37 | 38 | private: 39 | Q_DISABLE_COPY(QCRhiPaintDriver) 40 | QCRhiPaintDriverPrivate *d = nullptr; 41 | friend class QCRhiPaintDriverPrivate; 42 | }; 43 | 44 | Q_DECLARE_OPERATORS_FOR_FLAGS(QCRhiPaintDriver::EndPaintFlags) 45 | 46 | QT_END_NAMESPACE 47 | 48 | #endif // QCRHIPAINTPAINTDRIVER_H 49 | -------------------------------------------------------------------------------- /src/canvaspainter/qccustombrush.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCCUSTOMBRUSH_H 5 | #define QCCUSTOMBRUSH_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | class QCCustomBrushPrivate; 16 | class QCCustomBrush; 17 | struct FragUniforms; 18 | 19 | // TODO: Should this have QDataStream support? 20 | 21 | class Q_CANVASPAINTER_EXPORT QCCustomBrush : public QCBrush 22 | { 23 | public: 24 | QCCustomBrush(); 25 | QCCustomBrush(const QString &fragmentShader, 26 | const QString &vertexShader); 27 | ~QCCustomBrush(); 28 | 29 | bool operator==(const QCCustomBrush &brush) const; 30 | inline bool operator!=(const QCCustomBrush &brush) const { return !(operator==(brush)); } 31 | operator QVariant() const; 32 | 33 | void setFragmentShader(const QString &fragmentShader); 34 | void setVertexShader(const QString &vertexShader); 35 | 36 | bool timeRunning() const; 37 | void setTimeRunning(bool running); 38 | 39 | void setData1(const QVector4D &data); 40 | void setData2(const QVector4D &data); 41 | void setData3(const QVector4D &data); 42 | void setData4(const QVector4D &data); 43 | 44 | private: 45 | friend class QCCustomBrushPrivate; 46 | }; 47 | 48 | #ifndef QT_NO_DEBUG_STREAM 49 | Q_CANVASPAINTER_EXPORT QDebug operator<<(QDebug, const QCCustomBrush &); 50 | #endif 51 | 52 | QT_END_NAMESPACE 53 | 54 | #endif // QCCUSTOMBRUSH_H 55 | -------------------------------------------------------------------------------- /src/canvaspainter/qcpainterwidget.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2018 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef QCPAINTERWIDGET_H 6 | #define QCPAINTERWIDGET_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | QT_BEGIN_NAMESPACE 15 | 16 | class QCPainter; 17 | class QCPainterWidgetPrivate; 18 | 19 | class Q_CANVASPAINTER_EXPORT QCPainterWidget : public QRhiWidget 20 | { 21 | Q_OBJECT 22 | public: 23 | explicit QCPainterWidget(QWidget *parent = nullptr); 24 | ~QCPainterWidget() override; 25 | 26 | QColor fillColor() const; 27 | void setFillColor(const QColor &color); 28 | 29 | bool hasSharedPainter() const; 30 | void setSharedPainter(bool enable); 31 | 32 | void grabCanvas(const QCOffscreenCanvas &canvas, std::function callback); 33 | 34 | protected: 35 | virtual void initializeResources(QCPainter *painter); 36 | virtual void prePaint(QCPainter *painter); 37 | virtual void paint(QCPainter *painter); 38 | virtual void graphicsResourcesInvalidated(); 39 | 40 | void initialize(QRhiCommandBuffer *cb) override; 41 | void render(QRhiCommandBuffer *cb) override; 42 | void releaseResources() override; 43 | 44 | void beginCanvasPainting(QCOffscreenCanvas &canvas); 45 | void endCanvasPainting(); 46 | 47 | private: 48 | Q_DECLARE_PRIVATE(QCPainterWidget) 49 | }; 50 | 51 | QT_END_NAMESPACE 52 | 53 | #endif // QCPAINTERWIDGET_H 54 | -------------------------------------------------------------------------------- /src/canvaspainter/qcimagepattern_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | // 5 | // W A R N I N G 6 | // ------------- 7 | // 8 | // This file is not part of the Qt API. It exists purely as an 9 | // implementation detail. This header file may change from version to 10 | // version without notice, or even be removed. 11 | // 12 | // We mean it. 13 | // 14 | 15 | #ifndef QCIMAGEPATTERN_P_H 16 | #define QCIMAGEPATTERN_P_H 17 | 18 | #include "engine/qcpainterengine_p.h" 19 | #include "qcbrush_p.h" 20 | #include "qcimage.h" 21 | #include "qcimagepattern.h" 22 | #include 23 | #include 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QCImagePatternPrivate : public QCBrushPrivate 28 | { 29 | public: 30 | QCImagePatternPrivate(const QCImagePatternPrivate &) = default; 31 | 32 | QCImagePatternPrivate() : QCBrushPrivate(QCBrush::BrushType::ImagePattern) {} 33 | QCBrushPrivate *clone() override; 34 | 35 | QCPaint createPaint(QCPainter *painter) const override; 36 | 37 | static QCImagePatternPrivate *get(QCImagePattern *brush) 38 | { return static_cast(brush->baseData.get()); } 39 | static const QCImagePatternPrivate *get(const QCImagePattern *brush) 40 | { return static_cast(brush->baseData.get()); } 41 | 42 | QCImage image; 43 | QCPaint paint; 44 | QColor tintColor = QColorConstants::White; 45 | float x = 0.0f; 46 | float y = 0.0f; 47 | float width = 100.0f; 48 | float height = 100.0f; 49 | float angle = 0.0f; 50 | bool changed = true; 51 | }; 52 | 53 | QT_END_NAMESPACE 54 | 55 | #endif // QCIMAGEPATTERN_P_H 56 | -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/painterwindow.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #ifndef PAINTERWINDOW_H 5 | #define PAINTERWINDOW_H 6 | 7 | #include 8 | #include 9 | #if QT_CONFIG(opengl) 10 | #include 11 | #endif 12 | #include 13 | 14 | QT_FORWARD_DECLARE_CLASS(QCPainter) 15 | QT_FORWARD_DECLARE_CLASS(QCPainterFactory) 16 | 17 | class PainterWindow : public QWindow 18 | { 19 | Q_OBJECT 20 | public: 21 | PainterWindow(QRhi::Implementation api); 22 | ~PainterWindow() override; 23 | 24 | QColor fillColor() const; 25 | void setFillColor(const QColor &color); 26 | 27 | protected: 28 | virtual void paint(QCPainter *painter); 29 | virtual void cleanup(); 30 | 31 | void exposeEvent(QExposeEvent *) override; 32 | bool event(QEvent *) override; 33 | 34 | private: 35 | void updateSurfaceType(); 36 | void releaseSwapChain(); 37 | 38 | void init(); 39 | void resizeSwapChain(); 40 | void render(); 41 | 42 | QColor m_fillColor = {0, 0, 0, 0}; 43 | 44 | QCPainterFactory *m_factory = nullptr; 45 | QRhi::Implementation m_graphicsApi = QRhi::Null; 46 | 47 | #if QT_CONFIG(opengl) 48 | std::unique_ptr m_fallbackSurface; 49 | #endif 50 | std::unique_ptr m_rhi; 51 | std::unique_ptr m_sc; 52 | std::unique_ptr m_ds; 53 | std::unique_ptr m_rp; 54 | 55 | bool m_hasSwapChain = false; 56 | bool m_running = false; 57 | bool m_notExposed = false; 58 | bool m_newlyExposed = false; 59 | }; 60 | 61 | #endif // PAINTERWINDOW_H 62 | -------------------------------------------------------------------------------- /src/canvaspainter/qcgradient.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCGRADIENT_H 5 | #define QCGRADIENT_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | QT_BEGIN_NAMESPACE 14 | 15 | class QCGradientPrivate; 16 | class QCGradient; 17 | 18 | typedef std::pair QCGradientStop; 19 | typedef QList QCGradientStops; 20 | 21 | #ifndef QT_NO_DATASTREAM 22 | Q_CANVASPAINTER_EXPORT QDataStream &operator<<(QDataStream &, const QCGradient &); 23 | Q_CANVASPAINTER_EXPORT QDataStream &operator>>(QDataStream &, QCGradient &); 24 | #endif 25 | 26 | class Q_CANVASPAINTER_EXPORT QCGradient : public QCBrush 27 | { 28 | public: 29 | bool operator==(const QCGradient &gradient) const; 30 | inline bool operator!=(const QCGradient &gradient) const { return !(operator==(gradient)); } 31 | operator QVariant() const; 32 | 33 | QCBrush::BrushType type() const; 34 | 35 | QColor startColor() const; 36 | void setStartColor(const QColor &color); 37 | QColor endColor() const; 38 | void setEndColor(const QColor &color); 39 | void setColorAt(float position, const QColor &color); 40 | void setStops(const QCGradientStops &stops); 41 | QCGradientStops stops() const; 42 | 43 | protected: 44 | QCGradient(QCGradientPrivate *); 45 | private: 46 | friend class QCGradientPrivate; 47 | }; 48 | 49 | #ifndef QT_NO_DEBUG_STREAM 50 | Q_CANVASPAINTER_EXPORT QDebug operator<<(QDebug, const QCGradient &); 51 | #endif 52 | 53 | QT_END_NAMESPACE 54 | 55 | #endif // QCGRADIENT_H 56 | -------------------------------------------------------------------------------- /src/canvaspainter/qcimage.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCIMAGE_H 5 | #define QCIMAGE_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | 14 | class QCImagePrivate; 15 | 16 | QT_DECLARE_QESDP_SPECIALIZATION_DTOR(QCImagePrivate) 17 | 18 | class Q_CANVASPAINTER_EXPORT QCImage { 19 | Q_GADGET 20 | public: 21 | QCImage(); 22 | QCImage(const QCImage &image) noexcept; 23 | ~QCImage(); 24 | 25 | QCImage &operator=(const QCImage &image) noexcept; 26 | QCImage(QCImage &&other) noexcept = default; 27 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QCImage) 28 | void swap(QCImage &other) noexcept { d.swap(other.d); } 29 | 30 | bool operator==(const QCImage &image) const; 31 | inline bool operator!=(const QCImage &image) const { return !(operator==(image)); } 32 | operator QVariant() const; 33 | 34 | void detach(); 35 | 36 | int id() const; 37 | int width() const; 38 | int height() const; 39 | int size() const; 40 | bool isNull() const; 41 | 42 | QColor tintColor() const; 43 | void setTintColor(const QColor &color); 44 | 45 | // TODO: Add API for image rotation angle? Or rely only on state transformation? 46 | 47 | protected: 48 | friend class QCDataCache; 49 | friend class QCPainterPrivate; 50 | 51 | QExplicitlySharedDataPointer d; 52 | }; 53 | 54 | Q_DECLARE_SHARED(QCImage) 55 | 56 | #ifndef QT_NO_DEBUG_STREAM 57 | Q_CANVASPAINTER_EXPORT QDebug operator<<(QDebug, const QCImage &); 58 | #endif 59 | 60 | QT_END_NAMESPACE 61 | 62 | #endif // QCIMAGE_H 63 | -------------------------------------------------------------------------------- /src/canvaspainter/qcgridpattern_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | // 5 | // W A R N I N G 6 | // ------------- 7 | // 8 | // This file is not part of the Qt API. It exists purely as an 9 | // implementation detail. This header file may change from version to 10 | // version without notice, or even be removed. 11 | // 12 | // We mean it. 13 | // 14 | 15 | #ifndef QCGRIDPATTERN_P_H 16 | #define QCGRIDPATTERN_P_H 17 | 18 | #include "engine/qcpainterengine_p.h" 19 | #include "qcbrush_p.h" 20 | #include 21 | #include 22 | #include 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QCGridPatternPrivate : public QCBrushPrivate 27 | { 28 | public: 29 | QCGridPatternPrivate(const QCGridPatternPrivate &) = default; 30 | QCGridPatternPrivate() : QCBrushPrivate(QCBrush::BrushType::GridPattern) {} 31 | QCBrushPrivate *clone() override; 32 | QCPaint createPaint(QCPainter *painter) const override; 33 | 34 | static QCGridPatternPrivate *get(QCGridPattern *brush) 35 | { return static_cast(brush->baseData.get()); } 36 | static const QCGridPatternPrivate *get(const QCGridPattern *brush) 37 | { return static_cast(brush->baseData.get()); } 38 | 39 | void createGridPattern() const; 40 | 41 | QCPaint paint; 42 | QColor lineColor = QColorConstants::White; 43 | QColor backgroundColor = QColorConstants::Black; 44 | float x = 0.0f; 45 | float y = 0.0f; 46 | float width = 10.0f; 47 | float height = 10.0f; 48 | float feather = 1.0f; 49 | float angle = 0.0f; 50 | float lineWidth = 1.0f; 51 | bool changed = true; 52 | }; 53 | 54 | QT_END_NAMESPACE 55 | 56 | #endif // QCGRIDPATTERN_P_H 57 | -------------------------------------------------------------------------------- /src/canvaspainter/engine/qctextlayout_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCTEXTLAYOUT_P_H 5 | #define QCTEXTLAYOUT_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include "engine/qcdistancefieldglyphcache_p.h" 19 | #include "engine/qcpainterengineutils_p.h" 20 | #include "engine/qcrhidistancefieldglyphcache_p.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | QT_BEGIN_NAMESPACE 27 | 28 | using TextPoints 29 | = std::tuple, std::vector>; 30 | 31 | class QCTextLayout 32 | { 33 | public: 34 | QCTextLayout(); 35 | 36 | const QRectF bounds() const; 37 | 38 | static QTextOption::WrapMode convertToQtWrapMode(QCPainter::WrapMode mode); 39 | static Qt::Alignment convertToQtAlignment(QCPainter::TextAlign alignment); 40 | static float calculateVerticalAlignment(QCPainter::TextBaseline baseline, const QRectF &rect, 41 | const QFontMetrics &metrics, const QRectF &layoutRect); 42 | 43 | private: 44 | void generateVertexData(QCRhiDistanceFieldGlyphCache *cache); 45 | 46 | QTextLayout m_textLayout; 47 | QList m_runs; 48 | bool m_initialized = false; 49 | 50 | QVarLengthArray verts; 51 | QVarLengthArray indices; 52 | 53 | QRectF m_bounds; 54 | }; 55 | 56 | QT_END_NAMESPACE 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/canvaspainter/doc/src/qtcanvaspainter-index.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \title Qt Canvas Painter 6 | \page qtcanvaspainter-index.html 7 | \brief Provides hardware-accelerated painting API on QRhi. 8 | 9 | The Qt Canvas Painter module provides classes for hardware-accelerated 10 | imperative 2D painting. This painting API is available for both Qt Quick 11 | and Qt Widgets, and can also be used directly with QRhi. The API design 12 | generally follows HTML canvas 2d context, with some reductions and some 13 | additions. 14 | 15 | Compared to QPainter, the Qt Canvas Painter is more compact and has fewer 16 | abstractions, aiming to perform optimally on QRhi. Qt Canvas Painter is 17 | designed for GPU rendering and does not have a CPU backend as QPainter 18 | does. 19 | 20 | \note The Qt Canvas Painter module is currently in tech preview. 21 | 22 | \section1 Using the Module 23 | 24 | \section2 C++ API 25 | 26 | \include {module-use.qdocinc} {using the c++ api} 27 | 28 | \section3 Building with CMake 29 | 30 | \include {module-use.qdocinc} {building with cmake} {CanvasPainter} 31 | 32 | \section1 Class Reference 33 | 34 | \l{Qt Canvas Painter C++ Classes} 35 | 36 | \section1 Examples 37 | 38 | \l{Qt Canvas Painter Examples and Tutorials}{All examples} 39 | 40 | \section1 Licenses and Attributions 41 | 42 | Qt Canvas Painter runtime library is available under commercial licenses from 43 | \l{The Qt Company}. In addition, it is available under the \l {GNU General 44 | Public License, version 3}. 45 | 46 | See \l{Qt Licensing} for further details. 47 | 48 | Furthermore, Qt Canvas Painter in \QtVersion may contain third party 49 | modules under following permissive licenses: 50 | 51 | \annotatedlist attributions-qtcanvaspainter 52 | */ 53 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | project(qcgallery LANGUAGES CXX) 6 | 7 | find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick ShaderTools CanvasPainter) 8 | 9 | qt_standard_project_setup(REQUIRES 6.11) 10 | 11 | qt_add_executable(qcgalleryexample 12 | WIN32 13 | MACOSX_BUNDLE 14 | 15 | main.cpp 16 | galleryitem.cpp galleryitem.h 17 | galleryitemrenderer.cpp galleryitemrenderer.h 18 | ) 19 | 20 | qt_add_qml_module(qcgalleryexample 21 | URI 22 | GalleryExample 23 | QML_FILES 24 | main.qml 25 | TopBar.qml 26 | RESOURCE_PREFIX 27 | / 28 | RESOURCES 29 | images/pattern1.png 30 | images/pattern2.png 31 | fonts/Pacifico.ttf 32 | images/pattern3.png 33 | images/qt_development_white.png 34 | images/face-smile-bw.png 35 | NO_RESOURCE_TARGET_PATH 36 | ) 37 | 38 | target_link_libraries(qcgalleryexample PRIVATE 39 | Qt6::Core 40 | Qt6::Gui 41 | Qt6::Qml 42 | Qt6::Quick 43 | Qt6::CanvasPainter 44 | ) 45 | 46 | qc_add_shaders(qcgalleryexample "qcgallery_custombrush_shaders" 47 | PREFIX 48 | "/qcgalleryexample" 49 | FILES 50 | brush1.frag 51 | brush2.frag 52 | brush3.frag 53 | brush4.frag 54 | brush3.vert 55 | ) 56 | 57 | install(TARGETS qcgalleryexample 58 | BUNDLE DESTINATION . 59 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 60 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 61 | ) 62 | 63 | qt_generate_deploy_qml_app_script( 64 | TARGET qcgalleryexample 65 | OUTPUT_SCRIPT deploy_script 66 | MACOS_BUNDLE_POST_BUILD 67 | NO_UNSUPPORTED_PLATFORM_ERROR 68 | DEPLOY_USER_QML_MODULES_ON_UNSUPPORTED_PLATFORM 69 | ) 70 | install(SCRIPT ${deploy_script}) 71 | -------------------------------------------------------------------------------- /src/canvaspainter/qcbrush.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef QCBRUSH_H 6 | #define QCBRUSH_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | 14 | class QCPainter; 15 | struct QCPaint; 16 | 17 | class QCGradient; 18 | class QCBoxShadow; 19 | class QCImagePattern; 20 | class QCGridPattern; 21 | class QCCustomBrush; 22 | 23 | class QCBrushPrivate; 24 | 25 | QT_DECLARE_QESDP_SPECIALIZATION_DTOR(QCBrushPrivate) 26 | 27 | class Q_CANVASPAINTER_EXPORT QCBrush 28 | { 29 | Q_GADGET 30 | public: 31 | QCBrush(); 32 | QCBrush(const QCBrush &brush) noexcept; 33 | ~QCBrush(); 34 | 35 | QCBrush &operator=(const QCBrush &brush) noexcept; 36 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QCBrush) 37 | void swap(QCBrush &other) noexcept { baseData.swap(other.baseData); } 38 | 39 | enum class BrushType { 40 | Invalid, 41 | LinearGradient, 42 | RadialGradient, 43 | ConicalGradient, 44 | BoxGradient, 45 | BoxShadow, 46 | ImagePattern, 47 | GridPattern, 48 | // Add new brush types here 49 | Custom = 1000 50 | }; 51 | Q_ENUM(BrushType) 52 | 53 | BrushType type() const; 54 | void detach(); 55 | 56 | protected: 57 | explicit QCBrush(QCBrushPrivate *priv); 58 | QExplicitlySharedDataPointer baseData; 59 | private: 60 | QCPaint createPaint(QCPainter *painter) const; 61 | private: 62 | friend class QCPainter; 63 | }; 64 | 65 | Q_DECLARE_SHARED(QCBrush) 66 | 67 | #ifndef QT_NO_DEBUG_STREAM 68 | Q_CANVASPAINTER_EXPORT QDebug operator<<(QDebug, const QCBrush &); 69 | #endif 70 | 71 | QT_END_NAMESPACE 72 | 73 | #endif // QCBRUSH_H 74 | -------------------------------------------------------------------------------- /src/canvaspainter/qquickcpainterrenderer.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef QCQUICKITEMPAINTER_H 6 | #define QCQUICKITEMPAINTER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | class QQuickWindow; 18 | class QRhiCommandBuffer; 19 | class QQuickCPainterRendererPrivate; 20 | 21 | class Q_CANVASPAINTER_EXPORT QQuickCPainterRenderer : public QQuickRhiItemRenderer 22 | { 23 | public: 24 | explicit QQuickCPainterRenderer(); 25 | virtual ~QQuickCPainterRenderer() override; 26 | 27 | QColor fillColor() const; 28 | QCPainter *painter() const; 29 | float width() const; 30 | float height() const; 31 | 32 | bool hasSharedPainter() const; 33 | void setSharedPainter(bool enable); 34 | 35 | protected: 36 | virtual void initializeResources(QCPainter *painter); 37 | virtual void prePaint(QCPainter *painter); 38 | virtual void paint(QCPainter *painter); 39 | virtual void synchronize(QQuickCPainterItem *item); 40 | virtual void initialize(QRhiCommandBuffer *cb) override; 41 | 42 | void render(QRhiCommandBuffer *cb) override; 43 | void synchronize(QQuickRhiItem *item) override; 44 | 45 | void grabCanvas(const QCOffscreenCanvas &canvas, std::function callback); 46 | 47 | void beginCanvasPainting(QCOffscreenCanvas &canvas); 48 | void endCanvasPainting(); 49 | 50 | private: 51 | friend class QQuickCPainterItem; 52 | Q_DECLARE_PRIVATE(QQuickCPainterRenderer) 53 | QQuickCPainterRendererPrivate *d_ptr; 54 | }; 55 | 56 | QT_END_NAMESPACE 57 | 58 | #endif // QCQUICKITEMPAINTER_H 59 | -------------------------------------------------------------------------------- /src/canvaspainter/qquickcpainterrenderer_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCQUICKITEMPAINTER_P_H 5 | #define QCQUICKITEMPAINTER_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include "qquickcpainterrenderer.h" 19 | #include "engine/qcpainterengineutils_p.h" 20 | #include "qcdebug_p.h" 21 | 22 | QT_BEGIN_NAMESPACE 23 | 24 | class QCPainterFactory; 25 | class QRhiCommandBuffer; 26 | 27 | class QQuickCPainterRendererPrivate : public QObject 28 | { 29 | Q_DECLARE_PUBLIC(QQuickCPainterRenderer) 30 | public: 31 | QQuickCPainterRendererPrivate(QQuickCPainterRenderer *q); 32 | ~QQuickCPainterRendererPrivate(); 33 | 34 | struct ItemData { 35 | int width = 0; 36 | int height = 0; 37 | float devicePixelRatio = 1.0f; 38 | }; 39 | 40 | QQuickCPainterRenderer *q_ptr; 41 | 42 | QQuickWindow *m_window = nullptr; 43 | 44 | bool m_sharedPainter = true; 45 | QMetaObject::Connection m_sharedPainterNewFrameConn; 46 | QCPainterFactory *m_factory = nullptr; 47 | QRhiCommandBuffer *m_currentCb = nullptr; 48 | QColor m_fillColor = Qt::black; // the default in item is what matters 49 | ItemData m_itemData; 50 | bool m_antialiasing = true; 51 | bool m_highQualityRendering = false; 52 | bool m_renderedOnce = false; 53 | QCDrawDebug m_drawDebug; 54 | QCDebug m_debug; 55 | QRhi *m_rhi = nullptr; 56 | QRhiRenderTarget *m_rt = nullptr; 57 | bool m_initialized = false; 58 | bool m_initializeResourcesCalled = false; 59 | bool m_firstRender = true; 60 | static QAtomicInt m_rendered; 61 | }; 62 | 63 | QT_END_NAMESPACE 64 | 65 | #endif // QCQUICKITEMPAINTER_P_H 66 | -------------------------------------------------------------------------------- /src/canvaspainter/qcpainterpath_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCPAINTERPATH_P_H 5 | #define QCPAINTERPATH_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include "qcpainterpath.h" 19 | #include "engine/qcpainterengineutils_p.h" 20 | 21 | QT_BEGIN_NAMESPACE 22 | 23 | class QCPainterPathPrivate 24 | { 25 | public: 26 | static QCPainterPathPrivate *get(QCPainterPath *path) { return path->d_ptr; } 27 | static const QCPainterPathPrivate *get(const QCPainterPath *path) { return path->d_ptr; } 28 | 29 | static int dataSizeOf(QCCommand command) { 30 | switch (command) { 31 | case QCCommand::MoveTo: 32 | case QCCommand::LineTo: 33 | return 2; 34 | case QCCommand::BezierTo: 35 | return 6; 36 | case QCCommand::Close: 37 | case QCCommand::WindingCW: 38 | case QCCommand::WindingCCW: 39 | default: 40 | return 0; 41 | } 42 | }; 43 | 44 | void appendCommand(QCCommand command); 45 | void appendCommands(const QCCommand commands[], int cCount); 46 | void appendCommandsData(const float commandsData[], int dCount); 47 | void ensureCommands(int addition); 48 | void ensureCommandsData(int addition); 49 | 50 | QCCommands commands; 51 | QCCommandsData commandsData; 52 | qsizetype commandsCount = 0; 53 | qsizetype commandsDataCount = 0; 54 | // Distance tolerance for consecutive points 55 | float distTol = 0.01f; 56 | // When this increases, path has been (re)created 57 | // so all commands need to be re-evaluated. 58 | int pathIterations = 0; 59 | }; 60 | 61 | QT_END_NAMESPACE 62 | 63 | #endif // QCPAINTERPATH_P_H 64 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | cmake_minimum_required(VERSION 3.16) 5 | 6 | include(.cmake.conf) 7 | project(QtCanvasPainter 8 | VERSION "${QT_REPO_MODULE_VERSION}" 9 | DESCRIPTION "Qt CanvasPainter Libraries" 10 | HOMEPAGE_URL "https://qt.io/" 11 | LANGUAGES CXX C 12 | ) 13 | find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals) 14 | 15 | qt_internal_project_setup() 16 | 17 | find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED Core) 18 | find_package(Qt6 ${PROJECT_VERSION} QUIET CONFIG OPTIONAL_COMPONENTS Gui Widgets Quick) 19 | 20 | # Set up QT_HOST_PATH as an extra root path to look for the ShaderToolsTools package 21 | # when cross-compiling. 22 | if(NOT "${QT_HOST_PATH}" STREQUAL "") 23 | set(_qt_backup_qtdeclarative_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH}) 24 | set(_qt_backup_qtdeclarative_CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH}) 25 | list(PREPEND CMAKE_PREFIX_PATH "${QT_HOST_PATH_CMAKE_DIR}") 26 | list(PREPEND CMAKE_FIND_ROOT_PATH "${QT_HOST_PATH}") 27 | endif() 28 | 29 | # This can't use the find_package(Qt6 COMPONENTS) signature, because Qt6Config uses NO_DEFAULT and 30 | # won't look at the prepend extra find root paths. 31 | find_package(Qt6ShaderToolsTools ${PROJECT_VERSION} QUIET CONFIG 32 | PATHS 33 | ${_qt_additional_packages_prefix_path} 34 | ${_qt_additional_packages_prefix_path_env} 35 | ) 36 | 37 | if(NOT "${QT_HOST_PATH}" STREQUAL "") 38 | set(CMAKE_PREFIX_PATH ${_qt_backup_qtdeclarative_CMAKE_PREFIX_PATH}) 39 | set(CMAKE_FIND_ROOT_PATH ${_qt_backup_qtdeclarative_CMAKE_FIND_ROOT_PATH}) 40 | endif() 41 | 42 | # Optionally look for the target ShaderTools package to avoid warnings 43 | # when configuring the project to build examples in-tree in a prefix Qt build. 44 | # See QTBUG-96358 for details. 45 | find_package(Qt6 ${PROJECT_VERSION} CONFIG OPTIONAL_COMPONENTS ShaderTools) 46 | 47 | include(tools/qcshadergen/Qt6CanvasPainterMacros.cmake) 48 | 49 | qt_build_repo() 50 | -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/ecggraph.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #ifndef ECGGRAPH_H 5 | #define ECGGRAPH_H 6 | 7 | #include 8 | #include "theme.h" 9 | 10 | QT_FORWARD_DECLARE_CLASS(QCPainter) 11 | class MainWindow; 12 | 13 | class ECGGraph 14 | { 15 | 16 | public: 17 | explicit ECGGraph(); 18 | 19 | void paintWaves(QCPainter *painter, float x, float y, float w, float h); 20 | void initialize(); 21 | void updateData(float hr); 22 | 23 | private: 24 | friend class MainWindow; 25 | void paintWave(float x, float y, float w, float h); 26 | void paintSpo2Wave(float x, float y, float w, float h); 27 | 28 | void fillEmptyData(); 29 | void fillRandomData(); 30 | void fillBeatData(); 31 | 32 | MainWindow *m_mainWindow; 33 | QCPainter *m_painter; 34 | Theme *m_theme; 35 | // Wave data of each graph. Amount of graphs is m_waveAmount. 36 | QList m_waveData; 37 | // Index of new data arriving 38 | int m_heartDataIndex = 0; 39 | // Beat index for creating dummy data. Values > -1 mean that beat is ongoing. 40 | int m_beatDataIndex = -1; 41 | // Amount of data points per graph 42 | int m_dataLength = 250; 43 | // How big is the space between fresh data & old data, in items 44 | int m_clearAmount = 20; 45 | // Index of old data disappearing 46 | int m_clearDataIndex = 0; 47 | // How often a heart pulse comes, every nth frame 48 | // On 60Hz screen, 40 means HR = 60 * (60/40) = 90 49 | int m_pulseRate = 40; 50 | // Currently rendering frame 51 | int m_currentFrame = 0; 52 | // Frame where current pulse has started 53 | int m_beatFrame = 0; 54 | // True when the sensors are attached 55 | bool m_attached = true; 56 | // True when defibrillator is attached, causing random spikes 57 | bool m_defibrillator = false; 58 | float m_lineWidth = 2.0; 59 | QList m_spo2Data; 60 | 61 | }; 62 | 63 | #endif // ECGGRAPH_H 64 | -------------------------------------------------------------------------------- /tests/manual/itemtest/itemtest.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef ITEMTEST_H 6 | #define ITEMTEST_H 7 | 8 | #include "qquickcpainteritem.h" 9 | #include "qquickcpainterrenderer.h" 10 | #include "../shared/painthelper.h" 11 | 12 | class HelloItemRenderer : public QQuickCPainterRenderer 13 | { 14 | 15 | public: 16 | HelloItemRenderer() 17 | { 18 | // why this is interesting: because moving an item to a new QQuickWindow 19 | // automatically destroys and creates a new renderer object, thus 20 | // ensuring that no graphicsResourcesInvalidated() and similar are 21 | // needed, unlike the widget that has no dedicated renderer object. 22 | qDebug() << "HelloItemRenderer" << this << "created"; 23 | } 24 | 25 | void initializeResources(QCPainter *p) override 26 | { 27 | qDebug() << "initializeResources" << this; 28 | 29 | // Provide our own QCImage, to verify that a "load-if-not-yet-done" 30 | // logic works as expected, and it does not break down when the item 31 | // is moved between windows (and so changes QRhis, losing all graphics 32 | // resources in the process). 33 | static QImage logoImage(":/quitlogo.png"); 34 | if (logo.isNull()) 35 | logo = p->addImage(logoImage, QCPainter::ImageFlag::Repeat); 36 | } 37 | 38 | void synchronize(QQuickCPainterItem *) override 39 | { 40 | //qDebug() << "synchronize"; 41 | } 42 | 43 | void paint(QCPainter *p) override 44 | { 45 | paintHelloItem(p, width(), height(), &logo); 46 | } 47 | 48 | QCImage logo; 49 | }; 50 | 51 | class HelloItem : public QQuickCPainterItem 52 | { 53 | Q_OBJECT 54 | 55 | public: 56 | HelloItem(QQuickItem *parent = nullptr) 57 | : QQuickCPainterItem(parent) 58 | { 59 | } 60 | 61 | QQuickCPainterRenderer *createItemRenderer() const override 62 | { 63 | return new HelloItemRenderer; 64 | } 65 | }; 66 | 67 | #endif // ITEMTEST_H 68 | -------------------------------------------------------------------------------- /src/canvaspainter/qcboxshadow_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCBOXSHADOW_P_H 5 | #define QCBOXSHADOW_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include "engine/qcpainterengine_p.h" 19 | #include "qcboxshadow.h" 20 | #include "qcbrush_p.h" 21 | #include "qcimage.h" 22 | #include 23 | #include 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QCBoxShadowPrivate : public QCBrushPrivate 28 | { 29 | public: 30 | QCBoxShadowPrivate() : QCBrushPrivate(QCBrush::BrushType::BoxShadow) {} 31 | QCBoxShadowPrivate(const QCBoxShadowPrivate &) = default; 32 | QCBrushPrivate *clone() override; 33 | 34 | static QCBoxShadowPrivate *get(QCBoxShadow *brush) 35 | { return static_cast(brush->baseData.get()); } 36 | static const QCBoxShadowPrivate *get(const QCBoxShadow *brush) 37 | { return static_cast(brush->baseData.get()); } 38 | 39 | QCPaint createPaint(QCPainter *painter) const override; 40 | void createBoxShadow(float x, float y, float width, float height, 41 | const QVector4D &radius, 42 | float blur, const QColor &color) const; 43 | 44 | float clampedRadius(float radius, float width, float height) const; 45 | QColor clampedColor() const; 46 | 47 | QCPaint paint; 48 | float x = 0.0f; 49 | float y = 0.0f; 50 | float width = 100.0f; 51 | float height = 100.0f; 52 | float radius = 0.0f; 53 | float spread = 0.0f; 54 | float topLeftRadius = -1.0f; 55 | float topRightRadius = -1.0f; 56 | float bottomLeftRadius = -1.0f; 57 | float bottomRightRadius = -1.0f; 58 | float blur = 0.0f; 59 | QColor color = QColorConstants::Black; 60 | 61 | bool changed = true; 62 | }; 63 | 64 | QT_END_NAMESPACE 65 | 66 | #endif // QCBOXSHADOW_P_H 67 | -------------------------------------------------------------------------------- /src/canvaspainter/qcgradient_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCGRADIENT_P_H 5 | #define QCGRADIENT_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include "qcbrush_p.h" 19 | #include "qcgradient.h" 20 | #include "engine/qcpainterengineutils_p.h" 21 | #include 22 | #include 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QCGradientPrivate : public QCBrushPrivate 27 | { 28 | public: 29 | QCGradientPrivate(QCBrush::BrushType type); 30 | 31 | static QCGradientPrivate *get(QCGradient *brush) 32 | { return static_cast(brush->baseData.get()); } 33 | static const QCGradientPrivate *get(const QCGradient *brush) 34 | { return static_cast(brush->baseData.get()); } 35 | 36 | qint64 generateGradientId() const; 37 | static void gradientColorSpan(quint32 *data, const QColor &color0, const QColor &color1, float offset0, float offset1); 38 | void updateGradientTexture(QCPainter *painter); 39 | 40 | enum class DirtyFlag { 41 | Stops = 0x01, 42 | Values = 0x02, 43 | All = 0xFF 44 | }; 45 | Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag) 46 | 47 | // Variables specific to gradient types 48 | union QCGradientData { 49 | QCGradientData() {} 50 | struct { 51 | float sx, sy, ex, ey; 52 | } linear; 53 | struct { 54 | float cx, cy, oRadius, iRadius; 55 | } radial; 56 | struct { 57 | float cx, cy, angle; 58 | } conical; 59 | struct { 60 | float x, y, width, height, feather, radius; 61 | } box; 62 | }; 63 | QCGradientStops gradientStops; 64 | QCGradientData data; 65 | QCPaint paint; 66 | DirtyFlags dirty; 67 | int imageId; 68 | }; 69 | 70 | QT_END_NAMESPACE 71 | 72 | #endif // QCGRADIENT_P_H 73 | -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include 5 | #include 6 | #include "mainwindow.h" 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | QGuiApplication app(argc, argv); 11 | app.setAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents); 12 | 13 | QRhi::Implementation graphicsApi; 14 | #if defined(Q_OS_WIN) 15 | graphicsApi = QRhi::D3D11; 16 | #elif QT_CONFIG(metal) 17 | graphicsApi = QRhi::Metal; 18 | #elif QT_CONFIG(vulkan) 19 | graphicsApi = QRhi::Vulkan; 20 | #else 21 | graphicsApi = QRhi::OpenGLES2; 22 | #endif 23 | 24 | QCommandLineParser cmdLineParser; 25 | cmdLineParser.addHelpOption(); 26 | QCommandLineOption nullOption({ "n", "null" }, QLatin1String("Null")); 27 | cmdLineParser.addOption(nullOption); 28 | QCommandLineOption glOption({ "g", "opengl" }, QLatin1String("OpenGL")); 29 | cmdLineParser.addOption(glOption); 30 | QCommandLineOption vkOption({ "v", "vulkan" }, QLatin1String("Vulkan")); 31 | cmdLineParser.addOption(vkOption); 32 | QCommandLineOption d3d11Option({ "d", "d3d11" }, QLatin1String("Direct3D 11")); 33 | cmdLineParser.addOption(d3d11Option); 34 | QCommandLineOption d3d12Option({ "D", "d3d12" }, QLatin1String("Direct3D 12")); 35 | cmdLineParser.addOption(d3d12Option); 36 | QCommandLineOption mtlOption({ "m", "metal" }, QLatin1String("Metal")); 37 | cmdLineParser.addOption(mtlOption); 38 | 39 | cmdLineParser.process(app); 40 | 41 | if (cmdLineParser.isSet(nullOption)) 42 | graphicsApi = QRhi::Null; 43 | if (cmdLineParser.isSet(glOption)) 44 | graphicsApi = QRhi::OpenGLES2; 45 | if (cmdLineParser.isSet(vkOption)) 46 | graphicsApi = QRhi::Vulkan; 47 | if (cmdLineParser.isSet(d3d11Option)) 48 | graphicsApi = QRhi::D3D11; 49 | if (cmdLineParser.isSet(d3d12Option)) 50 | graphicsApi = QRhi::D3D12; 51 | if (cmdLineParser.isSet(mtlOption)) 52 | graphicsApi = QRhi::Metal; 53 | 54 | MainWindow window(graphicsApi); 55 | window.resize(1920 / 2, 1080 / 2); 56 | window.show(); 57 | 58 | return app.exec(); 59 | } 60 | -------------------------------------------------------------------------------- /src/canvaspainter/qcimagepattern.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef QCIMAGEPATTERN_H 6 | #define QCIMAGEPATTERN_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | class QCImagePatternPrivate; 19 | class QCImagePattern; 20 | 21 | #ifndef QT_NO_DATASTREAM 22 | Q_CANVASPAINTER_EXPORT QDataStream &operator<<(QDataStream &, const QCImagePattern &); 23 | Q_CANVASPAINTER_EXPORT QDataStream &operator>>(QDataStream &, QCImagePattern &); 24 | #endif 25 | 26 | class Q_CANVASPAINTER_EXPORT QCImagePattern : public QCBrush 27 | { 28 | public: 29 | QCImagePattern(); 30 | QCImagePattern(const QCImage &image); 31 | QCImagePattern(const QCImage &image, const QRectF &rect, float angle = 0.0f, const QColor &tintColor = QColorConstants::White); 32 | QCImagePattern(const QCImage &image, float x, float y, float width, float height, float angle = 0.0f, const QColor &tintColor = QColorConstants::White); 33 | ~QCImagePattern(); 34 | 35 | 36 | 37 | 38 | bool operator==(const QCImagePattern &pattern) const; 39 | inline bool operator!=(const QCImagePattern &pattern) const { return !(operator==(pattern)); } 40 | operator QVariant() const; 41 | 42 | QPointF startPosition() const; 43 | void setStartPosition(float x, float y); 44 | void setStartPosition(QPointF point); 45 | QSizeF imageSize() const; 46 | void setImageSize(float width, float height); 47 | void setImageSize(QSizeF size); 48 | QCImage image() const; 49 | void setImage(const QCImage &image); 50 | float rotation() const; 51 | void setRotation(float rotation); 52 | QColor tintColor() const; 53 | void setTintColor(const QColor &color); 54 | 55 | private: 56 | friend class QCImagePatternPrivate; 57 | }; 58 | 59 | #ifndef QT_NO_DEBUG_STREAM 60 | Q_CANVASPAINTER_EXPORT QDebug operator<<(QDebug, const QCImagePattern &); 61 | #endif 62 | 63 | QT_END_NAMESPACE 64 | 65 | #endif // QCIMAGEPATTERN_H 66 | -------------------------------------------------------------------------------- /src/canvaspainter/doc/snippets/paintdriver-ex-1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | //![0] 5 | int main(int argc, char *argv[]) 6 | { 7 | QGuiApplication app(argc, argv); 8 | 9 | // std::unique_ptr rhi(QRhi::create(...)); 10 | 11 | std::unique_ptr tex(rhi->newTexture(QRhiTexture::RGBA8, QSize(1280, 720), 1, 12 | QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource)); 13 | tex->create(); 14 | std::unique_ptr ds(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, QSize(1280, 720))); 15 | ds->create(); 16 | QRhiTextureRenderTargetDescription rtDesc; 17 | rtDesc.setColorAttachments({ tex.get() }); 18 | rtDesc.setDepthStencilBuffer(ds.get()); 19 | std::unique_ptr rt(rhi->newTextureRenderTarget(rtDesc)); 20 | std::unique_ptr rp(rt->newCompatibleRenderPassDescriptor()); 21 | rt->setRenderPassDescriptor(rp.get()); 22 | rt->create(); 23 | 24 | std::unique_ptr factory(new QCPainterFactory); 25 | QCPainter *painter = factory->create(rhi.get()); 26 | QCRhiPaintDriver *pd = factory->paintDriver(); 27 | 28 | QRhiCommandBuffer *cb; 29 | QRhiReadbackResult readbackResult; 30 | 31 | rhi->beginOffscreenFrame(&cb); 32 | pd->resetForNewFrame(); 33 | 34 | { 35 | pd->beginPaint(cb, rt.get()); 36 | 37 | painter->beginPath(); 38 | painter->circle(640, 360, 180); 39 | painter->setFillStyle(Qt::red); 40 | painter->fill(); 41 | 42 | pd->endPaint(); 43 | 44 | QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch(); 45 | u->readBackTexture({ tex.get() }, &readbackResult); 46 | cb->resourceUpdate(u); 47 | } 48 | 49 | rhi->endOffscreenFrame(); 50 | 51 | QImage image(reinterpret_cast(readbackResult.data.constData()), 52 | readbackResult.pixelSize.width(), 53 | readbackResult.pixelSize.height(), 54 | QImage::Format_RGBA8888); 55 | if (rhi->isYUpInFramebuffer()) 56 | image.flip(); 57 | 58 | image.save("result.png"); 59 | 60 | return 0; 61 | } 62 | //![0] 63 | -------------------------------------------------------------------------------- /src/canvaspainter/qcoffscreencanvas.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCOFFSCREENCANVAS_H 5 | #define QCOFFSCREENCANVAS_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | 14 | class QCOffscreenCanvasPrivate; 15 | class QRhiTexture; 16 | 17 | QT_DECLARE_QESDP_SPECIALIZATION_DTOR(QCOffscreenCanvasPrivate) 18 | 19 | class Q_CANVASPAINTER_EXPORT QCOffscreenCanvas 20 | { 21 | Q_GADGET 22 | 23 | public: 24 | enum class Flag { 25 | // Requests preserving (no clearing) of the color texture. 26 | // There's a catch: this will not always work with MSAA, depending on underlying details (on GLES, with certain extensions present) . 27 | // So probably going to be limited to non-multisample canvases. 28 | PreserveContents = 0x01 29 | }; 30 | Q_DECLARE_FLAGS(Flags, Flag) 31 | 32 | QCOffscreenCanvas(); 33 | QCOffscreenCanvas(const QCOffscreenCanvas &canvas) noexcept; 34 | ~QCOffscreenCanvas(); 35 | QCOffscreenCanvas &operator=(const QCOffscreenCanvas &canvas) noexcept; 36 | QCOffscreenCanvas(QCOffscreenCanvas &&other) noexcept = default; 37 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QCOffscreenCanvas) 38 | void swap(QCOffscreenCanvas &other) noexcept { d.swap(other.d); } 39 | 40 | bool operator==(const QCOffscreenCanvas &canvas) const; 41 | inline bool operator!=(const QCOffscreenCanvas &canvas) const { return !(operator==(canvas)); } 42 | 43 | void detach(); 44 | 45 | bool isNull() const; 46 | 47 | // flags and settings such as multisample count must be controlled by the 48 | // canvas factory function, we cannot have simple setters here, since under 49 | // the hood everything is immutable... 50 | Flags flags() const; 51 | 52 | QColor fillColor() const; 53 | void setFillColor(const QColor &color); 54 | 55 | QRhiTexture *texture() const; 56 | 57 | private: 58 | QExplicitlySharedDataPointer d; 59 | friend class QCOffscreenCanvasPrivate; 60 | friend class QCPainterRhiRenderer; 61 | }; 62 | 63 | Q_DECLARE_OPERATORS_FOR_FLAGS(QCOffscreenCanvas::Flags) 64 | Q_DECLARE_SHARED(QCOffscreenCanvas) 65 | 66 | QT_END_NAMESPACE 67 | 68 | #endif // QCOFFSCREENCANVAS_H 69 | -------------------------------------------------------------------------------- /src/canvaspainter/qcboxshadow.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCBOXSHADOW_H 5 | #define QCBOXSHADOW_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | QT_BEGIN_NAMESPACE 16 | 17 | class QCBoxShadowPrivate; 18 | class QCBoxShadow; 19 | class QCImage; 20 | 21 | class Q_CANVASPAINTER_EXPORT QCBoxShadow : public QCBrush 22 | { 23 | public: 24 | QCBoxShadow(); 25 | QCBoxShadow(const QRectF &rect, float radius = 0.0f, float blur = 0.0f, const QColor &color = QColorConstants::Black); 26 | QCBoxShadow(float x, float y, float width, float height, float radius = 0.0f, float blur = 0.0f, const QColor &color = QColorConstants::Black); 27 | ~QCBoxShadow(); 28 | 29 | bool operator==(const QCBoxShadow &shadow) const; 30 | inline bool operator!=(const QCBoxShadow &shadow) const { return !(operator==(shadow)); } 31 | operator QVariant() const; 32 | 33 | QRectF rect() const; 34 | void setRect(const QRectF &rect); 35 | void setRect(float x, float y, float width, float height); 36 | QRectF boundingRect() const; 37 | float radius() const; 38 | void setRadius(float radius); 39 | float blur() const; 40 | void setBlur(float blur); 41 | float spread() const; 42 | void setSpread(float spread); 43 | QColor color() const; 44 | void setColor(const QColor &color); 45 | 46 | float topLeftRadius() const; 47 | void setTopLeftRadius(float radius); 48 | float topRightRadius() const; 49 | void setTopRightRadius(float radius); 50 | float bottomLeftRadius() const; 51 | void setBottomLeftRadius(float radius); 52 | float bottomRightRadius() const; 53 | void setBottomRightRadius(float radius); 54 | 55 | private: 56 | friend class QCPainter; 57 | friend class QCPainterPrivate; 58 | friend class QCBoxShadowPrivate; 59 | }; 60 | 61 | #ifndef QT_NO_DATASTREAM 62 | Q_CANVASPAINTER_EXPORT QDataStream &operator<<(QDataStream &, const QCBoxShadow &); 63 | Q_CANVASPAINTER_EXPORT QDataStream &operator>>(QDataStream &, QCBoxShadow &); 64 | #endif 65 | 66 | #ifndef QT_NO_DEBUG_STREAM 67 | Q_CANVASPAINTER_EXPORT QDebug operator<<(QDebug, const QCBoxShadow &); 68 | #endif 69 | 70 | QT_END_NAMESPACE 71 | 72 | #endif // QCBOXSHADOW_H 73 | -------------------------------------------------------------------------------- /src/canvaspainter/qccustombrush_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCCUSTOMBRUSH_P_H 5 | #define QCCUSTOMBRUSH_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include "qcbrush_p.h" 19 | #include "qccustombrush.h" 20 | #include 21 | #include 22 | #include 23 | 24 | QT_BEGIN_NAMESPACE 25 | 26 | class QCCustomBrushPrivate : public QCBrushPrivate 27 | { 28 | public: 29 | QCCustomBrushPrivate() : QCBrushPrivate(QCBrush::BrushType::Custom) {} 30 | QCCustomBrushPrivate(const QCCustomBrushPrivate&) = default; 31 | QCBrushPrivate *clone() override; 32 | QCPaint createPaint(QCPainter *painter) const override; 33 | 34 | static QCCustomBrushPrivate *get(QCCustomBrush *brush) 35 | { return static_cast(brush->baseData.get()); } 36 | static const QCCustomBrushPrivate *get(const QCCustomBrush *brush) 37 | { return static_cast(brush->baseData.get()); } 38 | 39 | struct CommonUniforms { 40 | // Total size 112 + 112 = 224 bytes. 41 | // Built-in variables size is 112 bytes 42 | float scissorMat[12]; // matrices are actually 3 vec4s 43 | float scissorExt[2]; 44 | float scissorScale[2]; 45 | float alphaMult; 46 | float strokeThr; 47 | float fontAlphaMin; 48 | float fontAlphaMax; 49 | float colorEffects[4]; 50 | int texType; 51 | int type; 52 | float globalAlpha; 53 | int unusedInt; 54 | // Custom input size is 112 bytes. 55 | float iTime; 56 | int alphaIsRed; 57 | // Take into use when needed 58 | int unused1; 59 | float unused3; 60 | QVector4D data[4]; 61 | // Take these into use when needed 62 | float unused2[8]; 63 | }; 64 | 65 | // TODO: Should we store only shader filename strings here 66 | // and QShaders on the renderer side? 67 | QShader fragmentShader; 68 | QShader vertexShader; 69 | bool timeRunning = false; 70 | float time = 0; 71 | QVector4D data[4]; 72 | }; 73 | 74 | QT_END_NAMESPACE 75 | 76 | #endif // QCCUSTOMBRUSH_P_H 77 | -------------------------------------------------------------------------------- /src/canvaspainter/qcgridpattern.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef QCGRIDPATTERN_H 6 | #define QCGRIDPATTERN_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | QT_BEGIN_NAMESPACE 17 | 18 | class Q_CANVASPAINTER_EXPORT QCGridPattern : public QCBrush 19 | { 20 | public: 21 | QCGridPattern(); 22 | QCGridPattern(const QRectF &rect, 23 | const QColor &lineColor = QColorConstants::White, 24 | const QColor &backgroundColor = QColorConstants::Black, 25 | float lineWidth = 1.0f, float feather = 1.0f, float angle = 0.0f); 26 | QCGridPattern(float x, float y, float width, float height, 27 | const QColor &lineColor = QColorConstants::White, 28 | const QColor &backgroundColor = QColorConstants::Black, 29 | float lineWidth = 1.0f, float feather = 1.0f, float angle = 0.0f); 30 | ~QCGridPattern(); 31 | 32 | bool operator==(const QCGridPattern &pattern) const; 33 | inline bool operator!=(const QCGridPattern &pattern) const { return !(operator==(pattern)); } 34 | operator QVariant() const; 35 | 36 | QPointF startPosition() const; 37 | void setStartPosition(float x, float y); 38 | void setStartPosition(QPointF point); 39 | QSizeF cellSize() const; 40 | void setCellSize(float width, float height); 41 | void setCellSize(QSizeF size); 42 | float lineWidth() const; 43 | void setLineWidth(float width); 44 | float feather() const; 45 | void setFeather(float feather); 46 | float rotation() const; 47 | void setRotation(float rotation); 48 | QColor lineColor() const; 49 | void setLineColor(const QColor &color); 50 | QColor backgroundColor() const; 51 | void setBackgroundColor(const QColor &color); 52 | 53 | private: 54 | friend class QCGridPatternPrivate; 55 | }; 56 | 57 | #ifndef QT_NO_DATASTREAM 58 | Q_CANVASPAINTER_EXPORT QDataStream &operator<<(QDataStream &, const QCGridPattern &); 59 | Q_CANVASPAINTER_EXPORT QDataStream &operator>>(QDataStream &, QCGridPattern &); 60 | #endif 61 | 62 | #ifndef QT_NO_DEBUG_STREAM 63 | Q_CANVASPAINTER_EXPORT QDebug operator<<(QDebug, const QCGridPattern &); 64 | #endif 65 | 66 | QT_END_NAMESPACE 67 | 68 | #endif // QCGRIDPATTERN_H 69 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/galleryitem.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 4 | 5 | #ifndef GALLERYITEM_H 6 | #define GALLERYITEM_H 7 | 8 | #include 9 | #include 10 | #include "galleryitemrenderer.h" 11 | 12 | class GalleryItem : public QQuickCPainterItem 13 | { 14 | Q_OBJECT 15 | QML_NAMED_ELEMENT(GalleryItem) 16 | Q_PROPERTY(int galleryView READ galleryView WRITE setGalleryView NOTIFY galleryViewChanged) 17 | Q_PROPERTY(float animationTime READ animationTime WRITE setAnimationTime NOTIFY animationTimeChanged) 18 | Q_PROPERTY(float animationSine READ animationSine WRITE setAnimationSine NOTIFY animationSineChanged) 19 | Q_PROPERTY(float animState READ animState WRITE setAnimState NOTIFY animStateChanged) 20 | 21 | public: 22 | 23 | GalleryItem(QQuickItem *parent = nullptr); 24 | 25 | // Reimplement 26 | QQuickCPainterRenderer *createItemRenderer() const; 27 | 28 | int galleryView() const { return m_galleryView; } 29 | float animationTime() const { return m_animationTime; } 30 | float animationSine() const { return m_animationSine; } 31 | float animState() const { return m_animState; } 32 | 33 | void setGalleryView(int value) { 34 | if (m_galleryView == value) 35 | return; 36 | m_galleryView = value; 37 | Q_EMIT galleryViewChanged(); 38 | update(); 39 | } 40 | 41 | void setAnimationTime(float value) { 42 | if (qFuzzyCompare(value, m_animationTime)) 43 | return; 44 | m_animationTime = value; 45 | Q_EMIT animationTimeChanged(); 46 | update(); 47 | } 48 | 49 | void setAnimationSine(float value) { 50 | if (qFuzzyCompare(value, m_animationSine)) 51 | return; 52 | m_animationSine = value; 53 | Q_EMIT animationSineChanged(); 54 | update(); 55 | } 56 | 57 | void setAnimState(float value) { 58 | if (qFuzzyCompare(value, m_animState)) 59 | return; 60 | m_animState = value; 61 | Q_EMIT animStateChanged(); 62 | update(); 63 | } 64 | 65 | Q_SIGNALS: 66 | void galleryViewChanged(); 67 | void animationTimeChanged(); 68 | void animationSineChanged(); 69 | void animStateChanged(); 70 | 71 | private: 72 | int m_galleryView = 0; 73 | float m_animationTime = 0.0f; 74 | float m_animationSine = 0.0f; 75 | float m_animState = 0.0f; 76 | }; 77 | 78 | #endif // GALLERYITEM_H 79 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/brush1.frag: -------------------------------------------------------------------------------- 1 | #version 440 2 | 3 | QC_INCLUDE "customfrag.glsl" 4 | 5 | // Shader snippets taken from QQEM NoiseHelper and ElectricClounds nodes. 6 | 7 | // Hash from uvec2 to float 8 | float _hash21( uvec2 x ) 9 | { 10 | uvec2 q = 1103515245U * ( (x>>1U) ^ (x.yx ) ); 11 | uint n = 1103515245U * ( (q.x ) ^ (q.y>>3U) ); 12 | return float(n) * (1.0/float(0xffffffffU)); 13 | } 14 | 15 | // Hash from vec2 to float 16 | // Can be used directly with fragCoord 17 | float hash21(vec2 n) 18 | { 19 | uvec2 uin = uvec2(n); 20 | return _hash21(uin); 21 | } 22 | 23 | vec2 pseudo3dNoiseLevel(vec2 intPos, float t) { 24 | float rand = hash21(intPos); 25 | float angle = TAU * rand + t * rand; 26 | return vec2(cos(angle), sin(angle)); 27 | } 28 | 29 | // Generates noise which resembles 3D perlin-noise 30 | float pseudo3dNoise(vec3 pos) { 31 | const vec2 i = floor(pos.xy); 32 | const vec2 f = fract(pos.xy); 33 | const vec2 blend = f * f * (3.0 - 2.0 * f); 34 | float noiseVal = mix( 35 | mix( 36 | dot(pseudo3dNoiseLevel(i + vec2(0.0, 0.0), pos.z), f - vec2(0.0, 0.0)), 37 | dot(pseudo3dNoiseLevel(i + vec2(1.0, 0.0), pos.z), f - vec2(1.0, 0.0)), 38 | blend.x), 39 | mix( 40 | dot(pseudo3dNoiseLevel(i + vec2(0.0, 1.0), pos.z), f - vec2(0.0, 1.0)), 41 | dot(pseudo3dNoiseLevel(i + vec2(1.0, 1.0), pos.z), f - vec2(1.0, 1.0)), 42 | blend.x), 43 | blend.y); 44 | return noiseVal * SQRT2; 45 | } 46 | 47 | void main() 48 | { 49 | vec3 iResolution = vec3(500, 500, 1); 50 | int electricCloudLevels = 5; 51 | vec4 electricCloudColor = data1; 52 | vec2 uv = fragCoord.xy / iResolution.y; 53 | float cloudVal = 0.0; 54 | float sum = 0.0; 55 | float multiplier = 1.0; 56 | float time = iTime * 0.2; 57 | for (int i = 0; i < electricCloudLevels; i++) { 58 | vec3 noisePos = vec3(uv, time / multiplier); 59 | cloudVal += multiplier * abs(pseudo3dNoise(noisePos)); 60 | sum += multiplier; 61 | multiplier *= 0.5; 62 | uv = 2.0 * uv; 63 | } 64 | cloudVal /= sum; 65 | fragColor.a = 1.0; 66 | fragColor.rgb = mix(fragColor.rgb, vec3(cos(TAU * cloudVal)) * electricCloudColor.rgb * fragColor.a, electricCloudColor.a); 67 | 68 | // Note: If you don't need clipping support, remove clipMask(). 69 | // Note: If you don't need antialiasing support, remove antialiasingAlpha(). 70 | //fragColor *= globalAlpha * antialiasingAlpha() * clipMask(); 71 | fragColor *= globalAlpha * antialiasingAlpha(); 72 | 73 | // Note: Disable this if you don't want color effects to affect. 74 | applyColorEffects(fragColor); 75 | } 76 | -------------------------------------------------------------------------------- /tools/qcshadergen/shader_includes/customfrag.glsl: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 3 | 4 | #define TAU 6.28318530718 5 | #define SQRT2 1.41421356237 6 | 7 | layout(binding = 2) uniform sampler2D tex; 8 | layout(binding = 3) uniform sampler2D fontTex; 9 | layout(location = 0) in vec2 texCoord; 10 | layout(location = 1) in vec2 fragCoord; 11 | layout(location = 0) out vec4 fragColor; 12 | 13 | // Custom brushes use binding 1 14 | layout(std140, binding = 1) uniform commonUBuf { 15 | mat3 scissorMat; 16 | vec2 scissorExt; 17 | vec2 scissorScale; 18 | float alphaMult; 19 | float strokeThr; 20 | float fontAlphaMin; 21 | float fontAlphaMax; 22 | vec4 colorEffects; 23 | int texType; 24 | int type; 25 | float globalAlpha; 26 | int unused1; 27 | // Custom input 28 | float iTime; 29 | int alphaIsRed; 30 | float unused2; 31 | float unused3; 32 | vec4 data1; 33 | vec4 data2; 34 | vec4 data3; 35 | vec4 data4; 36 | vec4 unused4[2]; 37 | }; 38 | 39 | float clipMask() { 40 | vec2 sc = abs(scissorMat * vec3(fragCoord, 1.0)).xy - scissorExt; 41 | sc = vec2(0.5) - sc * scissorScale; 42 | return clamp(sc.x, 0.0, 1.0) * clamp(sc.y, 0.0, 1.0); 43 | } 44 | 45 | float antialiasingAlpha() { 46 | return min(1.0, (1.0 - abs(texCoord.x * 2.0 - 1.0)) * alphaMult) * min(1.0, texCoord.y); 47 | } 48 | 49 | // Returns text texture alpha as-is in the SDF texture. 50 | // Use smoothstep() to antialiase it as needed. 51 | float sdfFontAlphaRaw() { 52 | vec2 texSize = vec2(textureSize(fontTex, 0)); 53 | if (alphaIsRed == 0) 54 | return texture(fontTex, texCoord / texSize).a; 55 | else 56 | return texture(fontTex, texCoord / texSize).r; 57 | } 58 | 59 | // Returns text texture alpha with default antialiasing. 60 | float sdfFontAlpha() { 61 | vec2 texSize = vec2(textureSize(fontTex, 0)); 62 | float distance; 63 | if (alphaIsRed == 0) 64 | distance = texture(fontTex, texCoord / texSize).a; 65 | else 66 | distance = texture(fontTex, texCoord / texSize).r; 67 | // Smooth interpolation to get anti-aliased edges 68 | return smoothstep(fontAlphaMin, fontAlphaMax, distance); 69 | } 70 | 71 | void applyColorEffects(inout vec4 color) { 72 | if (colorEffects[0] > 0.0) { 73 | // Contrast + Brightness 74 | color.rgb = (color.rgb - 0.5 * color.a) * colorEffects[2] + 75 | 0.5 * color.a + colorEffects[1] * color.a; 76 | // Saturation 77 | const float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); 78 | color.rgb = mix(vec3(gray), color.rgb, colorEffects[3]); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/canvaspainter/hellowidget/doc/src/qtcanvaspainter-examples-hellowidget.qdoc: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only 3 | 4 | /*! 5 | \example hellowidget 6 | \ingroup canvaspainter-examples 7 | \title Qt Canvas Painter - Hello Widget Example 8 | \examplecategory {Graphics} 9 | \brief Demonstrates the use of QCPainter and QCPainterWidget. 10 | 11 | \image hellowidget-example.webp 12 | 13 | The example implements a QCPainterWidget subclass. One or more instances of 14 | this widget can then be added into a QMdiArea inside the QMainWindow. 15 | 16 | QCPainterWidget itself derives from \l QRhiWidget, and is always using 17 | accelerated 3D rendering via \l QRhi. 18 | 19 | Subclasses of QCPainterWidget will at minimum want to implement 20 | \l{QCPainterWidget::}{paint()}. This example also uses an image, loaded from 21 | a PNG file. 22 | 23 | \snippet hellowidget/canvaswidget.h 0 24 | 25 | The paint() function can start drawing using the provider QCPainter right away: 26 | 27 | \snippet hellowidget/canvaswidget.cpp paint 28 | 29 | See \l QCPainter, \l QCBrush, \l QCRadialGradient, \l QCImagePattern, \l 30 | QCImage, and \l QFont for more information on the features used by this 31 | example. 32 | 33 | The image is used as a pattern, for filling the heart shape: 34 | 35 | \snippet hellowidget/canvaswidget.cpp pattern 36 | 37 | When resources like QCImage and QCOffscreenCanvas are involved, these are 38 | managed in \l{QCPainterWidget::}{initializeResources()} and 39 | \l{QCPainterWidget::}{graphicsResourcesInvalidated()}: 40 | 41 | \snippet hellowidget/canvaswidget.cpp image 42 | 43 | initializeResources() is merely a convenience. Instead of implementing it, 44 | one could also write the following in paint(): 45 | 46 | \code 47 | if (m_image.isNull()) 48 | m_image = p->addImage(QImage(":/qt-translucent.png"), QCPainter::ImageFlag::Repeat); 49 | \endcode 50 | 51 | This example does not reparent widgets between windows, so graphics 52 | resources are not going to be lost. It is nonetheless a good pattern to 53 | assign a default, empty object to all QCImage and QCOffscreenCanvas 54 | variables in graphicsResourcesInvalidated(). 55 | 56 | The main() function creates a QMainWindow and QMdiArea. Multiple instances 57 | of the CanvasWidget class can be added as sub-windows. Due to 58 | \l{QCPainterWidget::}{hasSharedPainter()} defaulting to true, and due to 59 | being placed within the same top-level widget, all the painter widgets will 60 | share the same QCPainter and the associated rendering infrastructure, 61 | instead of creating dedicated ones. 62 | */ 63 | -------------------------------------------------------------------------------- /src/canvaspainter/doc/qtcanvaspainter.qdocconf: -------------------------------------------------------------------------------- 1 | include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) 2 | 3 | project = QtCanvasPainter 4 | description = Qt Canvas Painter Reference Documentation 5 | version = $QT_VERSION 6 | buildversion = Qt Canvas Painter | Commercial or GPLv3 7 | 8 | examplesinstallpath = canvaspainter 9 | url.examples = "https://code.qt.io/cgit/qt/qtcanvaspainter.git/tree/examples/\1?h=$QT_VER" 10 | url.sources = "https://code.qt.io/cgit/qt/qtcanvaspainter.git/tree/\1?h=$QT_VER#n\2" 11 | # Path to the root of qtcanvaspainter (for automatic linking to source code) 12 | url.sources.rootdir = ../../.. 13 | 14 | qhp.projects = QtCanvasPainter 15 | 16 | qhp.QtCanvasPainter.file = qtcanvaspainter.qhp 17 | qhp.QtCanvasPainter.namespace = org.qt-project.qtcanvaspainter.$QT_VERSION_TAG 18 | qhp.QtCanvasPainter.virtualFolder = qtcanvaspainter 19 | qhp.QtCanvasPainter.indexTitle = Qt Canvas Painter 20 | qhp.QtCanvasPainter.indexRoot = 21 | 22 | qhp.QtCanvasPainter.subprojects = manual examples classes 23 | 24 | qhp.QtCanvasPainter.subprojects.manual.title = Qt Canvas Painter 25 | qhp.QtCanvasPainter.subprojects.manual.indexTitle = Qt Canvas Painter module topics 26 | qhp.QtCanvasPainter.subprojects.manual.type = manual 27 | 28 | qhp.QtCanvasPainter.subprojects.examples.title = Examples 29 | qhp.QtCanvasPainter.subprojects.examples.indexTitle = Qt Canvas Painter Examples and Tutorials 30 | qhp.QtCanvasPainter.subprojects.examples.selectors = doc:example 31 | qhp.QtCanvasPainter.subprojects.examples.sortPages = true 32 | 33 | qhp.QtCanvasPainter.subprojects.classes.title = C++ Classes 34 | qhp.QtCanvasPainter.subprojects.classes.indexTitle = Qt Canvas Painter C++ Classes 35 | qhp.QtCanvasPainter.subprojects.classes.selectors = class doc:headerfile 36 | qhp.QtCanvasPainter.subprojects.classes.sortPages = true 37 | 38 | tagfile = ../../../doc/qtcanvaspainter/qtcanvaspainter.tags 39 | 40 | depends += qtdoc qtcmake qmake qtcore qtgui qtwidgets qtquick 41 | 42 | headerdirs += .. 43 | 44 | sourcedirs += .. 45 | 46 | exampledirs += snippets ../../../examples/canvaspainter 47 | 48 | imagedirs += images 49 | 50 | # Exclude private header files from the documentation build 51 | excludefiles += "*_p.h" 52 | 53 | navigation.landingpage = "Qt Canvas Painter" 54 | navigation.cppclassespage = "Qt Canvas Painter C++ Classes" 55 | # Autogenerate navigation linking based on "Qt Canvas Painter module topics": 56 | navigation.toctitles = "Qt Canvas Painter module topics" 57 | navigation.toctitles.inclusive = false 58 | 59 | macro.cmakeoptionsince = "\n\nThis option was introduced in Qt \1.\n\n" 60 | 61 | # Allow zero warnings when testing documentation in CI 62 | warninglimit = 0 63 | -------------------------------------------------------------------------------- /tests/manual/shared/painthelper.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2018 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #ifndef PAINTHELPER_H 6 | #define PAINTHELPER_H 7 | 8 | #include 9 | #include 10 | #include "qcpainter.h" 11 | #include "qcradialgradient.h" 12 | #include "qcimagepattern.h" 13 | 14 | inline void paintHelloItem(QCPainter *p, float width, float height, QCImage *heartImage = nullptr, float patternSizeFactor = 0.02f) 15 | { 16 | float size = std::min(width, height); 17 | QPointF center(width/2, height/2); 18 | // Paint the background circle 19 | QCRadialGradient gradient1(center.x(), center.y() - size*0.1, size*0.6); 20 | gradient1.setStartColor("#909090"); 21 | gradient1.setEndColor("#404040"); 22 | p->beginPath(); 23 | p->circle(center, size*0.46); 24 | p->setFillStyle(gradient1); 25 | p->fill(); 26 | p->setStrokeStyle("#202020"); 27 | p->setLineWidth(size*0.02); 28 | p->stroke(); 29 | // Hello text 30 | p->setTextAlign(QCPainter::TextAlign::Center); 31 | p->setTextBaseline(QCPainter::TextBaseline::Middle); 32 | QFont font1; 33 | font1.setWeight(QFont::Weight::Bold); 34 | font1.setItalic(true); 35 | font1.setPixelSize(size*0.08); 36 | p->setFont(font1); 37 | p->setFillStyle("#B0D040"); 38 | p->fillText("HELLO", center.x(), center.y() - size*0.18); 39 | // QCPainter text 40 | QFont font2; 41 | font2.setWeight(QFont::Weight::Thin); 42 | font2.setPixelSize(size*0.12); 43 | p->setFont(font2); 44 | p->fillText("QCPainter", center.x(), center.y() - size*0.08); 45 | // Paint heart 46 | static QImage logoImage(":/quitlogo.png"); 47 | // The QCImage must not be static, the underlying texture needs to be 48 | // recreated if the QRhi (and so the renderer) changes, when reparenting to 49 | // a new top-level for instance. 50 | QCImage logo = p->addImage(logoImage, QCPainter::ImageFlag::Repeat); 51 | float patternSize = size * patternSizeFactor; 52 | QCImagePattern pattern(heartImage ? *heartImage : logo, center.x(), center.y(), patternSize, patternSize); 53 | p->setFillStyle(pattern); 54 | p->setLineCap(QCPainter::LineCap::Round); 55 | p->setStrokeStyle("#B0D040"); 56 | p->beginPath(); 57 | p->moveTo(center.x(), center.y() + size*0.3); 58 | p->bezierCurveTo(center.x() - size*0.25, center.y() + size*0.1, 59 | center.x() - size*0.05, center.y() + size*0.05, 60 | center.x(), center.y() + size*0.15); 61 | p->bezierCurveTo(center.x() + size*0.05, center.y() + size*0.05, 62 | center.x() + size*0.25, center.y() + size*0.1, 63 | center.x(), center.y() + size*0.3); 64 | p->stroke(); 65 | p->fill(); 66 | } 67 | 68 | #endif // PAINTHELPER_H 69 | -------------------------------------------------------------------------------- /src/canvaspainter/engine/qctextlayout.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #include "engine/qcdistancefieldglyphcache_p.h" 5 | #include "qctextlayout_p.h" 6 | #include "engine/qcrhidistancefieldglyphcache_p.h" 7 | #include 8 | #include 9 | 10 | QT_BEGIN_NAMESPACE 11 | 12 | QCTextLayout::QCTextLayout() {} 13 | 14 | QTextOption::WrapMode QCTextLayout::convertToQtWrapMode(QCPainter::WrapMode mode) 15 | { 16 | switch (mode) { 17 | case QCPainter::WrapMode::NoWrap: 18 | return QTextOption::NoWrap; 19 | break; 20 | case QCPainter::WrapMode::Wrap: 21 | return QTextOption::WrapAtWordBoundaryOrAnywhere; 22 | break; 23 | case QCPainter::WrapMode::WordWrap: 24 | return QTextOption::WordWrap; 25 | break; 26 | case QCPainter::WrapMode::WrapAnywhere: 27 | return QTextOption::WrapAnywhere; 28 | break; 29 | } 30 | return QTextOption::NoWrap; 31 | } 32 | 33 | Qt::Alignment QCTextLayout::convertToQtAlignment(QCPainter::TextAlign alignment) 34 | { 35 | switch (alignment) { 36 | case QCPainter::TextAlign::Left: 37 | return Qt::AlignLeft; 38 | break; 39 | case QCPainter::TextAlign::Center: 40 | return Qt::AlignCenter; 41 | break; 42 | case QCPainter::TextAlign::Right: 43 | return Qt::AlignRight; 44 | break; 45 | default: 46 | break; 47 | } 48 | return Qt::AlignLeft; 49 | } 50 | 51 | const QRectF QCTextLayout::bounds() const 52 | { 53 | return m_bounds; 54 | } 55 | 56 | void QCTextLayout::generateVertexData(QCRhiDistanceFieldGlyphCache *cache) 57 | { 58 | m_initialized = true; 59 | 60 | for (const auto &run : m_runs) { 61 | cache->addGlyphs({0, 0}, run); 62 | cache->update(); 63 | cache->generateVertices(&verts, &indices, QTransform(), &m_bounds); 64 | } 65 | } 66 | 67 | float QCTextLayout::calculateVerticalAlignment(QCPainter::TextBaseline baseline, const QRectF &rect, 68 | const QFontMetrics &metrics, const QRectF &layoutRect) 69 | { 70 | float offset = 0; 71 | switch (baseline) { 72 | case QCPainter::TextBaseline::Top: 73 | break; 74 | case QCPainter::TextBaseline::Hanging: 75 | offset = -metrics.height() + metrics.ascent(); 76 | break; 77 | case QCPainter::TextBaseline::Middle: 78 | offset = rect.height() * 0.5 - layoutRect.height() * 0.5; 79 | break; 80 | case QCPainter::TextBaseline::Alphabetic: 81 | offset = rect.height() - layoutRect.height() + metrics.descent(); 82 | break; 83 | case QCPainter::TextBaseline::Bottom: 84 | offset = rect.height() - layoutRect.height(); 85 | break; 86 | } 87 | 88 | return offset; 89 | } 90 | 91 | QT_END_NAMESPACE 92 | -------------------------------------------------------------------------------- /tests/manual/itemtest/main.qml: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | import QtQuick 6 | import QtQuick.Controls 7 | import QtQuick.Layouts 8 | import HelloItem 9 | 10 | ApplicationWindow { 11 | id: w1 12 | visible: true 13 | width: 480 14 | height: 800 15 | 16 | Item { 17 | id: w1root 18 | anchors.fill: parent 19 | 20 | Item { 21 | id: content 22 | anchors.fill: parent 23 | 24 | Text { 25 | id: textItem 26 | anchors.horizontalCenter: parent.horizontalCenter 27 | y: parent.height * 0.02 28 | font.pixelSize: parent.width * 0.04 29 | color: "purple" 30 | text: "Here is our custom QCPainter item" 31 | } 32 | 33 | Rectangle { 34 | color: "red" 35 | width: 100 36 | height: 100 37 | NumberAnimation on rotation { from: 0; to: 360; duration: 5000; loops: -1 } 38 | anchors.top: textItem.bottom 39 | 40 | } 41 | 42 | Rectangle { 43 | color: "transparent" 44 | border.color: "green" 45 | border.width: 4 46 | anchors.top: textItem.bottom 47 | anchors.bottom: parent.bottom 48 | width: parent.width 49 | 50 | HelloItem { 51 | anchors.fill: parent 52 | alphaBlending: cbTransparentBackground.checked 53 | fillColor: cbTransparentBackground.checked ? "transparent" : "white" 54 | } 55 | } 56 | 57 | ColumnLayout { 58 | anchors.right: parent.right 59 | anchors.bottom: parent.bottom 60 | anchors.margins: 4 61 | CheckBox { 62 | id: cbTransparentBackground 63 | text: "Transparent background" 64 | checked: true 65 | } 66 | Button { 67 | text: "Reparent to new window" 68 | onClicked: { 69 | if (w2.visible) { 70 | content.parent = w1root 71 | w2.visible = false 72 | } else { 73 | content.parent = w2root 74 | w2.visible = true 75 | } 76 | } 77 | } 78 | } 79 | } 80 | } 81 | 82 | ApplicationWindow { 83 | id: w2 84 | width: 600 85 | height: 400 86 | visible: false 87 | 88 | Item { 89 | id: w2root 90 | anchors.fill: parent 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /examples/canvaspainter/hellowidget/canvaswidget.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "canvaswidget.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace Qt::StringLiterals; 11 | 12 | CanvasWidget::CanvasWidget() 13 | { 14 | setFillColor(Qt::white); 15 | } 16 | 17 | //![image] 18 | void CanvasWidget::initializeResources(QCPainter *p) 19 | { 20 | Q_ASSERT(m_image.isNull()); 21 | const auto flags = QCPainter::ImageFlag::Repeat | QCPainter::ImageFlag::GenerateMipmaps; 22 | m_image = p->addImage(QImage(u":/qt-translucent.png"_s), flags); 23 | } 24 | 25 | void CanvasWidget::graphicsResourcesInvalidated() 26 | { 27 | m_image = {}; 28 | } 29 | //![image] 30 | 31 | //![paint] 32 | void CanvasWidget::paint(QCPainter *p) 33 | { 34 | const float size = std::min(width(), height()); 35 | const float centerX = width() / 2; 36 | const float centerY = height() / 2; 37 | 38 | // Paint the background circle 39 | QCRadialGradient gradient1(centerX, centerY - size * 0.1f, size * 0.6f); 40 | gradient1.setStartColor(QColor(0x909090)); 41 | gradient1.setEndColor(QColor(0x404040)); 42 | p->beginPath(); 43 | p->circle(QPointF(centerX, centerY), size * 0.46f); 44 | p->setFillStyle(gradient1); 45 | p->fill(); 46 | p->setStrokeStyle(QColor(0x202020)); 47 | p->setLineWidth(size * 0.02f); 48 | p->stroke(); 49 | //![paint] 50 | // Hello text 51 | p->setTextAlign(QCPainter::TextAlign::Center); 52 | p->setTextBaseline(QCPainter::TextBaseline::Middle); 53 | QFont font1; 54 | font1.setWeight(QFont::Weight::Bold); 55 | font1.setItalic(true); 56 | font1.setPixelSize(qRound(size * 0.08f)); 57 | p->setFont(font1); 58 | p->setFillStyle(QColor(0xB0D040)); 59 | p->fillText(u"HELLO"_s, centerX, centerY - size * 0.18f); 60 | 61 | // QCPainter text 62 | QFont font2; 63 | font2.setWeight(QFont::Weight::Thin); 64 | font2.setPixelSize(qRound(size * 0.11f)); 65 | p->setFont(font2); 66 | p->fillText(u"Qt Canvas Painter"_s, centerX, centerY - size * 0.08f); 67 | 68 | //![pattern] 69 | // Paint heart 70 | QCImagePattern pattern(m_image, centerX, centerY, size * 0.08f, size * 0.05f); 71 | p->setFillStyle(pattern); 72 | //![pattern] 73 | p->setLineCap(QCPainter::LineCap::Round); 74 | p->setStrokeStyle(QColor(0xB0D040)); 75 | p->beginPath(); 76 | p->moveTo(centerX, centerY + size * 0.3f); 77 | p->bezierCurveTo(centerX - size * 0.25f, centerY + size * 0.1f, 78 | centerX - size * 0.05f, centerY + size * 0.05f, 79 | centerX, centerY + size * 0.15f); 80 | p->bezierCurveTo(centerX + size * 0.05f, centerY + size * 0.05f, 81 | centerX + size * 0.25f, centerY + size * 0.1f, 82 | centerX, centerY + size * 0.3f); 83 | p->stroke(); 84 | p->fill(); 85 | } 86 | -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/theme.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #include "theme.h" 5 | 6 | Theme::Theme() { 7 | initThemes(); 8 | m_theme = m_darkTheme; 9 | } 10 | 11 | void Theme::initThemes() { 12 | m_darkTheme.background1 = QColor(0x111111); 13 | m_darkTheme.background2 = QColor(0x1d2127); 14 | m_darkTheme.foreground1 = QColor(0xf0f0f0); 15 | m_darkTheme.foreground2 = QColor(0xa0a0a0); 16 | m_darkTheme.foreground3 = QColor(0x404040); 17 | m_darkTheme.highlight = QColor(0xf0d040); 18 | m_darkTheme.warning = QColor(0xf04040); 19 | m_darkTheme.graph1 = QColor(0x20f020); 20 | m_darkTheme.graph2 = QColor(0xf0f020); 21 | m_darkTheme.gradient1.setColorAt(0.0f, 0xff3030); 22 | m_darkTheme.gradient1.setColorAt(0.7f, 0xD0D020); 23 | m_darkTheme.gradient1.setColorAt(0.8f, 0x20D020); 24 | m_darkTheme.gradient1.setColorAt(1.0f, 0x80f0f0); 25 | m_darkTheme.gradient2.setColorAt(0.0f, 0x80b0f0); 26 | m_darkTheme.gradient2.setColorAt(1.0f, QColor::fromRgba(0x80504030)); 27 | 28 | m_lightTheme.background1 = QColor(0xeeeeee); 29 | m_lightTheme.background2 = QColor(0xd0d2d8); 30 | m_lightTheme.foreground1 = QColor(0x101010); 31 | m_lightTheme.foreground2 = QColor(0x505050); 32 | m_lightTheme.foreground3 = QColor(0xc0c0c0); 33 | m_lightTheme.highlight = QColor(0xd09000); 34 | m_lightTheme.warning = QColor(0xf00000); 35 | m_lightTheme.graph1 = QColor(0x10a010); 36 | m_lightTheme.graph2 = QColor(0xa0a010); 37 | m_lightTheme.gradient1.setColorAt(0.0f, 0xe01010); 38 | m_lightTheme.gradient1.setColorAt(0.7f, 0xd0d010); 39 | m_lightTheme.gradient1.setColorAt(0.8f, 0x108010); 40 | m_lightTheme.gradient1.setColorAt(1.0f, 0x108080); 41 | m_lightTheme.gradient2.setColorAt(0.0f, 0x60a0e0); 42 | m_lightTheme.gradient2.setColorAt(1.0f, QColor::fromRgba(0x80504030)); 43 | } 44 | 45 | void Theme::switchTheme() { 46 | m_isDarkTheme = !m_isDarkTheme; 47 | if (m_isDarkTheme) 48 | m_theme = m_darkTheme; 49 | else 50 | m_theme = m_lightTheme; 51 | } 52 | 53 | bool Theme::isDark() const 54 | { 55 | return m_isDarkTheme; 56 | } 57 | 58 | QColor Theme::background1() const 59 | { 60 | return m_theme.background1; 61 | } 62 | 63 | QColor Theme::background2() const 64 | { 65 | return m_theme.background2; 66 | } 67 | 68 | QColor Theme::foreground1() const 69 | { 70 | return m_theme.foreground1; 71 | } 72 | 73 | QColor Theme::foreground2() const 74 | { 75 | return m_theme.foreground2; 76 | } 77 | 78 | QColor Theme::foreground3() const 79 | { 80 | return m_theme.foreground3; 81 | } 82 | 83 | QColor Theme::highlight() const 84 | { 85 | return m_theme.highlight; 86 | } 87 | 88 | QColor Theme::warning() const 89 | { 90 | return m_theme.warning; 91 | } 92 | 93 | QColor Theme::graph1() const 94 | { 95 | return m_theme.graph1; 96 | } 97 | 98 | QColor Theme::graph2() const 99 | { 100 | return m_theme.graph2; 101 | } 102 | 103 | QCLinearGradient Theme::gradient1() const 104 | { 105 | return m_theme.gradient1; 106 | } 107 | 108 | QCLinearGradient Theme::gradient2() const 109 | { 110 | return m_theme.gradient2; 111 | } 112 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/galleryitemrenderer.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 4 | 5 | #ifndef GALLERYITEMRENDERER_H 6 | #define GALLERYITEMRENDERER_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | class GalleryItemRenderer : public QQuickCPainterRenderer 18 | { 19 | public: 20 | explicit GalleryItemRenderer(); 21 | ~GalleryItemRenderer(); 22 | 23 | // Reimplement 24 | void initializeResources(QCPainter *painter) override; 25 | void synchronize(QQuickCPainterItem *item) override; 26 | void paint(QCPainter *painter) override; 27 | 28 | private: 29 | 30 | // View - Rectangles 31 | void drawRectsWithLinearGradient(); 32 | void drawRectsWithRadialGradient(); 33 | void drawRectsWithBoxGradient(); 34 | void drawRectsWithConicalGradients(); 35 | void drawRectsWithImagePattern(); 36 | void drawRectsWithBrushStroke(); 37 | 38 | // View - Paths 39 | void drawPaths(); 40 | 41 | // View - Painter Paths 42 | void drawPainterPaths(); 43 | 44 | // View - States and transforms 45 | void drawTransforms(); 46 | 47 | // View - Antialiasing 48 | void drawAntialiasing(); 49 | 50 | // View - Composite 51 | void drawCompositeItem1(float x, float y, float w, float h, QCPainter::CompositeOperation mode); 52 | void drawCompositeItem2(float x, float y, float w, float h, QCPainter::CompositeOperation mode); 53 | void drawCompositeItem3(float x, float y, float w, float h, QCPainter::CompositeOperation mode); 54 | void drawCompositeModes(); 55 | 56 | // View - Grid patterns 57 | void drawGridPatterns(); 58 | 59 | // View - Shadows 60 | void drawRectangularShadows(); 61 | 62 | // View - Custom Brushes 63 | void drawCustomBrushes(); 64 | 65 | // View - Color Effects 66 | void drawButton(float x, float y, float w, float h, const QString &label); 67 | void drawColorEffects(); 68 | 69 | // View - Texts 70 | void drawTextsFonts(); 71 | void drawTextsBrushes(); 72 | void drawTextsAlignments(); 73 | void drawTextsWrapping(); 74 | 75 | // View - Images 76 | void drawImages(); 77 | 78 | void drawRect(float x, float y, float w, float h); 79 | 80 | //QCPainter *m_painter; 81 | float m_animationTime = 0.0f; 82 | float m_animationSine = 0.0f; 83 | float m_animState = 0.0f; 84 | float m_viewAlpha = 1.0f; 85 | float m_viewSaturate = 1.0f; 86 | int m_viewIndex = 0; 87 | float m_previousWidth = 0; 88 | float m_previousHeight = 0; 89 | bool m_sizeChanged = false; 90 | float m_topMargin = 0; 91 | QCRadialGradient m_radGrad; 92 | QCImage m_testImage; 93 | QCImage m_patternImage; 94 | QCImage m_patternImage2; 95 | QCImage m_patternImage3; 96 | QCImage image3Gray; 97 | QCImage image3Plain; 98 | QCImage image3Nearest; 99 | QCImage image3Mips; 100 | QCImage image3NearestMips; 101 | QCCustomBrush m_customBrush; 102 | QCCustomBrush m_customBrush2; 103 | QCCustomBrush m_customBrush3; 104 | QCCustomBrush m_customBrush4; 105 | QCPainterPath m_path1; 106 | QCPainterPath m_path2; 107 | QCPainterPath m_path3; 108 | QCPainterPath m_path4; 109 | QCPainterPath m_pathGraphLine; 110 | QCPainterPath m_pathGraphArea; 111 | }; 112 | 113 | #endif // GALLERYITEMRENDERER_H 114 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/main.qml: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 4 | 5 | import QtQuick 6 | import QtQuick.Window 7 | import GalleryExample 8 | 9 | Window { 10 | id: mainView 11 | 12 | readonly property real dp: height / 600 13 | property real animationTime: 0 14 | property real animationSine: 0 15 | property bool animatePainting: true 16 | 17 | width: 1280 18 | height: 720 19 | visible: true 20 | color: "#222831" 21 | 22 | NumberAnimation on animationTime { 23 | id: animationTimeAnimation 24 | running: mainView.animatePainting 25 | from: 0 26 | to: 360 27 | duration: 1000*360 28 | loops: Animation.Infinite 29 | } 30 | SequentialAnimation on animationSine { 31 | running: mainView.animatePainting 32 | loops: Animation.Infinite 33 | NumberAnimation { 34 | from: 0 35 | to: 1 36 | duration: 1000 37 | easing.type: Easing.InOutSine 38 | } 39 | NumberAnimation { 40 | from: 1 41 | to: 0 42 | duration: 1000 43 | easing.type: Easing.InOutSine 44 | } 45 | } 46 | 47 | TopBar { 48 | id: topBar 49 | width: parent.width 50 | height: Math.floor(60 * dp) 51 | currentIndex: listView.currentIndex 52 | itemCount: listView.count 53 | visibilityState: (listView.visibleArea.xPosition * (listView.delegateWidth * listView.count + listView.width)) / listView.delegateWidth 54 | } 55 | 56 | /* 57 | // This can be used for autoscrolling gallery to see memory usage 58 | // while (un)loading items 59 | SequentialAnimation { 60 | running: true 61 | loops: Animation.Infinite 62 | ScriptAction { 63 | script: listView.currentIndex = listView.count-1; 64 | } 65 | PauseAnimation { 66 | duration: 5000 67 | } 68 | ScriptAction { 69 | script: listView.currentIndex = 0; 70 | } 71 | PauseAnimation { 72 | duration: 5000 73 | } 74 | } 75 | */ 76 | 77 | ListView { 78 | id: listView 79 | readonly property real delegateWidth: height * 0.75 80 | anchors.top: topBar.bottom 81 | anchors.topMargin: Math.floor(20 * dp) 82 | anchors.bottom: parent.bottom 83 | width: parent.width 84 | orientation: ListView.Horizontal 85 | snapMode: ListView.SnapToItem 86 | highlightRangeMode: ListView.StrictlyEnforceRange 87 | maximumFlickVelocity: 10000 88 | highlightMoveDuration: 2500 89 | model: 15 90 | // Disable this to not preload all views. 91 | cacheBuffer: 10000 92 | preferredHighlightBegin: width * 0.5 - delegateWidth * 0.5 93 | preferredHighlightEnd: preferredHighlightBegin + 1 94 | Component.onCompleted: currentIndex = 0; 95 | delegate: GalleryItem { 96 | readonly property bool animationsOn: index >= listView.currentIndex - 1 && 97 | index <= listView.currentIndex + 1 98 | width: listView.delegateWidth 99 | height: listView.height 100 | animationTime: animationsOn ? mainView.animationTime : 0 101 | animationSine: animationsOn ? mainView.animationSine : 0 102 | animState: Math.max(0, (1.0 - Math.abs(topBar.visibilityState - index))) 103 | galleryView: index 104 | fillColor: "transparent" 105 | alphaBlending: true 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/canvaspainter/qcbrush.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #include "qcbrush.h" 6 | #include "qcbrush_p.h" 7 | #include "engine/qcpainterengineutils_p.h" 8 | #include "qdatastream.h" 9 | #include 10 | 11 | QT_BEGIN_NAMESPACE 12 | 13 | /*! 14 | \class QCBrush 15 | \brief QCBrush is the base class for all QCPainter fill / stroke brushes. 16 | \inmodule QtCanvasPainter 17 | 18 | QCBrush is the base class for all styles used for \l QCPainter::fill() 19 | and \l QCPainter::stroke(). 20 | */ 21 | 22 | /*! 23 | Constructs an invalid brush. 24 | */ 25 | 26 | QCBrush::QCBrush() 27 | { 28 | } 29 | 30 | /*! 31 | Constructs a brush that is a copy of the given \a brush. 32 | */ 33 | QCBrush::QCBrush(const QCBrush &brush) noexcept 34 | : baseData(brush.baseData) 35 | { 36 | } 37 | 38 | QCBrush::~QCBrush() = default; 39 | 40 | /*! 41 | Assigns the given \a brush to this brush and returns a reference to 42 | this brush. 43 | */ 44 | 45 | QCBrush &QCBrush::operator=(const QCBrush &brush) noexcept 46 | { 47 | QCBrush(brush).swap(*this); 48 | return *this; 49 | } 50 | 51 | /*! 52 | \fn QCBrush::QCBrush(QCImage &&other) noexcept 53 | 54 | Move-constructs a new QCBrush from \a other. 55 | */ 56 | 57 | /*! 58 | \fn QCBrush &QCBrush::operator=(QCBrush &&other) 59 | 60 | Move-assigns \a other to this QCBrush instance. 61 | */ 62 | 63 | /*! 64 | \fn void QCBrush::swap(QCBrush &other) 65 | \memberswap{brush} 66 | */ 67 | 68 | 69 | /*! 70 | \enum QCBrush::BrushType 71 | 72 | Specifies the type of brush. 73 | 74 | \value Invalid - Empty brush. 75 | 76 | \value LinearGradient - Interpolates colors between start and end points 77 | (QCLinearGradient) 78 | 79 | \value RadialGradient - Interpolates colors between a focal point and end 80 | points on a circle surrounding it (QCRadialGradient). 81 | 82 | \value ConicalGradient - Interpolates colors around a center point 83 | (QCConicalGradient). 84 | 85 | \value BoxGradient - Interpolates colors on a round rectangle 86 | (QCBoxGradient). 87 | 88 | \value BoxShadow - Creates a soft round rectangle shadow (QCBoxShadow). 89 | 90 | \value ImagePattern - Creates a pattern using the specified image and 91 | repetition (QCImagePattern). 92 | 93 | \value GridPattern - Creates a pattern using the specified grid (QCGridPattern). 94 | 95 | \value Custom - Creates a custom shader brush (QCCustomBrush). 96 | 97 | \sa type() 98 | */ 99 | 100 | /*! 101 | Returns the type of the brush. 102 | */ 103 | 104 | QCBrush::BrushType QCBrush::type() const 105 | { 106 | return baseData ? baseData->type : QCBrush::BrushType::Invalid; 107 | } 108 | 109 | // ***** Private ***** 110 | 111 | /*! 112 | \internal 113 | */ 114 | void QCBrush::detach() 115 | { 116 | if (baseData) 117 | baseData.detach(); 118 | } 119 | 120 | QCBrush::QCBrush(QCBrushPrivate *priv) 121 | : baseData(priv) 122 | { 123 | } 124 | 125 | QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QCBrushPrivate); 126 | 127 | /*! 128 | \internal 129 | */ 130 | QCPaint QCBrush::createPaint(QCPainter *painter) const 131 | { 132 | Q_UNUSED(painter) 133 | if (baseData) 134 | return baseData->createPaint(painter); 135 | QCPaint empty; 136 | return empty; 137 | } 138 | 139 | #ifndef QT_NO_DEBUG_STREAM 140 | /*! 141 | \internal 142 | */ 143 | QDebug operator<<(QDebug dbg, const QCBrush &b) 144 | { 145 | QDebugStateSaver saver(dbg); 146 | const auto t = b.type(); 147 | dbg.nospace() << "QCBrush(" << t << ")"; 148 | return dbg; 149 | } 150 | #endif 151 | QT_END_NAMESPACE 152 | -------------------------------------------------------------------------------- /src/canvaspainter/qcpainter_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | // 6 | // W A R N I N G 7 | // ------------- 8 | // 9 | // This file is not part of the Qt API. It exists purely as an 10 | // implementation detail. This header file may change from version to 11 | // version without notice, or even be removed. 12 | // 13 | // We mean it. 14 | // 15 | 16 | #ifndef QCPAINTER_P_H 17 | #define QCPAINTER_P_H 18 | 19 | #include "qcpainter.h" 20 | #include "qcimage.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | QT_BEGIN_NAMESPACE 28 | 29 | class QCPainterEngine; 30 | class QCPainterRhiRenderer; 31 | 32 | Q_DECLARE_LOGGING_CATEGORY(QC_INFO) 33 | 34 | // Keeps count of the texture id's and the total size of textures. 35 | // This doesn't cache the actual texture data. 36 | class QCDataCache 37 | { 38 | public: 39 | inline bool contains(qint64 key) const { return m_data.contains(key); } 40 | inline QCImage image(qint64 key) const { return m_data.value(key); } 41 | inline int textureId(qint64 key) const { return m_data.value(key).id(); } 42 | inline void insert(qint64 key, const QCImage &image) 43 | { 44 | m_dataAmount += image.size(); 45 | m_data.insert(key, image); 46 | } 47 | inline qsizetype dataAmount() const { return m_dataAmount; } 48 | inline qsizetype size() const { return m_data.size(); } 49 | void removeTemporaryResources(); 50 | void removeTextureId(int imageId); 51 | void handleRemoveTextures(); 52 | void markTextureIdUsed(int imageId); 53 | void clear(); 54 | 55 | private: 56 | friend class QCPainterPrivate; 57 | QCPainterPrivate *m_painterPrivate = nullptr; 58 | QHash m_data; 59 | QList m_cleanupTextures; 60 | QList m_usedTextureIDs; 61 | qsizetype m_dataAmount = 0; 62 | bool m_doingResourcesRemoval = false; 63 | }; 64 | 65 | class QRhi; 66 | 67 | class QCPainterPrivate : public QObjectPrivate 68 | { 69 | Q_DECLARE_PUBLIC(QCPainter) 70 | public: 71 | QCPainterPrivate(); 72 | ~QCPainterPrivate(); 73 | QCPainterEngine *engine() const; 74 | 75 | static QCPainterPrivate *get(QCPainter *painter) { return painter->d_func(); } 76 | static const QCPainterPrivate *get(const QCPainter *painter) { return painter->d_func(); } 77 | 78 | qint64 generateImageKey(const QImage &image, QCPainter::ImageFlags flags) const; 79 | QCImage getQCImage(const QImage &image, QCPainter::ImageFlags flags, qint64 imageKey = 0); 80 | QCImage getQCImage(QRhiTexture *texture, QCPainter::ImageFlags flags); 81 | QCImage getQCImage(const QCOffscreenCanvas &canvas, QCPainter::ImageFlags flags); 82 | void drawImageId(int imageId, float x, float y, float width, float height, const QColor &tintColor); 83 | void handleCleanupTextures(); 84 | void clearTextureCache(); 85 | void markTextureIdUsed(int imageId); 86 | 87 | void setFont(const QFont &font); 88 | void fillText(const QString &text, float x, float y, float maxWidth = -1); 89 | void fillText(const QString &text, const QRectF &rect); 90 | QRectF textBoundingBox(const QString &text, float x, float y, float maxWidth = -1); 91 | QRectF textBoundingBox(const QString &text, const QRectF &rect); 92 | 93 | QCDataCache m_dataCache; 94 | QHash m_nativeTextureCache; 95 | float m_devicePixelRatio = 1.0f; 96 | QCPainterRhiRenderer *m_renderer = nullptr; 97 | QCPainterEngine *m_e = nullptr; 98 | int m_maxTextures = 0; 99 | bool m_trackingDisabled = false; 100 | }; 101 | 102 | QT_END_NAMESPACE 103 | 104 | #endif // QCPAINTER_P_H 105 | -------------------------------------------------------------------------------- /examples/canvaspainter/gallery/TopBar.qml: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2015 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 4 | 5 | import QtQuick 2.0 6 | 7 | Item { 8 | id: root 9 | 10 | property int currentIndex: 0 11 | property real visibilityState: 0 12 | property int itemCount: 0 13 | property string groupTitle 14 | property string title 15 | 16 | onCurrentIndexChanged: { 17 | switch (root.currentIndex) { 18 | case 0: 19 | groupTitle = "Brushes"; 20 | title = "Gradients and Image Patterns"; 21 | break; 22 | case 1: 23 | groupTitle = "Brushes"; 24 | title = "Images"; 25 | break; 26 | case 2: 27 | groupTitle = "Brushes"; 28 | title = "Grid Patterns"; 29 | break; 30 | case 3: 31 | groupTitle = "Brushes"; 32 | title = "Shadows"; 33 | break; 34 | case 4: 35 | groupTitle = "Brushes"; 36 | title = "Custom Brushes"; 37 | break; 38 | case 5: 39 | groupTitle = "Painting"; 40 | title = "Paths, Caps & Joins"; 41 | break; 42 | case 6: 43 | groupTitle = "Painting"; 44 | title = "Painter Paths"; 45 | break; 46 | case 7: 47 | groupTitle = "Painting"; 48 | title = "States, Transitions and Clipping"; 49 | break; 50 | case 8: 51 | groupTitle = "Painting"; 52 | title = "Antialiasing and Line Width"; 53 | break; 54 | case 9: 55 | groupTitle = "Painting"; 56 | title = "Composite Modes"; 57 | break; 58 | case 10: 59 | groupTitle = "Painting"; 60 | title = "Color Effects"; 61 | break; 62 | case 11: 63 | groupTitle = "Text"; 64 | title = "Fonts and Styles"; 65 | break; 66 | case 12: 67 | groupTitle = "Text"; 68 | title = "Brushes"; 69 | break; 70 | case 13: 71 | groupTitle = "Text"; 72 | title = "Alignment"; 73 | break; 74 | case 14: 75 | groupTitle = "Text"; 76 | title = "Wrapping"; 77 | break; 78 | } 79 | } 80 | 81 | Text { 82 | id: groupTextItem 83 | anchors.horizontalCenter: parent.horizontalCenter 84 | anchors.bottom: titleTextItem.top 85 | font.pixelSize: 12 * dp 86 | color: "#DFD0B8" 87 | text: groupTitle 88 | } 89 | Text { 90 | id: titleTextItem 91 | anchors.horizontalCenter: parent.horizontalCenter 92 | anchors.verticalCenter: parent.verticalCenter 93 | anchors.verticalCenterOffset: 8 * dp 94 | font.pixelSize: 20 * dp 95 | color: "#DFD0B8" 96 | text: title 97 | } 98 | Row { 99 | anchors.top: titleTextItem.bottom 100 | anchors.topMargin: 6 * dp 101 | anchors.horizontalCenter: parent.horizontalCenter 102 | spacing: 4 * dp 103 | Repeater { 104 | model: root.itemCount 105 | Rectangle { 106 | // Between 0..1 when the page indicator is highligted 107 | readonly property real animState: Math.max(0, (1.0 - Math.abs(root.visibilityState - index))) 108 | width: height + 16 * dp * animState 109 | height: 8 * dp 110 | radius: width/2 111 | color: "#948979" 112 | border.width: 1 113 | border.color: "#DFD0B8" 114 | opacity: 0.2 + 0.8 * animState 115 | } 116 | } 117 | } 118 | } 119 | 120 | -------------------------------------------------------------------------------- /examples/canvaspainter/compacthealth/mainwindow.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause 3 | 4 | #ifndef MAINWINDOW_H 5 | #define MAINWINDOW_H 6 | 7 | #include "painterwindow.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "ecggraph.h" 15 | #include "theme.h" 16 | 17 | class MainWindow : public PainterWindow 18 | { 19 | 20 | public: 21 | MainWindow(QRhi::Implementation api); 22 | ~MainWindow(); 23 | 24 | protected: 25 | void paint(QCPainter *p) override; 26 | void touchEvent(QTouchEvent *ev) override; 27 | void resizeEvent(QResizeEvent *ev) override; 28 | 29 | private: 30 | friend class ECGGraph; 31 | 32 | enum class Dirty { 33 | TemperatureBars = 0x0001, 34 | GraphGrid = 0x0002, 35 | ActivitySlider = 0x0004, 36 | ViewBackgrounds = 0x0008, 37 | All = 0xFFFF 38 | }; 39 | Q_DECLARE_FLAGS(DirtyFlags, Dirty) 40 | 41 | enum PathGroups { 42 | // Paths which basically change only when resizing window. 43 | StaticPaths = 1, // TODO: Why text rendering fails if this is 0? 44 | // Paths for graphs which don't update on every frame (e.g. temperature graph). 45 | GraphPaths, 46 | // Paths for activity slider, changes only when adjusted. 47 | ActivitySliderPaths 48 | }; 49 | 50 | void initializeTempData(); 51 | void initializeRespData(); 52 | void updateViewSizes(); 53 | void paintTempBars(float x, float y, float w, float h); 54 | void paintRespGraph(float x, float y, float w, float h); 55 | void paintSlider(float x, float y, float w, float h); 56 | void paintGrid(float x, float y, float w, float h); 57 | void buttonClicked(int buttonID); 58 | void animateData(); 59 | void updateRespData(); 60 | void updateWarnings(); 61 | 62 | QCPainter *m_painter; 63 | QTimer m_timer; 64 | QElapsedTimer m_elapsedTimer; 65 | bool m_initialized = false; 66 | bool m_showSettings = true; 67 | DirtyFlags m_dirty = { Dirty::All }; 68 | float m_px = 1.0f; 69 | float m_margin = 0.0f; 70 | float m_activity = 0.2f; 71 | // Current pulse 72 | float m_hr = 82.0f; 73 | // Current body temperature 74 | float m_temperature = 37.0f; 75 | float m_temperatureMax = 43.0f; 76 | float m_temperatureMin = 35.0f; 77 | // How often temperature graph is updated 78 | int m_temperatureLogMs = 1000; 79 | float m_spo2 = 99.0f; 80 | // AirWay Respiratory Rate 81 | float m_awrr = 12.5; 82 | QCPainterPath m_tempBarsPath; 83 | QList m_tempData; 84 | int m_tempDataCount = 64; 85 | 86 | QList m_respData; 87 | int m_respDataCount = 256; 88 | 89 | ECGGraph m_ecgGraph; 90 | 91 | QRectF m_sliderRect; 92 | float m_sliderMarginTop = 0; 93 | float m_sliderMarginBottom = 0; 94 | int m_selectedButton = 0; 95 | 96 | struct View { 97 | QRectF rect; 98 | QString title; 99 | bool fillBackground = true; 100 | }; 101 | 102 | enum Views { 103 | W1, 104 | W2, 105 | W3, 106 | W4, 107 | Center, 108 | Slider, 109 | B1, 110 | B2, 111 | B3, 112 | ViewsEnd, 113 | }; 114 | View m_views[ViewsEnd]; 115 | // These views will be shows with warning box 116 | QSet m_warningViews; 117 | 118 | Theme m_theme; 119 | float m_iconSize = 20; 120 | QCImage m_b1ImageLight; 121 | QCImage m_b1ImageDark; 122 | QCImage m_b2ImageLight; 123 | QCImage m_b2ImageDark; 124 | QCImage m_b3ImageLight; 125 | QCImage m_b3ImageDark; 126 | QCImage m_sImageLight; 127 | QCImage m_sImageDark; 128 | 129 | QFont m_titleFont; 130 | QFont m_bigFont; 131 | }; 132 | 133 | #endif // MAINWINDOW_H 134 | -------------------------------------------------------------------------------- /tools/qcshadergen/qcshadergen.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace Qt::StringLiterals; 12 | 13 | static void printError(const char *msg, ...) 14 | { 15 | va_list arglist; 16 | va_start(arglist, msg); 17 | vfprintf(stderr, msg, arglist); 18 | fputs("\n", stderr); 19 | va_end(arglist); 20 | } 21 | 22 | static QByteArray getSnippet(const QByteArray &name) 23 | { 24 | const QString fileName = ":/"_L1 + QString::fromUtf8(name); 25 | QFile f(fileName); 26 | if (f.open(QIODevice::ReadOnly | QIODevice::Text)) 27 | return f.readAll(); 28 | return {}; 29 | } 30 | 31 | static bool process(const QString &inputFile, const QString &outputFile) 32 | { 33 | QFile inFile(inputFile); 34 | if (!inFile.open(QIODevice::ReadOnly | QIODevice::Text)) { 35 | printError("Failed to open %s", qPrintable(inputFile)); 36 | return false; 37 | } 38 | 39 | QByteArray content = inFile.readAll(); 40 | 41 | QDir().mkpath(QFileInfo(outputFile).path()); 42 | QFile outFile(outputFile); 43 | if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) { 44 | printError("Filed to create %s", qPrintable(outputFile)); 45 | return false; 46 | } 47 | 48 | qsizetype pos = 0; 49 | for (; ;) { 50 | const qsizetype foundPos = content.indexOf("QC_INCLUDE ", pos); 51 | if (foundPos == -1) 52 | break; 53 | 54 | const qsizetype openQuotePos = content.indexOf('\"', foundPos + 1); 55 | if (openQuotePos != -1) { 56 | const qsizetype closeQuotePos = content.indexOf('\"', openQuotePos + 1); 57 | if (closeQuotePos != -1) { 58 | const QByteArray name = content.mid(openQuotePos + 1, closeQuotePos - openQuotePos - 1); 59 | const QByteArray sourceCode = getSnippet(name); 60 | if (sourceCode.isEmpty()) { 61 | qWarning("Unrecognized name in QC_INCLUDE statement: %s", name.constData()); 62 | } else { 63 | content.replace(foundPos, closeQuotePos - foundPos + 1, sourceCode); 64 | } 65 | } else { 66 | qWarning("No closing double quote found for QC_INCLUDE"); 67 | } 68 | } else { 69 | qWarning("No opening double quote found for QC_INCLUDE"); 70 | } 71 | pos = foundPos + 1; 72 | } 73 | 74 | outFile.write(content); 75 | 76 | return true; 77 | } 78 | 79 | int main(int argc, char **argv) 80 | { 81 | QCoreApplication app(argc, argv); 82 | 83 | QCommandLineParser cmdLineParser; 84 | const QString appDesc = "Qt Canvas Painter Shader Generator"_L1; 85 | cmdLineParser.setApplicationDescription(appDesc); 86 | app.setApplicationVersion(QLatin1String(QT_VERSION_STR)); 87 | cmdLineParser.addHelpOption(); 88 | cmdLineParser.addVersionOption(); 89 | 90 | cmdLineParser.addPositionalArgument(QLatin1String("file"), 91 | QObject::tr("Vulkan GLSL source file to preprocess. QC_INCLUDE statements will get replaced with the appropriate source code. " 92 | "The file extension must be .vert or .frag." 93 | ), 94 | QObject::tr("file")); 95 | 96 | QCommandLineOption outputOption({ "o", "output" }, 97 | QObject::tr("Output file."), 98 | QObject::tr("filename")); 99 | cmdLineParser.addOption(outputOption); 100 | 101 | cmdLineParser.process(app); 102 | 103 | if (cmdLineParser.positionalArguments().isEmpty()) { 104 | cmdLineParser.showHelp(); 105 | return 0; 106 | } 107 | 108 | if (cmdLineParser.isSet(outputOption)) { 109 | const QString inputFile = cmdLineParser.positionalArguments().first(); 110 | const QString outputFile = cmdLineParser.value(outputOption); 111 | if (!process(inputFile, outputFile)) 112 | return 1; 113 | } else { 114 | printError("No output file specified"); 115 | } 116 | 117 | return 0; 118 | } 119 | -------------------------------------------------------------------------------- /src/canvaspainter/qcpainterpath.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCPAINTERPATH_H 5 | #define QCPAINTERPATH_H 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | QT_BEGIN_NAMESPACE 13 | 14 | class QCPainterPathPrivate; 15 | class QTransform; 16 | 17 | class Q_CANVASPAINTER_EXPORT QCPainterPath 18 | { 19 | public: 20 | 21 | QCPainterPath(); 22 | QCPainterPath(qsizetype commandsSize, qsizetype commandsDataSize = -1); 23 | QCPainterPath(const QCPainterPath &path) noexcept; 24 | ~QCPainterPath(); 25 | 26 | QCPainterPath &operator=(const QCPainterPath &path) noexcept; 27 | QCPainterPath(QCPainterPath &&other) noexcept = default; 28 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QCPainterPath) 29 | inline void swap(QCPainterPath &other) noexcept { qt_ptr_swap(d_ptr, other.d_ptr); } 30 | 31 | bool operator==(const QCPainterPath &path) const; 32 | inline bool operator!=(const QCPainterPath &path) const { return !(operator==(path)); } 33 | operator QVariant() const; 34 | 35 | // Path commands 36 | // These should match to path methods of QCPainter for consistency. 37 | void closePath(); 38 | void moveTo(float x, float y); 39 | void moveTo(QPointF point); 40 | void lineTo(float x, float y); 41 | void lineTo(QPointF point); 42 | void bezierCurveTo(float c1x, float c1y, float c2x, float c2y, float x, float y); 43 | void bezierCurveTo( 44 | QPointF controlPoint1, QPointF controlPoint2, QPointF endPoint); 45 | void quadraticCurveTo(float cx, float cy, float x, float y); 46 | void quadraticCurveTo(QPointF controlPoint, QPointF endPoint); 47 | void arcTo(float c1x, float c1y, float c2x, float c2y, float radius); 48 | void arcTo(QPointF controlPoint1, QPointF controlPoint2, float radius); 49 | void arc( 50 | float centerX, 51 | float centerY, 52 | float radius, 53 | float a0, 54 | float a1, 55 | QCPainter::PathWinding direction = QCPainter::PathWinding::ClockWise, 56 | bool isConnected = true); 57 | void arc( 58 | QPointF centerPoint, 59 | float radius, 60 | float a0, 61 | float a1, 62 | QCPainter::PathWinding direction = QCPainter::PathWinding::ClockWise, 63 | bool isConnected = true); 64 | void rect(float x, float y, float width, float height); 65 | void rect(const QRectF &rect); 66 | void roundRect(float x, float y, float width, float height, float radius); 67 | void roundRect(const QRectF &rect, float radius); 68 | void roundRect( 69 | float x, 70 | float y, 71 | float width, 72 | float height, 73 | float radiusTopLeft, 74 | float radiusTopRight, 75 | float radiusBottomRight, 76 | float radiusBottomLeft); 77 | void roundRect( 78 | const QRectF &rect, 79 | float radiusTopLeft, 80 | float radiusTopRight, 81 | float radiusBottomRight, 82 | float radiusBottomLeft); 83 | void ellipse(float x, float y, float radiusX, float radiusY); 84 | void ellipse(const QRectF &rect); 85 | void circle(float x, float y, float radius); 86 | void circle(QPointF centerPoint, float radius); 87 | 88 | void setPathWinding(QCPainter::PathWinding winding); 89 | void addPath(const QCPainterPath &path, const QTransform &transform = QTransform()); 90 | void addPath(const QCPainterPath &path, qsizetype start, qsizetype count, const QTransform &transform = QTransform()); 91 | 92 | // Memory and size management 93 | bool isEmpty() const; 94 | void clear(); 95 | void squeeze(); 96 | qsizetype commandsSize() const; 97 | qsizetype commandsDataSize() const; 98 | qsizetype commandsCapacity() const; 99 | qsizetype commandsDataCapacity() const; 100 | void reserve(qsizetype commandsSize, qsizetype commandsDataSize = -1); 101 | 102 | // Other 103 | QPointF currentPosition() const; 104 | QPointF positionAt(qsizetype index) const; 105 | [[nodiscard]] QCPainterPath sliced(qsizetype start, qsizetype count, const QTransform &transform = QTransform()) const &; 106 | 107 | private: 108 | friend class QCPainterEngine; 109 | friend class QCPainterRhiRenderer; 110 | 111 | Q_DECLARE_PRIVATE(QCPainterPath) 112 | QCPainterPathPrivate *d_ptr; 113 | 114 | }; 115 | 116 | QT_END_NAMESPACE 117 | 118 | #endif // QCPAINTERPATH_H 119 | -------------------------------------------------------------------------------- /src/canvaspainter/engine/qcdistancefieldglyphcache_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCDISTANCEFIELDGLYPHCACHE_P_H 5 | #define QCDISTANCEFIELDGLYPHCACHE_P_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists purely as an 12 | // implementation detail. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include "engine/qcpainterengineutils_p.h" 19 | #include "engine/qcrhidistancefieldglyphcache_p.h" 20 | #include 21 | #include 22 | 23 | QT_BEGIN_NAMESPACE 24 | 25 | class QCDistanceFieldGlyphCache 26 | { 27 | public: 28 | // A FontKey map holding 2 values: The previous QRhiTexture * if the texture is updated, and the glyph cache with the 29 | // new texture. Currently there is one texture each 30 | struct FontKeyData 31 | { 32 | QRhiTexture *prevTextureState = nullptr; 33 | QCRhiDistanceFieldGlyphCache *nativeGlyphCache = nullptr; 34 | QRawFont rawFont; 35 | }; 36 | 37 | struct FontKey 38 | { 39 | FontKey(const QRawFont &font); 40 | 41 | QFontEngine::FaceId faceId; 42 | QFont::Style style; 43 | int weight; 44 | QString familyName; 45 | QString styleName; 46 | }; 47 | 48 | struct GlyphCacheKey 49 | { 50 | FontKey fontKey; 51 | QString text; 52 | QCPainter::TextAlign textAlign; 53 | QCPainter::WrapMode wrapMode; 54 | float pixelSize; 55 | float lineWidth; 56 | float letterSpacing; 57 | float wordSpacing; 58 | }; 59 | 60 | struct GlyphCacheValue 61 | { 62 | QList runs; 63 | QRectF rect; 64 | int usageCounter = 0; 65 | }; 66 | 67 | QCDistanceFieldGlyphCache(QRhi *rhi); 68 | ~QCDistanceFieldGlyphCache(); 69 | 70 | std::tuple, std::vector> 71 | generate(const QString &text, const QRectF &rect, const QFont &font, QCState *state, QCPainter::TextAlign alignment); 72 | 73 | void commitResourceUpdates(QRhiResourceUpdateBatch *batch); 74 | 75 | QRhiTexture *getCurrentTextures(const FontKey &key) const; 76 | QRhiTexture *getOldTextures(const FontKey &key) const; 77 | 78 | void setOldTexture(FontKey key, QRhiTexture *tex); 79 | void optimizeCache(); 80 | 81 | private: 82 | QList generateGlyphRuns(const QString &text, const QRectF &rect, 83 | const QFont &font, const QFontMetrics &metrics, 84 | QCState *state, QCPainter::TextAlign alignment); 85 | QHash m_glyphCaches; 86 | QRhi *m_rhi; 87 | QTextLayout m_layout; 88 | #ifdef QCPAINTER_CACHE_GLYPH_RUNS 89 | QHash m_glyphRunCache; 90 | #endif 91 | 92 | private: 93 | friend bool operator==(const FontKey &f1, const FontKey &f2); 94 | friend size_t qHash(const FontKey &f, size_t seed); 95 | 96 | }; 97 | 98 | inline bool operator==( 99 | const QCDistanceFieldGlyphCache::FontKey &f1, const QCDistanceFieldGlyphCache::FontKey &f2) 100 | { 101 | return f1.faceId == f2.faceId && f1.style == f2.style && f1.weight == f2.weight 102 | && f1.familyName == f2.familyName && f1.styleName == f2.styleName; 103 | } 104 | 105 | inline size_t qHash(const QCDistanceFieldGlyphCache::FontKey &f, size_t seed = 0) 106 | { 107 | return qHashMulti(seed, f.faceId, f.familyName, f.styleName, f.style, f.weight); 108 | } 109 | 110 | inline bool operator==( 111 | const QCDistanceFieldGlyphCache::GlyphCacheKey &a, const QCDistanceFieldGlyphCache::GlyphCacheKey &b) 112 | { 113 | return a.fontKey == b.fontKey && qFuzzyCompare(a.pixelSize, b.pixelSize) 114 | && a.text == b.text && a.textAlign == b.textAlign 115 | && a.wrapMode == b.wrapMode && qFuzzyCompare(a.lineWidth, b.lineWidth) 116 | && qFuzzyCompare(a.letterSpacing, b.letterSpacing) 117 | && qFuzzyCompare(a.wordSpacing, b.wordSpacing); 118 | } 119 | 120 | inline bool operator!=( 121 | const QCDistanceFieldGlyphCache::GlyphCacheKey &a, const QCDistanceFieldGlyphCache::GlyphCacheKey &b) 122 | { 123 | return !(a == b); 124 | } 125 | 126 | inline size_t qHash(const QCDistanceFieldGlyphCache::GlyphCacheKey &k, size_t seed = 0) 127 | { 128 | return qHashMulti(seed, k.fontKey, k.text, k.textAlign, k.wrapMode, k.lineWidth, 129 | k.letterSpacing, k.wordSpacing, k.pixelSize); 130 | } 131 | 132 | QT_END_NAMESPACE 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /tests/auto/qcpainterpath/tst_qcpainterpath.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "qcpainterpath.h" 9 | #include "qcpainter.h" 10 | 11 | class tst_QCPainterPath : public QObject 12 | { 13 | Q_OBJECT 14 | 15 | private slots: 16 | // Path autotests 17 | void testConstructors(); 18 | void testEqual(); 19 | void testAppending(); 20 | void testSlicing(); 21 | }; 22 | 23 | void tst_QCPainterPath::testConstructors() 24 | { 25 | QCPainterPath p1; 26 | QVERIFY(p1.isEmpty()); 27 | // Note: Currently there is no initial capasity. 28 | QCOMPARE(p1.commandsCapacity(), 0); 29 | QCOMPARE(p1.commandsDataCapacity(), 0); 30 | QCPainterPath p2(10); 31 | QCOMPARE(p2.commandsCapacity(), 10); 32 | QCOMPARE(p2.commandsDataCapacity(), 20); 33 | QCPainterPath p3(10, 40); 34 | QCOMPARE(p3.commandsCapacity(), 10); 35 | QCOMPARE(p3.commandsDataCapacity(), 40); 36 | QCPainterPath p4(p3); 37 | QCOMPARE(p4.commandsCapacity(), 10); 38 | QCOMPARE(p4.commandsDataCapacity(), 40); 39 | QCPainterPath p5 = p4; 40 | QCOMPARE(p5.commandsCapacity(), 10); 41 | QCOMPARE(p5.commandsDataCapacity(), 40); 42 | 43 | p5.reserve(23); 44 | QCOMPARE(p5.commandsCapacity(), 23); 45 | QCOMPARE(p5.commandsDataCapacity(), 2 * 23); 46 | p5.reserve(15, 51); 47 | QCOMPARE(p5.commandsCapacity(), 15); 48 | QCOMPARE(p5.commandsDataCapacity(), 51); 49 | } 50 | 51 | void tst_QCPainterPath::testEqual() 52 | { 53 | QCPainterPath p1; 54 | QCPainterPath p2; 55 | QCOMPARE(p1, p2); 56 | QCOMPARE(p1.isEmpty(), true); 57 | 58 | p1.moveTo(10, 20); 59 | QCOMPARE_NE(p1, p2); 60 | p2.moveTo(10, 20); 61 | QCOMPARE(p1, p2); 62 | p1.lineTo(30, 40); 63 | QCOMPARE_NE(p1, p2); 64 | p2.lineTo(30, 40); 65 | QCOMPARE(p1, p2); 66 | p1.rect(1, 2, 3, 4); 67 | QCOMPARE_NE(p1, p2); 68 | p2 = p1; 69 | QCOMPARE(p1, p2); 70 | 71 | p2.clear(); 72 | QCOMPARE(p2.isEmpty(), true); 73 | QCOMPARE_NE(p1, p2); 74 | p1.clear(); 75 | QCOMPARE(p1.isEmpty(), true); 76 | QCOMPARE(p1, p2); 77 | } 78 | 79 | void tst_QCPainterPath::testAppending() 80 | { 81 | { 82 | // addPath, full 83 | QCPainterPath p1; 84 | p1.moveTo(0, 100); 85 | p1.lineTo(50, 100); 86 | p1.lineTo(100, 50); 87 | p1.lineTo(150, 100); 88 | QCOMPARE(p1.commandsSize(), 4); 89 | 90 | QCPainterPath p2; 91 | p2.addPath(p1); 92 | QCOMPARE(p1, p2); 93 | p2.addPath(p1); 94 | QCOMPARE(p2.commandsSize(), 8); 95 | 96 | QCPainterPath p3; 97 | QTransform tIdentity; 98 | p3.addPath(p1, tIdentity); 99 | QCOMPARE(p1, p3); 100 | 101 | QCPainterPath p4; 102 | QTransform t2; 103 | t2.rotate(20); 104 | p4.addPath(p1, t2); 105 | QCOMPARE_NE(p1, p4); 106 | } 107 | 108 | { 109 | // addPath, parts 110 | QCPainterPath p2; 111 | p2.moveTo(1, 1); 112 | p2.lineTo(2, 1); 113 | p2.lineTo(3, 1); 114 | p2.lineTo(4, 1); 115 | QCPainterPath p3; 116 | p3.moveTo(1, 1); 117 | p3.lineTo(2, 1); 118 | p3.lineTo(3, 1); 119 | //p3.lineTo(4, 1); // Not adding this 120 | QCPainterPath p4; 121 | //p4.moveTo(1, 1); // Not adding this 122 | p4.lineTo(2, 1); 123 | p4.lineTo(3, 1); 124 | //p4.lineTo(4, 1); // Not adding this 125 | 126 | QCOMPARE_NE(p2, p3); 127 | QCPainterPath p5; 128 | p5.addPath(p2, 0, p2.commandsSize()); 129 | QCOMPARE(p2, p5); // 1, 2, 3, 4 130 | QCPainterPath p6; 131 | p6.addPath(p2, 0, p2.commandsSize() - 1); 132 | QCOMPARE(p3, p6); // 1, 2, 3 133 | QCPainterPath p7; 134 | p7.addPath(p2, 1, 2); 135 | QCOMPARE(p4, p7); // 2, 3 136 | } 137 | } 138 | 139 | void tst_QCPainterPath::testSlicing() 140 | { 141 | QCPainterPath p1; 142 | p1.moveTo(1, 1); 143 | p1.lineTo(2, 1); 144 | p1.lineTo(3, 1); 145 | p1.lineTo(4, 1); 146 | QCOMPARE(p1.commandsSize(), 4); 147 | QCOMPARE(p1.commandsDataSize(), 8); 148 | QCPainterPath p2 = p1.sliced(0, p1.commandsSize()); 149 | QCOMPARE(p2.commandsSize(), 4); 150 | QCOMPARE(p2.commandsDataSize(), 8); 151 | QCOMPARE(p1, p2); 152 | QCPainterPath p3 = p1.sliced(0, p1.commandsSize() - 1); 153 | QCOMPARE(p3.commandsSize(), 3); 154 | QCOMPARE(p3.commandsDataSize(), 6); 155 | QCPainterPath p4 = p1.sliced(1, p1.commandsSize() - 1); 156 | QCOMPARE(p4.commandsSize(), 3); 157 | QCOMPARE(p4.commandsDataSize(), 6); 158 | QCPainterPath p5 = p1.sliced(1, p1.commandsSize() - 2); 159 | QCOMPARE(p5.commandsSize(), 2); 160 | QCOMPARE(p5.commandsDataSize(), 4); 161 | } 162 | 163 | QTEST_MAIN(tst_QCPainterPath) 164 | #include 165 | -------------------------------------------------------------------------------- /src/canvaspainter/qcdebug.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // Copyright (C) 2018 QUIt Coding 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 4 | 5 | #include "qcdebug_p.h" 6 | #include "qcpainter_p.h" 7 | #include "engine/qcpainterengine_p.h" 8 | 9 | QT_BEGIN_NAMESPACE 10 | 11 | QCDebug::QCDebug() 12 | : m_debugNsElapsed(0) 13 | , m_debugCounter(0) 14 | , m_debugMsElapsed(QLatin1String("0.000")) 15 | { 16 | } 17 | 18 | void QCDebug::start() 19 | { 20 | m_debugTimer.start(); 21 | } 22 | 23 | void QCDebug::paintDrawDebug(QCPainter *painter, float width, float height) 24 | { 25 | if (!painter) 26 | return; 27 | 28 | auto *painterPriv = QCPainterPrivate::get(painter); 29 | if (!painterPriv->m_e) 30 | return; 31 | 32 | m_drawDebug = painterPriv->m_e->drawDebug(); 33 | 34 | qint64 elapsed = m_debugTimer.nsecsElapsed(); 35 | m_debugNsElapsed += elapsed; 36 | m_debugCounter++; 37 | if (!m_debugUpdateTimer.isValid()) 38 | m_debugUpdateTimer.start(); 39 | 40 | // How often time is updated, in seconds 41 | // Longer period increases accuracy 42 | const int UPDATE_FREQUENCY_MS = 1000; 43 | if (m_debugUpdateTimer.elapsed() >= UPDATE_FREQUENCY_MS) { 44 | qint64 ms = 1000000; 45 | double msElapsed = double(m_debugNsElapsed) / (ms * m_debugCounter); 46 | m_debugMsElapsed = QString::number(msElapsed, 'f', 3); 47 | m_debugNsElapsed = 0; 48 | m_debugCounter = 0; 49 | m_debugUpdateTimer.start(); 50 | } 51 | //float fontSize = qMin(QCPainter::ptToPx(14), width*0.04f); 52 | float fontSize = 14.0f; 53 | float margin = fontSize * 0.2f; 54 | float debugHeight = fontSize * 5.0f + margin * 3.0f; 55 | float debugWidth = qMin(width, 28 * fontSize); 56 | float debugY = height - debugHeight; 57 | // Note: Returning these state settings back 58 | // shouldn't be needed as this debug is painted 59 | // as the very last thing. 60 | painter->resetTransform(); 61 | painter->setAntialias(1.0f); 62 | painter->setGlobalCompositeOperation(QCPainter::CompositeOperation::SourceOver); 63 | painter->resetClipping(); 64 | 65 | // Background 66 | painter->setFillStyle(QColor::fromRgba(0xB0000000)); 67 | painter->fillRect(0, debugY, debugWidth, debugHeight); 68 | 69 | // Texts 70 | static const QString debugText1 = QStringLiteral(u"DRAWCALLS:"); 71 | static const QString debugText2 = QStringLiteral(u"FILL"); 72 | static const QString debugText3 = QStringLiteral(u"STROKE"); 73 | static const QString debugText4 = QStringLiteral(u"TEXT"); 74 | static const QString debugText5 = QStringLiteral(u"TOTAL"); 75 | static const QString debugText6 = QStringLiteral(u"TRIANGLES:"); 76 | QFont font; 77 | font.setPixelSize(fontSize); 78 | painter->setFont(font); 79 | painter->setTextAlign(QCPainter::TextAlign::Left); 80 | painter->setTextBaseline(QCPainter::TextBaseline::Top); 81 | painter->setFillStyle(0xFFFFFFFF); 82 | // Draw calls and triangles table 83 | float textY = debugY; 84 | float cellWidth = debugWidth / 6.0f; 85 | painter->fillText(debugText2, margin + 2.0f * cellWidth, textY); 86 | painter->fillText(debugText3, margin + 3.0f * cellWidth, textY); 87 | painter->fillText(debugText4, margin + 4.0f * cellWidth, textY); 88 | painter->fillText(debugText5, margin + 5.0f * cellWidth, textY); 89 | textY += fontSize + margin; 90 | painter->fillText(debugText1, margin, textY); 91 | painter->fillText(QString::number(m_drawDebug.fillDrawCallCount), 92 | margin + 2.0f * cellWidth, textY); 93 | painter->fillText(QString::number(m_drawDebug.strokeDrawCallCount), 94 | margin + 3.0f * cellWidth, textY); 95 | painter->fillText(QString::number(m_drawDebug.textDrawCallCount), 96 | margin + 4.0f * cellWidth, textY); 97 | painter->fillText(QString::number(m_drawDebug.drawCallCount), 98 | margin + 5.0f * cellWidth, textY); 99 | textY += fontSize + margin; 100 | painter->fillText(debugText6, margin, textY); 101 | painter->fillText(QString::number(m_drawDebug.fillTriangleCount), 102 | margin + 2.0f * cellWidth, textY); 103 | painter->fillText(QString::number(m_drawDebug.strokeTriangleCount), 104 | margin + 3.0f * cellWidth, textY); 105 | painter->fillText(QString::number(m_drawDebug.textTriangleCount), 106 | margin + 4.0f * cellWidth, textY); 107 | painter->fillText(QString::number(m_drawDebug.triangleCount), 108 | margin + 5.0f * cellWidth, textY); 109 | // Textures and timing info 110 | textY = height - fontSize * 1.5f; 111 | int textures = painter->cacheTextureAmount(); 112 | int textureMem = painter->cacheMemoryUsage(); 113 | QString debugText7 = QStringLiteral("IMAGES: %1, MEM: %2 kB, TIME: %3 ms") 114 | .arg(textures).arg(textureMem).arg(m_debugMsElapsed); 115 | painter->fillText(debugText7, margin, textY); 116 | } 117 | 118 | QT_END_NAMESPACE 119 | -------------------------------------------------------------------------------- /licenseRule.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "comment": ["file_pattern_ending: strings matched against the end of a file name.", 4 | "location keys: regular expression matched against the beginning of", 5 | "the file path (relative to the git submodule root).", 6 | "spdx: list of SPDX-License-Expression's allowed in the matching files.", 7 | "-------------------------------------------------------", 8 | "Files with the following endings are Build System licensed,", 9 | "unless they are examples", 10 | "Files with other endings can also be build system files" 11 | ], 12 | "file_pattern_ending": ["CMakeLists.txt", ".cmake", ".pro", ".pri", ".prf", 13 | "configure", "configure.bat", "cmake.in", "plist.in", "CMakeLists.txt.in", 14 | ".cmake.conf", ".tag", ".yaml", "ci_config_linux.json", 15 | "configure.json", ".qrc"], 16 | "location": { 17 | "": { 18 | "comment": "Default", 19 | "file type": "build system", 20 | "spdx": ["BSD-3-Clause"] 21 | }, 22 | "(.*)(examples/|snippets/)": { 23 | "comment": "Example takes precedence", 24 | "file type": "examples and snippets", 25 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 26 | } 27 | } 28 | }, 29 | { 30 | "comments": ["Files with the following endings are infrastructure licensed"], 31 | "file_pattern_ending": [".gitattributes", ".gitignore", ".gitmodules", ".gitreview", 32 | "_clang-format", "licenseRule.json", "REUSE.toml"], 33 | "location":{ 34 | "": { 35 | "comment": "Default", 36 | "file type": "infrastructure", 37 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 38 | } 39 | } 40 | }, 41 | { 42 | "comments": ["Files with the following endings are Tool licensed,", 43 | "unless they are examples.", 44 | "Files with other endings can also be tool files."], 45 | "file_pattern_ending": [".sh", ".py", ".pl", ".bat", ".ps1"], 46 | "location":{ 47 | "": { 48 | "comment": "Default", 49 | "file type": "tools and utils", 50 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0"] 51 | }, 52 | "(.*)(examples/|snippets/)": { 53 | "comment": "Example takes precedence", 54 | "file type": "examples and snippets", 55 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 56 | } 57 | } 58 | }, 59 | { 60 | "comment": "Files with the following endings are Documentation licensed.", 61 | "file_pattern_ending": [".qdoc", ".qdocinc" , ".qdocconf", "README", "qt_attribution.json", 62 | ".css"], 63 | "location":{ 64 | "": { 65 | "comment": "", 66 | "file type": "documentation", 67 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"] 68 | } 69 | } 70 | }, 71 | { 72 | "comment": ["All other files", 73 | "The licensing is defined only by the file location in the Qt module repository.", 74 | "NO key for this case!", 75 | "This needs to be the last entry of the file."], 76 | "location": { 77 | "": { 78 | "comment": "Default", 79 | "file type": "module and plugin", 80 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 81 | }, 82 | "dist/": { 83 | "comment": "Default", 84 | "file type": "documentation", 85 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"] 86 | }, 87 | "src/": { 88 | "comment": "Default", 89 | "file type": "module and plugin", 90 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 91 | }, 92 | "tools/": { 93 | "comment": "Default", 94 | "file type": "tools and utils", 95 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0"] 96 | }, 97 | "tests/": { 98 | "comment": "Default", 99 | "file type": "test", 100 | "spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"] 101 | }, 102 | "(.*)(examples/|snippets/)": { 103 | "comment": "Default", 104 | "file type": "examples and snippets", 105 | "spdx": ["LicenseRef-Qt-Commercial OR BSD-3-Clause"] 106 | }, 107 | ".*doc/images/": { 108 | "comment": "Default", 109 | "file type": "documentation", 110 | "spdx": ["LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only"] 111 | } 112 | } 113 | } 114 | ] 115 | -------------------------------------------------------------------------------- /tools/qcshadergen/Qt6CanvasPainterMacros.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 The Qt Company Ltd. 2 | # SPDX-License-Identifier: BSD-3-Clause 3 | 4 | function(_qc_internal_add_shaders_impl target resourcename) 5 | cmake_parse_arguments( 6 | arg 7 | "_QT_INTERNAL" 8 | "PREFIX;BASE;OUTPUT_TARGETS" 9 | "FILES;OUTPUTS;DEFINES" 10 | ${ARGN} 11 | ) 12 | 13 | set(qsb_outputs ${arg_OUTPUTS}) 14 | set(processed_files "") 15 | 16 | math(EXPR file_index "0") 17 | foreach(file IN LISTS arg_FILES) 18 | get_filename_component(input_file_absolute ${file} ABSOLUTE) 19 | get_filename_component(input_file_ext ${file} LAST_EXT) 20 | 21 | # Mirror Qt6ShaderToolsMacros.cmake logic, but use a .qctempshaders 22 | # directory. OUTPUTS, if present, matters in particular for the temporary 23 | # filename, since just generating a filename based on the input (in FILES) 24 | # would lead to clashes if the same source file was used to generate 25 | # multiple variants (like with different DEFINES) in qc_add_shaders. 26 | 27 | set(output_file "${file}.qsb") 28 | if(arg_OUTPUTS) 29 | list(GET arg_OUTPUTS ${file_index} output_file) 30 | else() 31 | if(arg_BASE) 32 | get_filename_component(abs_base "${arg_BASE}" ABSOLUTE) 33 | get_filename_component(abs_output_file "${output_file}" ABSOLUTE) 34 | file(RELATIVE_PATH output_file "${abs_base}" "${abs_output_file}") 35 | endif() 36 | list(APPEND qsb_outputs ${output_file}) 37 | endif() 38 | 39 | # Now output_file ends in .qsb, but it must end with the original .vert 40 | # or .frag extension since that is required by qsb. 41 | set(output_file "${output_file}.qcpre${input_file_ext}") 42 | set(processed_file "${CMAKE_CURRENT_BINARY_DIR}/.qctempshaders/${output_file}") 43 | list(APPEND processed_files "${processed_file}") 44 | 45 | set(shadergen_args "") 46 | 47 | list(APPEND shadergen_args "-o") 48 | list(APPEND shadergen_args "${processed_file}") 49 | 50 | list(APPEND shadergen_args "${input_file_absolute}") 51 | 52 | _qt_internal_get_tool_wrapper_script_path(tool_wrapper) 53 | set(qcshadergen_executable "$") 54 | if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" 55 | AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.20") 56 | set(qcshadergen_executable "$") 57 | endif() 58 | add_custom_command( 59 | OUTPUT 60 | ${processed_file} 61 | COMMAND 62 | ${tool_wrapper} 63 | ${qcshadergen_executable} 64 | ${shadergen_args} 65 | DEPENDS 66 | ${qcshadergen_executable} 67 | "${file}" 68 | VERBATIM 69 | ) 70 | 71 | math(EXPR file_index "${file_index}+1") 72 | endforeach() 73 | 74 | add_custom_target(${target}_${resourcename}_qcpre DEPENDS "${processed_files}") 75 | add_dependencies(${target} ${target}_${resourcename}_qcpre) 76 | 77 | # OpenGL ES 3.0 or newer, OpenGL 3.2 or newer. 130 (OpenGL 3.0) is the 78 | # minimum (e.g. due to textureSize), it is here for old llvmpipe versions 79 | # that some CI might still use. 80 | set(opengl_glsl_versions "300es,150,130") 81 | 82 | if (arg__QT_INTERNAL) 83 | qt_internal_add_shaders(${target} ${resourcename} 84 | GLSL 85 | ${opengl_glsl_versions} 86 | PREFIX 87 | ${arg_PREFIX} 88 | FILES 89 | ${processed_files} 90 | ORIGINAL_FILES 91 | ${arg_FILES} 92 | OUTPUTS 93 | ${qsb_outputs} 94 | DEFINES 95 | ${arg_DEFINES} 96 | OUTPUT_TARGETS 97 | output_targets 98 | ) 99 | else() 100 | qt_add_shaders(${target} ${resourcename} 101 | GLSL 102 | ${opengl_glsl_versions} 103 | PREFIX 104 | ${arg_PREFIX} 105 | FILES 106 | ${processed_files} 107 | ORIGINAL_FILES 108 | ${arg_FILES} 109 | OUTPUTS 110 | ${qsb_outputs} 111 | DEFINES 112 | ${arg_DEFINES} 113 | OUTPUT_TARGETS 114 | output_targets 115 | ) 116 | endif() 117 | 118 | if(arg_OUTPUT_TARGETS) 119 | set(${arg_OUTPUT_TARGETS} "${output_targets}" PARENT_SCOPE) 120 | endif() 121 | endfunction() 122 | 123 | function(qc_add_shaders) 124 | _qc_internal_add_shaders_impl(${ARGV}) 125 | cmake_parse_arguments(PARSE_ARGV 1 arg "" "OUTPUT_TARGETS" "") 126 | if (arg_OUTPUT_TARGETS) 127 | set(${arg_OUTPUT_TARGETS} ${${arg_OUTPUT_TARGETS}} PARENT_SCOPE) 128 | endif() 129 | endfunction() 130 | 131 | # for use by Qt modules that need qt_internal_add_resource 132 | function(qc_internal_add_shaders) 133 | _qc_internal_add_shaders_impl(${ARGV} _QT_INTERNAL) 134 | cmake_parse_arguments(PARSE_ARGV 1 arg "" "OUTPUT_TARGETS" "") 135 | if (arg_OUTPUT_TARGETS) 136 | set(${arg_OUTPUT_TARGETS} ${${arg_OUTPUT_TARGETS}} PARENT_SCOPE) 137 | endif() 138 | endfunction() 139 | -------------------------------------------------------------------------------- /src/canvaspainter/engine/qcrhidistancefieldglyphcache_p.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 The Qt Company Ltd. 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only 3 | 4 | #ifndef QCRHIDISTANCEFIELDGLYPHCACHE_H 5 | #define QCRHIDISTANCEFIELDGLYPHCACHE_H 6 | 7 | // 8 | // W A R N I N G 9 | // ------------- 10 | // 11 | // This file is not part of the Qt API. It exists for the convenience 12 | // of other Qt classes. This header file may change from version to 13 | // version without notice, or even be removed. 14 | // 15 | // We mean it. 16 | // 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "qcareaallocator_p.h" 23 | #include 24 | 25 | QT_BEGIN_NAMESPACE 26 | 27 | class QCRhiDistanceFieldGlyphCache 28 | { 29 | public: 30 | struct TextureInfo 31 | { 32 | QRhiTexture *texture = nullptr; 33 | QSize size; 34 | QRect allocatedArea; 35 | QDistanceField image; 36 | int padding = -1; 37 | QVarLengthArray uploads; 38 | 39 | bool operator==(const TextureInfo &other) const { return texture == other.texture; } 40 | 41 | TextureInfo(const QRect &preallocRect = QRect()) 42 | : allocatedArea(preallocRect) 43 | {} 44 | }; 45 | 46 | struct TexCoord 47 | { 48 | qreal x = 0; 49 | qreal y = 0; 50 | qreal width = -1; 51 | qreal height = -1; 52 | qreal xMargin = 0; 53 | qreal yMargin = 0; 54 | 55 | bool isNull() const { return width <= 0 || height <= 0; } 56 | bool isValid() const { return width >= 0 && height >= 0; } 57 | }; 58 | 59 | struct Metrics 60 | { 61 | qreal width; 62 | qreal height; 63 | qreal baselineX; 64 | qreal baselineY; 65 | 66 | bool isNull() const { return width == 0 || height == 0; } 67 | }; 68 | 69 | struct TexturedPoint2D 70 | { 71 | float x, y; 72 | float tx, ty; 73 | void set(float nx, float ny, float ntx, float nty) 74 | { 75 | x = nx; 76 | y = ny; 77 | tx = ntx; 78 | ty = nty; 79 | } 80 | }; 81 | 82 | struct GlyphData 83 | { 84 | TextureInfo *texture = nullptr; 85 | TexCoord texCoord; 86 | QRectF boundingRect; 87 | QPainterPath path; 88 | quint32 ref = 0; 89 | }; 90 | 91 | struct GlyphPosition 92 | { 93 | glyph_t glyph; 94 | QPointF position; 95 | }; 96 | 97 | public: 98 | QCRhiDistanceFieldGlyphCache(QRhi *rhi); 99 | ~QCRhiDistanceFieldGlyphCache(); 100 | 101 | bool populate(const QList &glyphs); 102 | void update(); 103 | 104 | void setRawFont(const QRawFont &font); 105 | bool addGlyphs(QPointF position, const QGlyphRun &glyphs); 106 | void createTexture(TextureInfo *texInfo, int width, int height); 107 | void createTexture(TextureInfo *texInfo, int width, int height, const void *pixels); 108 | void resizeTexture(TextureInfo *texInfo, int width, int height); 109 | 110 | void requestGlyphs(const QSet &glyphs); 111 | void storeGlyphs(const QList &glyphs); 112 | void removeGlyph(glyph_t glyph); 113 | void setGlyphsPosition(const QList &glyphs); 114 | void referenceGlyphs(const QSet &glyphs); 115 | 116 | bool setGlyphs(QPointF position, const QGlyphRun &glyphs); 117 | void setGlyphTexture(const QList &glyphs, const TextureInfo &tex); 118 | 119 | void generateVertices( 120 | QVarLengthArray *verts, 121 | QVarLengthArray *indices, 122 | const QTransform &transform, 123 | QRectF *boundingRect); 124 | 125 | void commitResourceUpdate(QRhiResourceUpdateBatch *batch); 126 | QList &getTextures() { return m_textures; } 127 | 128 | GlyphData &glyphData(glyph_t glyph); 129 | 130 | private: 131 | static TextureInfo s_emptyTexture; 132 | 133 | QRhi *m_rhi; 134 | QCAreaAllocator *m_areaAllocator = nullptr; 135 | QRhiResourceUpdateBatch *m_batch; 136 | 137 | QPointF m_position; 138 | QGlyphRun m_glyphs; 139 | QRawFont m_referenceFont; 140 | int m_glyphCount; 141 | mutable int m_maxTextureSize = 1024; 142 | int m_maxTextureCount = 1; 143 | bool m_doubleGlyphResolution = false; 144 | 145 | QHash m_glyphsData; 146 | QSet m_populatingGlyphs; 147 | QSet m_unusedGlyphs; 148 | QHash m_glyphsTexture; 149 | QList m_textures; 150 | QDataBuffer m_pendingGlyphs; 151 | 152 | GlyphData &emptyData(glyph_t glyph); 153 | int maxTextureSize() const; 154 | void markGlyphsToRender(const QList &glyphs); 155 | bool useTextureResizeWorkaround() const; 156 | void updateRhiTexture(QRhiTexture *oldTex, QRhiTexture *newTex, QSize newTexSize); 157 | Metrics glyphMetrics(glyph_t glyph, qreal pixelSize); 158 | 159 | qreal fontScale(qreal pixelSize) const; 160 | 161 | qreal distanceFieldRadius() const 162 | { 163 | return QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) 164 | / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution)); 165 | } 166 | 167 | TextureInfo *textureInfo(int index) 168 | { 169 | // Make sure there are enough m_textures for index. 170 | for (int i = m_textures.size(); i <= index; ++i) 171 | m_textures.append(TextureInfo()); 172 | 173 | return &m_textures[index]; 174 | } 175 | 176 | inline TexCoord glyphTexCoord(glyph_t glyph) { return glyphData(glyph).texCoord; }; 177 | }; 178 | 179 | QT_END_NAMESPACE 180 | 181 | #endif // QCRHIDISTANCEFIELDGLYPHCACHE_H 182 | --------------------------------------------------------------------------------