From ab53500cfa11b988e7e4234583fa6eb5027b4c08 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 27 Nov 2024 17:58:32 +0100 Subject: [PATCH] QPen/QBrush: add optimized assignment operators for color and style Assigning a color or style to an existing pen or brush (which we do frequently in QPainter and elsewhere in Qt) used to implicitly create a new QPen/QBrush instance and then move-assign that. This involves an allocation of the new private data, and often also a deallocation of the old pen or brush private if that wasn't shared (which it often isn't, as we usually set a temporary object with no further copies). By implementing specific assignment operators from color and style we can shortcut this and avoid the allocations. With this set of changes, the setPen/setBrush benchmarks now compare to Qt 6.8 as follows: setPen 6.8: 0.00016 msecs per iteration (total: 89, iterations: 524288) 6.9: 0.000032 msecs per iteration (total: 69, iterations: 2097152) setBrush 6.8: 0.000078 msecs per iteration (total: 82, iterations: 1048576) 6.9: 0.000017 msecs per iteration (total: 73, iterations: 4194304) i.e. improve by a factor of >4.5. Change-Id: Ia9c0229b0f540ecf9afba2a598973c6931712f64 Reviewed-by: Christian Ehrlicher --- src/gui/painting/qbrush.cpp | 42 +++++++++++++++++++++++++++++++------ src/gui/painting/qbrush.h | 4 ++++ src/gui/painting/qpen.cpp | 41 ++++++++++++++++++++++++++++++++++++ src/gui/painting/qpen.h | 3 +++ 4 files changed, 84 insertions(+), 6 deletions(-) diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index 5a6fbd8232a..6a279ef8cac 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -598,19 +598,49 @@ void QBrush::detach(Qt::BrushStyle newStyle) /*! - \fn QBrush &QBrush::operator=(const QBrush &brush) - Assigns the given \a brush to \e this brush and returns a reference to \e this brush. */ -QBrush &QBrush::operator=(const QBrush &b) +QBrush &QBrush::operator=(const QBrush &brush) { - if (d == b.d) + if (d == brush.d) return *this; - b.d->ref.ref(); - d.reset(b.d.get()); + brush.d->ref.ref(); + d.reset(brush.d.get()); + return *this; +} + +/*! + \fn QBrush &QBrush::operator=(QColor color) + \fn QBrush &QBrush::operator=(Qt::GlobalColor color) + \overload + \since 6.9 + + Makes this brush a solid pattern brush of the given \a color, + and returns a reference to \e this brush. +*/ +QBrush &QBrush::operator=(QColor color) +{ + detach(Qt::SolidPattern); + d->color = color; + d->transform = {}; + return *this; +} + +/*! + \overload + \since 6.9 + + Makes this brush a black brush of the given \a style, + and returns a reference to \e this brush. +*/ +QBrush &QBrush::operator=(Qt::BrushStyle style) +{ + detach(style); + d->color = Qt::black; + d->transform = {}; return *this; } diff --git a/src/gui/painting/qbrush.h b/src/gui/painting/qbrush.h index b5958f853c3..62c752345e4 100644 --- a/src/gui/painting/qbrush.h +++ b/src/gui/painting/qbrush.h @@ -49,6 +49,10 @@ public: inline void swap(QBrush &other) noexcept { d.swap(other.d); } + QBrush &operator=(Qt::BrushStyle style); + QBrush &operator=(QColor color); + QBrush &operator=(Qt::GlobalColor color) { return operator=(QColor(color)); } + operator QVariant() const; inline Qt::BrushStyle style() const; diff --git a/src/gui/painting/qpen.cpp b/src/gui/painting/qpen.cpp index 89dbdc0d3df..fdab16ff0e4 100644 --- a/src/gui/painting/qpen.cpp +++ b/src/gui/painting/qpen.cpp @@ -344,6 +344,47 @@ QPen &QPen::operator=(const QPen &p) noexcept \memberswap{pen} */ +/*! + \overload + \since 6.9 + + Makes this pen a solid pen with the given color, and default + cap and join styles, and returns a reference to \e this pen. +*/ +QPen &QPen::operator=(QColor color) +{ + detach(); + d->brush = color; + d->width = 1; + d->style = Qt::SolidLine; + d->capStyle = qpen_default_cap; + d->joinStyle = qpen_default_join; + + return *this; +} + +/*! + \overload + \since 6.9 + + Makes this pen a solid, black pen with default cap and join styles, + and returns a reference to \e this pen. +*/ +QPen &QPen::operator=(Qt::PenStyle style) +{ + detach(); + if (style == Qt::NoPen) { + d = nullPenInstance()->pen; + } else { + d->brush = Qt::black; + d->width = 1; + d->style = style; + d->capStyle = qpen_default_cap; + d->joinStyle = qpen_default_join; + } + return *this; +} + /*! Returns the pen as a QVariant. */ diff --git a/src/gui/painting/qpen.h b/src/gui/painting/qpen.h index abd5d914628..897ebfb8428 100644 --- a/src/gui/painting/qpen.h +++ b/src/gui/painting/qpen.h @@ -41,6 +41,9 @@ public: QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QPen) void swap(QPen &other) noexcept { d.swap(other.d); } + QPen &operator=(QColor color); + QPen &operator=(Qt::PenStyle style); + Qt::PenStyle style() const; void setStyle(Qt::PenStyle);