summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEirik Aavitsland <[email protected]>2022-05-20 16:47:42 +0200
committerEirik Aavitsland <[email protected]>2022-05-31 21:20:41 +0200
commit5adaa8d868b6718e07035152351b14449cea95d3 (patch)
tree3b08ac3e7db2c9c0850c8026dcad0a53a4dc33bf
parent5e48a51608485cbc87b68498fd54ab36f001d584 (diff)
Add painter render hint for brush pattern transformation
[ChangeLog][QtGui][QPainter] In Qt 5, the predefined brush patterns would always be transformed along with the object being painted. In Qt 6.0 onwards, they would or would not, depending on the SmoothPixmapTransformation render hint. Instead of this somewhat surprising behavior, make the default be untransformed (i.e. cosmetic), which makes sense when it comes to dpr scaling. For the cases where one wants scaling, a new render hint is introduced to enable that: NonCosmeticPatternBrushes. Change-Id: I2208c7a28af9056d7ab97a529b66bf2d502c3c4f Reviewed-by: Allan Sandfeld Jensen <[email protected]>
-rw-r--r--src/gui/image/qpicture.cpp2
-rw-r--r--src/gui/painting/qdrawhelper.cpp12
-rw-r--r--src/gui/painting/qdrawhelper_p.h2
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp19
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h1
-rw-r--r--src/gui/painting/qpainter.cpp6
-rw-r--r--src/gui/painting/qpainter.h1
-rw-r--r--tests/baseline/painting/scripts/pattern_xform.qps78
-rw-r--r--tests/baseline/shared/paintcommands.cpp35
-rw-r--r--tests/baseline/shared/paintcommands.h1
10 files changed, 134 insertions, 23 deletions
diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp
index 3f4dec37d5f..da8c5ef1e54 100644
--- a/src/gui/image/qpicture.cpp
+++ b/src/gui/image/qpicture.cpp
@@ -814,6 +814,8 @@ bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
bool(ul & QPainter::Antialiasing));
painter->setRenderHint(QPainter::SmoothPixmapTransform,
bool(ul & QPainter::SmoothPixmapTransform));
+ painter->setRenderHint(QPainter::NonCosmeticBrushPatterns,
+ bool(ul & QPainter::NonCosmeticBrushPatterns));
break;
case QPicturePrivate::PdcSetCompositionMode:
s >> ul;
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 6e498bc2e30..35c44b82864 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -3581,20 +3581,20 @@ static const CompositionFunctionFP *functionForModeFP = qt_functionForModeFP_C;
static TextureBlendType getBlendType(const QSpanData *data)
{
TextureBlendType ft;
- if (data->txop <= QTransform::TxTranslate)
- if (data->texture.type == QTextureData::Tiled || data->texture.type == QTextureData::Pattern)
+ if (data->texture.type == QTextureData::Pattern)
+ ft = BlendTiled;
+ else if (data->txop <= QTransform::TxTranslate)
+ if (data->texture.type == QTextureData::Tiled)
ft = BlendTiled;
else
ft = BlendUntransformed;
else if (data->bilinear)
- if (data->texture.type == QTextureData::Tiled || data->texture.type == QTextureData::Pattern)
+ if (data->texture.type == QTextureData::Tiled)
ft = BlendTransformedBilinearTiled;
else
ft = BlendTransformedBilinear;
else
- if (data->texture.type == QTextureData::Pattern)
- ft = BlendTiled;
- else if (data->texture.type == QTextureData::Tiled)
+ if (data->texture.type == QTextureData::Tiled)
ft = BlendTransformedTiled;
else
ft = BlendTransformed;
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index cad0fa9fa3a..5b6f5ce2165 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -345,7 +345,7 @@ struct QSpanData
void init(QRasterBuffer *rb, const QRasterPaintEngine *pe);
- void setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode);
+ void setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode, bool isCosmetic);
void setupMatrix(const QTransform &matrix, int bilinear);
void initTexture(const QImage *image, int alpha, QTextureData::Type = QTextureData::Plain, const QRect &sourceRect = QRect());
void adjustSpanMethods();
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index a5acd6a3246..4192a0fa071 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -426,12 +426,12 @@ bool QRasterPaintEngine::begin(QPaintDevice *device)
d->rasterizer->setClipRect(d->deviceRect);
s->penData.init(d->rasterBuffer.data(), this);
- s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode);
+ s->penData.setup(s->pen.brush(), s->intOpacity, s->composition_mode, s->flags.cosmetic_brush);
s->stroker = &d->basicStroker;
d->basicStroker.setClipRect(d->deviceRect);
s->brushData.init(d->rasterBuffer.data(), this);
- s->brushData.setup(s->brush, s->intOpacity, s->composition_mode);
+ s->brushData.setup(s->brush, s->intOpacity, s->composition_mode, s->flags.cosmetic_brush);
d->rasterBuffer->compositionMode = QPainter::CompositionMode_SourceOver;
@@ -523,6 +523,7 @@ QRasterPaintEngineState::QRasterPaintEngineState()
flags.fast_text = true;
flags.tx_noshear = true;
flags.fast_images = true;
+ flags.cosmetic_brush = true;
clip = nullptr;
flags.has_clip_ownership = false;
@@ -621,7 +622,8 @@ void QRasterPaintEngine::updatePen(const QPen &pen)
s->strokeFlags = 0;
s->penData.clip = d->clip();
- s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity, s->composition_mode);
+ s->penData.setup(pen_style == Qt::NoPen ? QBrush() : pen.brush(), s->intOpacity,
+ s->composition_mode, s->flags.cosmetic_brush);
if (s->strokeFlags & QRasterPaintEngine::DirtyTransform
|| pen.brush().transform().type() >= QTransform::TxNone) {
@@ -720,7 +722,7 @@ void QRasterPaintEngine::updateBrush(const QBrush &brush)
QRasterPaintEngineState *s = state();
// must set clip prior to setup, as setup uses it...
s->brushData.clip = d->clip();
- s->brushData.setup(brush, s->intOpacity, s->composition_mode);
+ s->brushData.setup(brush, s->intOpacity, s->composition_mode, s->flags.cosmetic_brush);
if (s->fillFlags & DirtyTransform
|| brush.transform().type() >= QTransform::TxNone)
d_func()->updateMatrixData(&s->brushData, brush, d->brushMatrix());
@@ -807,14 +809,16 @@ void QRasterPaintEngine::renderHintsChanged()
bool was_aa = s->flags.antialiased;
bool was_bilinear = s->flags.bilinear;
+ bool was_cosmetic_brush = s->flags.cosmetic_brush;
s->flags.antialiased = bool(s->renderHints & QPainter::Antialiasing);
s->flags.bilinear = bool(s->renderHints & QPainter::SmoothPixmapTransform);
+ s->flags.cosmetic_brush = !bool(s->renderHints & QPainter::NonCosmeticBrushPatterns);
if (was_aa != s->flags.antialiased)
s->strokeFlags |= DirtyHints;
- if (was_bilinear != s->flags.bilinear) {
+ if (was_bilinear != s->flags.bilinear || was_cosmetic_brush != s->flags.cosmetic_brush) {
s->strokeFlags |= DirtyPen;
s->fillFlags |= DirtyBrush;
}
@@ -4472,7 +4476,8 @@ void QSpanData::init(QRasterBuffer *rb, const QRasterPaintEngine *pe)
Q_GUI_EXPORT extern QImage qt_imageForBrush(int brushStyle, bool invert);
-void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode)
+void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode compositionMode,
+ bool isCosmetic)
{
Qt::BrushStyle brushStyle = qbrush_style(brush);
cachedGradient.reset();
@@ -4579,7 +4584,7 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
if (!tempImage)
tempImage = new QImage();
*tempImage = rasterBuffer->colorizeBitmap(qt_imageForBrush(brushStyle, true), brush.color());
- initTexture(tempImage, alpha, QTextureData::Pattern);
+ initTexture(tempImage, alpha, isCosmetic ? QTextureData::Pattern : QTextureData::Tiled);
break;
case Qt::TexturePattern:
type = Texture;
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index abd1a16ade6..c6d723e0c30 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -76,6 +76,7 @@ public:
uint fast_text : 1;
uint tx_noshear : 1;
uint fast_images : 1;
+ uint cosmetic_brush : 1;
};
union {
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index a38d42c5041..6995f7d1800 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -1412,6 +1412,12 @@ void QPainterPrivate::updateState(QPainterState *newState)
JPEG compression.
This value was added in Qt 5.13.
+ \value NonCosmeticBrushPatterns When painting with a brush with one of the predefined pattern
+ styles, transform the pattern too, along with the object being painted. The default is to treat
+ the pattern as cosmetic, so that the pattern pixels will map directly to device pixels,
+ independently of any active transformations.
+ This value was added in Qt 6.4.
+
\sa renderHints(), setRenderHint(), {QPainter#Rendering
Quality}{Rendering Quality}, {Concentric Circles Example}
diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h
index ce3d1fabdbe..7bcacb4bcaa 100644
--- a/src/gui/painting/qpainter.h
+++ b/src/gui/painting/qpainter.h
@@ -54,6 +54,7 @@ public:
SmoothPixmapTransform = 0x04,
VerticalSubpixelPositioning = 0x08,
LosslessImageRendering = 0x40,
+ NonCosmeticBrushPatterns = 0x80
};
Q_ENUM(RenderHint)
diff --git a/tests/baseline/painting/scripts/pattern_xform.qps b/tests/baseline/painting/scripts/pattern_xform.qps
new file mode 100644
index 00000000000..a12ae05c72a
--- /dev/null
+++ b/tests/baseline/painting/scripts/pattern_xform.qps
@@ -0,0 +1,78 @@
+# Version: 1
+# CheckVsReference: 5%
+
+#define basic block off screen
+save
+translate -1000 -1000
+begin_block drawrects
+setBrush green Dense4Pattern
+drawRect 0 0 40 40
+setBrush green DiagCrossPattern
+drawRect 40 0 40 40
+setBrush green VerPattern
+brushRotate 30
+drawRect 80 0 40 40
+save
+setPen brush 40 SolidLine FlatCap
+setBrush NoBrush
+drawLine 120 20 160 20
+restore
+end_block
+restore
+
+begin_block hintsuite
+save
+setRenderHint NonCosmeticBrushPatterns false
+setRenderHint SmoothPixmapTransform false
+translate 10 10
+repeat_block drawrects
+
+setRenderHint NonCosmeticBrushPatterns false
+setRenderHint SmoothPixmapTransform true
+translate 0 50
+repeat_block drawrects
+
+setRenderHint NonCosmeticBrushPatterns true
+setRenderHint SmoothPixmapTransform false
+translate 0 50
+repeat_block drawrects
+
+setRenderHint NonCosmeticBrushPatterns true
+setRenderHint SmoothPixmapTransform true
+translate 0 50
+repeat_block drawrects
+restore
+end_block
+
+save
+translate 0 200
+scale 2 2
+repeat_block hintsuite
+restore
+
+save
+translate 500 0
+scale 1.5 2.5
+rotate_y 60
+repeat_block hintsuite
+restore
+
+
+translate 0 650
+setBrush blue CrossPattern
+setPen red
+setRenderHint NonCosmeticBrushPatterns false
+
+begin_block dots
+save
+drawRect 0 0 50 50
+setBrushOrigin 12 0
+drawRect 50 0 50 50
+scale 2 1
+drawRect 50 0 50 50
+restore
+end_block dots
+
+setRenderHint NonCosmeticBrushPatterns true
+translate 0 60
+repeat_block dots
diff --git a/tests/baseline/shared/paintcommands.cpp b/tests/baseline/shared/paintcommands.cpp
index daf58a7c2ea..4a3de0168b9 100644
--- a/tests/baseline/shared/paintcommands.cpp
+++ b/tests/baseline/shared/paintcommands.cpp
@@ -175,6 +175,12 @@ const char *PaintCommands::imageFormatTable[] = {
"RGBA32FPx4_Premultiplied",
};
+const char *PaintCommands::renderHintTable[] = {
+ "Antialiasing",
+ "SmoothPixmapTransform",
+ "NonCosmeticBrushPatterns"
+};
+
int PaintCommands::translateEnum(const char *table[], const QString &pattern, int limit)
{
QByteArray p = pattern.toLatin1().toLower();
@@ -313,7 +319,7 @@ void PaintCommands::staticInit()
"pen_setCosmetic true");
DECL_PAINTCOMMAND("setRenderHint", command_setRenderHint,
"^setRenderHint\\s+([\\w_0-9]*)\\s*(\\w*)$",
- "setRenderHint <Antialiasing|SmoothPixmapTransform> <true|false>",
+ "setRenderHint <hint> <true|false>",
"setRenderHint Antialiasing true");
DECL_PAINTCOMMAND("clearRenderHint", command_clearRenderHint,
"^clearRenderHint$",
@@ -665,6 +671,7 @@ void PaintCommands::staticInit()
ADD_ENUMLIST("image formats", imageFormatTable);
ADD_ENUMLIST("coordinate modes", coordinateMethodTable);
ADD_ENUMLIST("size modes", sizeModeTable);
+ ADD_ENUMLIST("render hints", renderHintTable);
}
#undef DECL_PAINTCOMMAND
@@ -2240,18 +2247,27 @@ void PaintCommands::command_setPen2(QRegularExpressionMatch re)
void PaintCommands::command_setRenderHint(QRegularExpressionMatch re)
{
QString hintString = re.captured(1).toLower();
- bool on = re.captured(2).isEmpty() || re.captured(2).toLower() == "true";
- if (hintString.contains("antialiasing")) {
- if (m_verboseMode)
- printf(" -(lance) setRenderHint Antialiasing\n");
+ QString setting = re.captured(2).toLower();
- m_painter->setRenderHint(QPainter::Antialiasing, on);
+ bool on = setting.isEmpty() || setting == "true" || setting == "on";
+ QPainter::RenderHint hint;
+ int hintIdx = -1;
+ if (hintString.contains("antialiasing")) {
+ hintIdx = 0;
+ hint = QPainter::Antialiasing;
} else if (hintString.contains("smoothpixmaptransform")) {
+ hintIdx = 1;
+ hint = QPainter::SmoothPixmapTransform;
+ } else if (hintString.contains("noncosmeticbrushpatterns")) {
+ hintIdx = 2;
+ hint = QPainter::NonCosmeticBrushPatterns;
+ }
+ if (hintIdx >= 0) {
if (m_verboseMode)
- printf(" -(lance) setRenderHint SmoothPixmapTransform\n");
- m_painter->setRenderHint(QPainter::SmoothPixmapTransform, on);
+ printf(" -(lance) setRenderHint %s %s\n", renderHintTable[hintIdx], on ? "true" : "false");
+ m_painter->setRenderHint(hint, on);
} else {
- fprintf(stderr, "ERROR(setRenderHint): unknown hint '%s'\n", qPrintable(hintString));
+ fprintf(stderr, "ERROR(setRenderHint): unknown hint '%s'\n", qPrintable(re.captured(1)));
}
}
@@ -2260,6 +2276,7 @@ void PaintCommands::command_clearRenderHint(QRegularExpressionMatch /*re*/)
{
m_painter->setRenderHint(QPainter::Antialiasing, false);
m_painter->setRenderHint(QPainter::SmoothPixmapTransform, false);
+ m_painter->setRenderHint(QPainter::NonCosmeticBrushPatterns, false);
if (m_verboseMode)
printf(" -(lance) clearRenderHint\n");
}
diff --git a/tests/baseline/shared/paintcommands.h b/tests/baseline/shared/paintcommands.h
index 75f48d3eb7c..0d8044fc470 100644
--- a/tests/baseline/shared/paintcommands.h
+++ b/tests/baseline/shared/paintcommands.h
@@ -280,6 +280,7 @@ private:
static const char *compositionModeTable[];
static const char *imageFormatTable[];
static const char *sizeModeTable[];
+ static const char *renderHintTable[];
static int translateEnum(const char *table[], const QString &pattern, int limit);
// utility