summaryrefslogtreecommitdiffstats
path: root/src/gui/painting/qpainterpath.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/painting/qpainterpath.cpp')
-rw-r--r--src/gui/painting/qpainterpath.cpp164
1 files changed, 51 insertions, 113 deletions
diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp
index de0b3f3998..8d23d167b0 100644
--- a/src/gui/painting/qpainterpath.cpp
+++ b/src/gui/painting/qpainterpath.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpainterpath.h"
#include "qpainterpath_p.h"
@@ -88,17 +52,6 @@ static bool hasValidCoords(QRectF r)
return isValidCoord(r.x()) && isValidCoord(r.y()) && isValidCoord(r.width()) && isValidCoord(r.height());
}
-struct QPainterPathPrivateDeleter
-{
- static inline void cleanup(QPainterPathPrivate *d)
- {
- // note - we must downcast to QPainterPathData since QPainterPathPrivate
- // has a non-virtual destructor!
- if (d && !d->ref.deref())
- delete static_cast<QPainterPathData *>(d);
- }
-};
-
// This value is used to determine the length of control point vectors
// when approximating arc segments as curves. The factor is multiplied
// with the radius of the circle.
@@ -556,12 +509,7 @@ QPainterPath::QPainterPath() noexcept
\sa operator=()
*/
-QPainterPath::QPainterPath(const QPainterPath &other)
- : d_ptr(other.d_ptr.data())
-{
- if (d_ptr)
- d_ptr->ref.ref();
-}
+QPainterPath::QPainterPath(const QPainterPath &other) = default;
/*!
Creates a QPainterPath object with the given \a startPoint as its
@@ -569,34 +517,22 @@ QPainterPath::QPainterPath(const QPainterPath &other)
*/
QPainterPath::QPainterPath(const QPointF &startPoint)
- : d_ptr(new QPainterPathData)
+ : d_ptr(new QPainterPathPrivate(startPoint))
{
- Element e = { startPoint.x(), startPoint.y(), MoveToElement };
- d_func()->elements << e;
}
void QPainterPath::detach()
{
- if (d_ptr->ref.loadRelaxed() != 1)
- detach_helper();
+ d_ptr.detach();
setDirty(true);
}
/*!
\internal
*/
-void QPainterPath::detach_helper()
-{
- QPainterPathPrivate *data = new QPainterPathData(*d_func());
- d_ptr.reset(data);
-}
-
-/*!
- \internal
-*/
void QPainterPath::ensureData_helper()
{
- QPainterPathPrivate *data = new QPainterPathData;
+ QPainterPathPrivate *data = new QPainterPathPrivate;
data->elements.reserve(16);
QPainterPath::Element e = { 0, 0, QPainterPath::MoveToElement };
data->elements << e;
@@ -613,12 +549,8 @@ void QPainterPath::ensureData_helper()
*/
QPainterPath &QPainterPath::operator=(const QPainterPath &other)
{
- if (other.d_func() != d_func()) {
- QPainterPathPrivate *data = other.d_func();
- if (data)
- data->ref.ref();
- d_ptr.reset(data);
- }
+ QPainterPath copy(other);
+ swap(copy);
return *this;
}
@@ -668,7 +600,7 @@ void QPainterPath::clear()
Attempts to allocate memory for at least \a size elements.
- \sa clear(), capacity(), QVector::reserve()
+ \sa clear(), capacity(), QList::reserve()
\since 5.13
*/
void QPainterPath::reserve(int size)
@@ -753,7 +685,7 @@ void QPainterPath::moveTo(const QPointF &p)
ensureData();
detach();
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
Q_ASSERT(!d->elements.isEmpty());
d->require_moveTo = false;
@@ -803,7 +735,7 @@ void QPainterPath::lineTo(const QPointF &p)
ensureData();
detach();
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
Q_ASSERT(!d->elements.isEmpty());
d->maybeMoveTo();
if (p == QPointF(d->elements.constLast()))
@@ -862,7 +794,7 @@ void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF &
ensureData();
detach();
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
Q_ASSERT(!d->elements.isEmpty());
@@ -1201,6 +1133,9 @@ void QPainterPath::addEllipse(const QRectF &boundingRect)
that the left end of the text's baseline lies at the specified \a
point.
+ Some fonts may yield overlapping subpaths and will require the
+ \c Qt::WindingFill fill rule for correct rendering.
+
\table 100%
\row
\li \inlineimage qpainterpath-addtext.png
@@ -1209,7 +1144,7 @@ void QPainterPath::addEllipse(const QRectF &boundingRect)
\endtable
\sa QPainter::drawText(), {QPainterPath#Composing a
- QPainterPath}{Composing a QPainterPath}
+ QPainterPath}{Composing a QPainterPath}, setFillRule()
*/
void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &text)
{
@@ -1221,6 +1156,11 @@ void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &
QTextLayout layout(text, f);
layout.setCacheEnabled(true);
+
+ QTextOption opt = layout.textOption();
+ opt.setUseDesignMetrics(true);
+ layout.setTextOption(opt);
+
QTextEngine *eng = layout.engine();
layout.beginLayout();
QTextLine line = layout.createLine();
@@ -1247,7 +1187,7 @@ void QPainterPath::addText(const QPointF &point, const QFont &f, const QString &
if (si.analysis.flags < QScriptAnalysis::TabOrObject) {
QGlyphLayout glyphs = eng->shapedGlyphs(&si);
- QFontEngine *fe = f.d->engineForScript(si.analysis.script);
+ QFontEngine *fe = eng->fontEngine(si);
Q_ASSERT(fe);
fe->addOutlineToPath(x, y, glyphs, this,
si.analysis.bidiLevel % 2
@@ -1288,7 +1228,7 @@ void QPainterPath::addPath(const QPainterPath &other)
ensureData();
detach();
- QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
+ QPainterPathPrivate *d = d_func();
// Remove last moveto so we don't get multiple moveto's
if (d->elements.constLast().type == MoveToElement)
d->elements.remove(d->elements.size()-1);
@@ -1319,7 +1259,7 @@ void QPainterPath::connectPath(const QPainterPath &other)
ensureData();
detach();
- QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
+ QPainterPathPrivate *d = d_func();
// Remove last moveto so we don't get multiple moveto's
if (d->elements.constLast().type == MoveToElement)
d->elements.remove(d->elements.size()-1);
@@ -1366,7 +1306,7 @@ void QPainterPath::addRegion(const QRegion &region)
*/
Qt::FillRule QPainterPath::fillRule() const
{
- return isEmpty() ? Qt::OddEvenFill : d_func()->fillRule;
+ return !d_func() ? Qt::OddEvenFill : d_func()->fillRule;
}
/*!
@@ -1509,7 +1449,7 @@ QRectF QPainterPath::boundingRect() const
{
if (!d_ptr)
return QRectF();
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
if (d->dirtyBounds)
computeBoundingRect();
@@ -1530,7 +1470,7 @@ QRectF QPainterPath::controlPointRect() const
{
if (!d_ptr)
return QRectF();
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
if (d->dirtyControlBounds)
computeControlPointRect();
@@ -1549,7 +1489,7 @@ QRectF QPainterPath::controlPointRect() const
bool QPainterPath::isEmpty() const
{
- return !d_ptr || (d_ptr->elements.size() == 1 && d_ptr->elements.first().type == MoveToElement);
+ return !d_ptr || (d_ptr->elements.size() == 1 && d_ptr->elements.constFirst().type == MoveToElement);
}
/*!
@@ -1692,7 +1632,7 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
if (count == 0)
return polys;
- QVector<QRectF> bounds;
+ QList<QRectF> bounds;
bounds.reserve(count);
for (int i=0; i<count; ++i)
bounds += subpaths.at(i).boundingRect();
@@ -1703,7 +1643,7 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
qDebug() << " bounds" << i << bounds.at(i);
#endif
- QVector< QVector<int> > isects;
+ QList< QList<int> > isects;
isects.resize(count);
// find all intersections
@@ -1731,12 +1671,12 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
// flatten the sets of intersections
for (int i=0; i<count; ++i) {
- const QVector<int> &current_isects = isects.at(i);
+ const QList<int> &current_isects = isects.at(i);
for (int j=0; j<current_isects.size(); ++j) {
int isect_j = current_isects.at(j);
if (isect_j == i)
continue;
- const QVector<int> &isects_j = isects.at(isect_j);
+ const QList<int> &isects_j = isects.at(isect_j);
for (int k = 0, size = isects_j.size(); k < size; ++k) {
int isect_k = isects_j.at(k);
if (isect_k != i && !isects.at(i).contains(isect_k)) {
@@ -1760,7 +1700,7 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const
// Join the intersected subpaths as rewinded polygons
for (int i=0; i<count; ++i) {
- const QVector<int> &subpath_list = isects.at(i);
+ const QList<int> &subpath_list = isects.at(i);
if (!subpath_list.isEmpty()) {
QPolygonF buildUp;
for (int j=0; j<subpath_list.size(); ++j) {
@@ -1857,7 +1797,7 @@ bool QPainterPath::contains(const QPointF &pt) const
if (isEmpty() || !controlPointRect().contains(pt))
return false;
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
int winding_number = 0;
@@ -2151,7 +2091,7 @@ bool QPainterPath::intersects(const QRectF &rect) const
Q_D(QPainterPath);
- // Check if the rectangle surounds any subpath...
+ // Check if the rectangle surrounds any subpath...
for (int i=0; i<d->elements.size(); ++i) {
const Element &e = d->elements.at(i);
if (e.type == QPainterPath::MoveToElement && rect.contains(e))
@@ -2316,8 +2256,8 @@ static inline bool epsilonCompare(const QPointF &a, const QPointF &b, const QSiz
bool QPainterPath::operator==(const QPainterPath &path) const
{
- QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func());
- QPainterPathData *other_d = path.d_func();
+ QPainterPathPrivate *d = d_func();
+ QPainterPathPrivate *other_d = path.d_func();
if (other_d == d) {
return true;
} else if (!d || !other_d) {
@@ -2502,14 +2442,14 @@ QDataStream &operator>>(QDataStream &s, QPainterPath &p)
int size;
s >> size;
- if (size == 0)
+ if (size == 0) {
+ p = {};
return s;
+ }
p.ensureData(); // in case if p.d_func() == 0
- if (p.d_func()->elements.size() == 1) {
- Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement);
- p.d_func()->elements.clear();
- }
+ p.detach();
+ p.d_func()->elements.clear();
for (int i=0; i<size; ++i) {
int type;
double x, y;
@@ -2532,9 +2472,7 @@ QDataStream &operator>>(QDataStream &s, QPainterPath &p)
s >> fillRule;
Q_ASSERT(fillRule == Qt::OddEvenFill || fillRule == Qt::WindingFill);
p.d_func()->fillRule = Qt::FillRule(fillRule);
- p.d_func()->dirtyBounds = true;
- p.d_func()->dirtyControlBounds = true;
- if (errorDetected)
+ if (errorDetected || p.d_func()->elements.isEmpty())
p = QPainterPath(); // Better than to return path with possibly corrupt datastructure, which would likely cause crash
return s;
}
@@ -2592,7 +2530,7 @@ void qt_path_stroke_cubic_to(qfixed c1x, qfixed c1y,
\endlist
The setDashPattern() function accepts both a Qt::PenStyle object
- and a vector representation of the pattern as argument.
+ and a list representation of the pattern as argument.
In addition you can specify a curve's threshold, controlling the
granularity with which a curve is drawn, using the
@@ -2811,16 +2749,16 @@ void QPainterPathStroker::setDashPattern(Qt::PenStyle style)
dashPattern. This function makes it possible to specify custom
dash patterns.
- Each element in the vector contains the lengths of the dashes and spaces
+ Each element in the list contains the lengths of the dashes and spaces
in the stroke, beginning with the first dash in the first element, the
first space in the second element, and alternating between dashes and
spaces for each following pair of elements.
- The vector can contain an odd number of elements, in which case the last
+ The list can contain an odd number of elements, in which case the last
element will be extended by the length of the first element when the
pattern repeats.
*/
-void QPainterPathStroker::setDashPattern(const QVector<qreal> &dashPattern)
+void QPainterPathStroker::setDashPattern(const QList<qreal> &dashPattern)
{
d_func()->dashPattern.clear();
for (int i=0; i<dashPattern.size(); ++i)
@@ -2830,7 +2768,7 @@ void QPainterPathStroker::setDashPattern(const QVector<qreal> &dashPattern)
/*!
Returns the dash pattern for the generated outlines.
*/
-QVector<qreal> QPainterPathStroker::dashPattern() const
+QList<qreal> QPainterPathStroker::dashPattern() const
{
return d_func()->dashPattern;
}
@@ -3297,7 +3235,7 @@ QPainterPath QPainterPath::subtracted(const QPainterPath &p) const
*/
QPainterPath QPainterPath::simplified() const
{
- if(isEmpty())
+ if (isEmpty())
return *this;
QPathClipper clipper(*this, QPainterPath());
return clipper.clip(QPathClipper::Simplify);
@@ -3356,7 +3294,7 @@ void QPainterPath::setDirty(bool dirty)
void QPainterPath::computeBoundingRect() const
{
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
d->dirtyBounds = false;
if (!d_ptr) {
d->bounds = QRect();
@@ -3403,7 +3341,7 @@ void QPainterPath::computeBoundingRect() const
void QPainterPath::computeControlPointRect() const
{
- QPainterPathData *d = d_func();
+ QPainterPathPrivate *d = d_func();
d->dirtyControlBounds = false;
if (!d_ptr) {
d->controlBounds = QRect();