diff --git a/src/gui/painting/qpainterstateguard.cpp b/src/gui/painting/qpainterstateguard.cpp index b62400fa3b6..9f88a6e75d6 100644 --- a/src/gui/painting/qpainterstateguard.cpp +++ b/src/gui/painting/qpainterstateguard.cpp @@ -37,6 +37,25 @@ QT_BEGIN_NAMESPACE QPainter's state. */ +/*! + \fn QPainterStateGuard::QPainterStateGuard(QPainterStateGuard &&other) + + Move-constructs a painter state guard from \a other. +*/ + +/*! + \fn QPainterStateGuard &QPainterStateGuard::operator=(QPainterStateGuard &&other) + + Move-assigns \a other to this painter state guard. +*/ + +/*! + \fn void QPainterStateGuard::swap(QPainterStateGuard &other) + + Swaps the \a other with this painter state guard. This operation is very + fast and never fails. +*/ + /*! \fn QPainterStateGuard::~QPainterStateGuard() Destroys the QPainterStateGuard instance and calls restore() as often as save() diff --git a/src/gui/painting/qpainterstateguard.h b/src/gui/painting/qpainterstateguard.h index 01e1a0a1163..b6b5c039775 100644 --- a/src/gui/painting/qpainterstateguard.h +++ b/src/gui/painting/qpainterstateguard.h @@ -11,13 +11,24 @@ QT_BEGIN_NAMESPACE class QPainterStateGuard { - Q_DISABLE_COPY_MOVE(QPainterStateGuard) + Q_DISABLE_COPY(QPainterStateGuard) public: enum class InitialState : quint8 { Save, NoSave, }; + QPainterStateGuard(QPainterStateGuard &&other) noexcept + : m_painter(std::exchange(other.m_painter, nullptr)) + , m_level(std::exchange(other.m_level, 0)) + {} + QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QPainterStateGuard) + void swap(QPainterStateGuard &other) noexcept + { + qt_ptr_swap(m_painter, other.m_painter); + std::swap(m_level, other.m_level); + } + Q_NODISCARD_CTOR explicit QPainterStateGuard(QPainter *painter, InitialState state = InitialState::Save) : m_painter(painter) diff --git a/tests/auto/gui/painting/CMakeLists.txt b/tests/auto/gui/painting/CMakeLists.txt index b49a80b1803..ca985f9af1a 100644 --- a/tests/auto/gui/painting/CMakeLists.txt +++ b/tests/auto/gui/painting/CMakeLists.txt @@ -10,6 +10,7 @@ add_subdirectory(qpagelayout) add_subdirectory(qpageranges) add_subdirectory(qpagesize) add_subdirectory(qpainter) +add_subdirectory(qpainterstateguard) if (QT_FEATURE_pdf) add_subdirectory(qpdfwriter) endif() diff --git a/tests/auto/gui/painting/qpainterstateguard/CMakeLists.txt b/tests/auto/gui/painting/qpainterstateguard/CMakeLists.txt new file mode 100644 index 00000000000..7331b86b37e --- /dev/null +++ b/tests/auto/gui/painting/qpainterstateguard/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## tst_qpainterstateguard Test: +##################################################################### + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qpainterstateguard LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qpainterstateguard + SOURCES + tst_qpainterstateguard.cpp + LIBRARIES + Qt::Gui +) diff --git a/tests/auto/gui/painting/qpainterstateguard/tst_qpainterstateguard.cpp b/tests/auto/gui/painting/qpainterstateguard/tst_qpainterstateguard.cpp new file mode 100644 index 00000000000..54484c03358 --- /dev/null +++ b/tests/auto/gui/painting/qpainterstateguard/tst_qpainterstateguard.cpp @@ -0,0 +1,69 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#define Q_ASSERT(cond) ((cond) ? static_cast(0) : qCritical(#cond)) + +#include + +#include +#include +#include + +class tst_QPainterStateGuard : public QObject +{ + Q_OBJECT + +private slots: + void basics_data(); + void basics(); +}; + +void tst_QPainterStateGuard::basics_data() +{ + QTest::addColumn("initialState"); + QTest::addColumn("expectWarning"); + + QTest::addRow("Save") << QPainterStateGuard::InitialState::Save << false; + QTest::addRow("NoSave") << QPainterStateGuard::InitialState::NoSave << true; +} + +void tst_QPainterStateGuard::basics() +{ + QFETCH(const QPainterStateGuard::InitialState, initialState); + QFETCH(const bool, expectWarning); + + if (expectWarning) { + QTest::ignoreMessage(QtCriticalMsg, "m_level > 0"); + QTest::ignoreMessage(QtWarningMsg, "QPainter::restore: Unbalanced save/restore"); + } else { + QTest::failOnWarning("QPainter::restore: Unbalanced save/restore"); + } + QPixmap pixmap(100, 100); + QPainter painter(&pixmap); + const QPen defaultPen = painter.pen(); + + { + auto makeGuard = [initialState](QPainter *p) -> QPainterStateGuard { + return QPainterStateGuard(p, initialState); + }; + QPainterStateGuard guard = makeGuard(&painter); + + painter.setPen(Qt::red); + QCOMPARE(painter.pen().color(), Qt::red); + + QPainterStateGuard guard2 = std::move(guard); + + QCOMPARE(painter.pen().color(), Qt::red); + + guard2.restore(); + } + + if (expectWarning) + QCOMPARE_NE(painter.pen(), defaultPen); + else + QCOMPARE(painter.pen(), defaultPen); +} + +QTEST_MAIN(tst_QPainterStateGuard) + +#include "tst_qpainterstateguard.moc"