summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEirik Aavitsland <eirik.aavitsland@qt.io>2017-08-04 16:22:23 +0200
committerEirik Aavitsland <eirik.aavitsland@qt.io>2018-06-22 10:42:33 +0000
commitf5fe9fc5a4136a696f07c4bd3567d85348ec42d9 (patch)
treecbfd3a39c9eeaa5ae11a8469bcd5431bedc06f77
parent99d4f0026f90681974f6fd1d23941e5b69024796 (diff)
Add ObjectMode coordinate mode to QGradient
The ObjectBoundingMode coordinate mode of QGradient allows specifying the gradient coordinates relative to the object being painted. But if the gradient brush also has a transformation, that transformation is applied in the logical, not object, coordinate space. That behavior is counterintuitive. However, changing it now would break existing code. Instead, we introduce a new coordinate mode enum with the expected behavior, and document the old one as deprecated. This prepares to fix the bugs below in qtsvg, by making it possible to specify the same behavior in Qt as SVG has. [ChangeLog][QtGui][QGradient] Add ObjectMode coordinate mode [ChangeLog][Important Behavior Changes] QDataStream version bumped up to 18 to account for changes in the serialization of QGradient. Task-number: QTBUG-59978 Task-number: QTBUG-67995 Change-Id: I8820a2555359812f3e1a46e37d6ac2cc29a2091d Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--src/corelib/serialization/qdatastream.h2
-rw-r--r--src/gui/painting/qbrush.cpp18
-rw-r--r--src/gui/painting/qbrush.h3
-rw-r--r--src/gui/painting/qemulationpaintengine.cpp19
-rw-r--r--src/gui/painting/qpainter.cpp18
-rw-r--r--src/widgets/kernel/qwidget.cpp3
-rw-r--r--tests/auto/other/lancelot/paintcommands.cpp5
-rw-r--r--tests/auto/other/lancelot/scripts/gradientxform_object.qps15
8 files changed, 57 insertions, 26 deletions
diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h
index 85a2177652..4ae4a3d76c 100644
--- a/src/corelib/serialization/qdatastream.h
+++ b/src/corelib/serialization/qdatastream.h
@@ -98,7 +98,7 @@ public:
Qt_5_9 = Qt_5_8,
Qt_5_10 = Qt_5_9,
Qt_5_11 = Qt_5_10,
- Qt_5_12 = Qt_5_11,
+ Qt_5_12 = 18,
#if QT_VERSION >= 0x050d00
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
#endif
diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp
index c667454cd2..f8185f5db8 100644
--- a/src/gui/painting/qbrush.cpp
+++ b/src/gui/painting/qbrush.cpp
@@ -1077,7 +1077,10 @@ QDataStream &operator<<(QDataStream &s, const QBrush &b)
s << type_as_int;
if (s.version() >= QDataStream::Qt_4_3) {
s << int(gradient->spread());
- s << int(gradient->coordinateMode());
+ QGradient::CoordinateMode co_mode = gradient->coordinateMode();
+ if (s.version() < QDataStream::Qt_5_12 && co_mode == QGradient::ObjectMode)
+ co_mode = QGradient::ObjectBoundingMode;
+ s << int(co_mode);
}
if (s.version() >= QDataStream::Qt_4_5)
@@ -1562,14 +1565,19 @@ QGradientStops QGradient::stops() const
\value LogicalMode This is the default mode. The gradient coordinates
are specified logical space just like the object coordinates.
+ \value ObjectMode In this mode the gradient coordinates are
+ relative to the bounding rectangle of the object being drawn, with
+ (0,0) in the top left corner, and (1,1) in the bottom right corner
+ of the object's bounding rectangle. This value was added in Qt
+ 5.12.
\value StretchToDeviceMode In this mode the gradient coordinates
are relative to the bounding rectangle of the paint device,
with (0,0) in the top left corner, and (1,1) in the bottom right
corner of the paint device.
- \value ObjectBoundingMode In this mode the gradient coordinates are
- relative to the bounding rectangle of the object being drawn, with
- (0,0) in the top left corner, and (1,1) in the bottom right corner
- of the object's bounding rectangle.
+ \value ObjectBoundingMode This mode is the same as ObjectMode, except that
+ the {QBrush::transform()} {brush transform}, if any, is applied relative to
+ the logical space instead of the object space. This enum value is
+ deprecated and should not be used in new code.
*/
/*!
diff --git a/src/gui/painting/qbrush.h b/src/gui/painting/qbrush.h
index 9023d2f43d..b43a732c86 100644
--- a/src/gui/painting/qbrush.h
+++ b/src/gui/painting/qbrush.h
@@ -194,7 +194,8 @@ public:
enum CoordinateMode {
LogicalMode,
StretchToDeviceMode,
- ObjectBoundingMode
+ ObjectBoundingMode,
+ ObjectMode
};
Q_ENUM(CoordinateMode)
diff --git a/src/gui/painting/qemulationpaintengine.cpp b/src/gui/painting/qemulationpaintengine.cpp
index 49ecd3b318..638834ef3b 100644
--- a/src/gui/painting/qemulationpaintengine.cpp
+++ b/src/gui/painting/qemulationpaintengine.cpp
@@ -74,10 +74,11 @@ QPainterState *QEmulationPaintEngine::createState(QPainterState *orig) const
static inline void combineXForm(QBrush *brush, const QRectF &r)
{
- QTransform t = brush->transform();
- t.translate(r.x(), r.y());
- t.scale(r.width(), r.height());
- brush->setTransform(t);
+ QTransform t(r.width(), 0, 0, r.height(), r.x(), r.y());
+ if (brush->gradient()->coordinateMode() == QGradient::ObjectMode)
+ brush->setTransform(brush->transform() * t);
+ else
+ brush->setTransform(t * brush->transform());
}
void QEmulationPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
@@ -96,7 +97,7 @@ void QEmulationPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
if (coMode > QGradient::LogicalMode) {
QBrush copy = brush;
const QPaintDevice *d = real_engine->painter()->device();
- QRectF r = (coMode == QGradient::ObjectBoundingMode) ? path.controlPointRect() : QRectF(0, 0, d->width(), d->height());
+ QRectF r = (coMode == QGradient::StretchToDeviceMode) ? QRectF(0, 0, d->width(), d->height()) : path.controlPointRect();
combineXForm(&copy, r);
real_engine->fill(path, copy);
return;
@@ -132,7 +133,7 @@ void QEmulationPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
QGradient::CoordinateMode coMode = brush.gradient()->coordinateMode();
if (coMode > QGradient::LogicalMode) {
const QPaintDevice *d = real_engine->painter()->device();
- QRectF r = (coMode == QGradient::ObjectBoundingMode) ? path.controlPointRect() : QRectF(0, 0, d->width(), d->height());
+ QRectF r = (coMode == QGradient::StretchToDeviceMode) ? QRectF(0, 0, d->width(), d->height()) : path.controlPointRect();
combineXForm(&brush, r);
copy.setBrush(brush);
real_engine->stroke(path, copy);
@@ -174,9 +175,9 @@ void QEmulationPaintEngine::drawTextItem(const QPointF &p, const QTextItem &text
QBrush copy = s->pen.brush();
const QPaintDevice *d = real_engine->painter()->device();
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
- QRectF r = (g.coordinateMode() == QGradient::ObjectBoundingMode) ?
- QRectF(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal()) :
- QRectF(0, 0, d->width(), d->height());
+ QRectF r = (g.coordinateMode() == QGradient::StretchToDeviceMode) ?
+ QRectF(0, 0, d->width(), d->height()) :
+ QRectF(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal());
combineXForm(&copy, r);
g.setCoordinateMode(QGradient::LogicalMode);
QBrush brush(g);
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 4a18df899e..41e81c5fbe 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -530,7 +530,10 @@ static inline QBrush stretchGradientToUserSpace(const QBrush &brush, const QRect
g.setCoordinateMode(QGradient::LogicalMode);
QBrush b(g);
- b.setTransform(gradientToUser * b.transform());
+ if (brush.gradient()->coordinateMode() == QGradient::ObjectMode)
+ b.setTransform(b.transform() * gradientToUser);
+ else
+ b.setTransform(gradientToUser * b.transform());
return b;
}
@@ -569,7 +572,7 @@ void QPainterPrivate::drawStretchedGradient(const QPainterPath &path, DrawOperat
} else {
needsFill = true;
- if (brushMode == QGradient::ObjectBoundingMode) {
+ if (brushMode == QGradient::ObjectBoundingMode || brushMode == QGradient::ObjectMode) {
Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
boundingRect = path.boundingRect();
q->setBrush(stretchGradientToUserSpace(brush, boundingRect));
@@ -613,11 +616,11 @@ void QPainterPrivate::drawStretchedGradient(const QPainterPath &path, DrawOperat
changedBrush = true;
}
- if (penMode == QGradient::ObjectBoundingMode) {
+ if (penMode == QGradient::ObjectBoundingMode || penMode == QGradient::ObjectMode) {
Q_ASSERT(engine->hasFeature(QPaintEngine::PatternTransform));
// avoid computing the bounding rect twice
- if (!needsFill || brushMode != QGradient::ObjectBoundingMode)
+ if (!needsFill || (brushMode != QGradient::ObjectBoundingMode && brushMode != QGradient::ObjectMode))
boundingRect = path.boundingRect();
QPen p = pen;
@@ -849,8 +852,8 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
gradientStretch |= (brushMode == QGradient::StretchToDeviceMode);
gradientStretch |= (penMode == QGradient::StretchToDeviceMode);
- objectBoundingMode |= (brushMode == QGradient::ObjectBoundingMode);
- objectBoundingMode |= (penMode == QGradient::ObjectBoundingMode);
+ objectBoundingMode |= (brushMode == QGradient::ObjectBoundingMode || brushMode == QGradient::ObjectMode);
+ objectBoundingMode |= (penMode == QGradient::ObjectBoundingMode || penMode == QGradient::ObjectMode);
}
if (gradientStretch)
s->emulationSpecifier |= QGradient_StretchToDevice;
@@ -6857,7 +6860,8 @@ static inline bool needsResolving(const QBrush &brush)
Qt::BrushStyle s = brush.style();
return ((s == Qt::LinearGradientPattern || s == Qt::RadialGradientPattern ||
s == Qt::ConicalGradientPattern) &&
- brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode);
+ (brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode ||
+ brush.gradient()->coordinateMode() == QGradient::ObjectMode));
}
/*!
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index 95d3da1ed4..61b255e362 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -2403,7 +2403,8 @@ static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QBrus
#endif
} else if (brush.gradient()
- && brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode) {
+ && (brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode
+ || brush.gradient()->coordinateMode() == QGradient::ObjectMode)) {
painter->save();
painter->setClipRegion(rgn);
painter->fillRect(0, 0, painter->device()->width(), painter->device()->height(), brush);
diff --git a/tests/auto/other/lancelot/paintcommands.cpp b/tests/auto/other/lancelot/paintcommands.cpp
index 45429624f5..377b98fa41 100644
--- a/tests/auto/other/lancelot/paintcommands.cpp
+++ b/tests/auto/other/lancelot/paintcommands.cpp
@@ -106,7 +106,8 @@ const char *PaintCommands::spreadMethodTable[] = {
const char *PaintCommands::coordinateMethodTable[] = {
"LogicalMode",
"StretchToDeviceMode",
- "ObjectBoundingMode"
+ "ObjectBoundingMode",
+ "ObjectMode"
};
const char *PaintCommands::sizeModeTable[] = {
@@ -2394,7 +2395,7 @@ void PaintCommands::command_gradient_setSpread(QRegularExpressionMatch re)
void PaintCommands::command_gradient_setCoordinateMode(QRegularExpressionMatch re)
{
- int coord = translateEnum(coordinateMethodTable, re.captured(1), 3);
+ int coord = translateEnum(coordinateMethodTable, re.captured(1), 4);
if (m_verboseMode)
printf(" -(lance) gradient_setCoordinateMode %d=[%s]\n", coord,
diff --git a/tests/auto/other/lancelot/scripts/gradientxform_object.qps b/tests/auto/other/lancelot/scripts/gradientxform_object.qps
index d785a008c0..dcc718072f 100644
--- a/tests/auto/other/lancelot/scripts/gradientxform_object.qps
+++ b/tests/auto/other/lancelot/scripts/gradientxform_object.qps
@@ -62,7 +62,22 @@ repeat_block row
restore
end_block block
+save
translate 400 0
brushRotate 30.0
brushScale 1.5 .5
repeat_block block
+restore
+
+drawText 80 400 "BRUSH XFORM, OBJECT BOUNDING MODE"
+drawText 500 400 "BRUSH XFORM, OBJECT MODE"
+
+translate 0 400
+brushTranslate 0.5 0.5
+brushRotate 180.0
+brushTranslate -0.5 -0.5
+repeat_block block
+
+translate 400 0
+gradient_setCoordinateMode ObjectMode
+repeat_block block