Support cosmetic brush patterns in the pdf and opengl paint engines

This implements the recent functionality extension of painting
cosmetic (untransformed) brush patterns, and the corresponding
NonCosmeticBrushPatterns render hint, in the pdf and opengl paint
engines.

As part of the implementation it also fixes a couple of pre-existing
bugs in the opengl engine, relating to updating the brush after
changes in transformation or brush origin.

As a driveby, it also includes a minor fix for the lance testing tool:
request stencil buffer, as that is needed and not always provided by
default. This echoes a recent fix done to tst_baseline_painting.

Change-Id: Ia8811477e015eebeb40ed138bca96643ce1ab0dc
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
Eirik Aavitsland 2022-06-02 16:40:05 +02:00
parent f8c5f4b7b5
commit f67d89ebde
5 changed files with 116 additions and 11 deletions

View File

@ -1081,6 +1081,9 @@ void QPdfEngine::updateState(const QPaintEngineState &state)
QPaintEngine::DirtyFlags flags = state.state(); QPaintEngine::DirtyFlags flags = state.state();
if (flags & DirtyHints)
flags |= DirtyBrush;
if (flags & DirtyTransform) if (flags & DirtyTransform)
d->stroker.matrix = state.transform(); d->stroker.matrix = state.transform();
@ -2714,18 +2717,22 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor,
*specifyColor = true; *specifyColor = true;
*gStateObject = 0; *gStateObject = 0;
QTransform matrix = m; const Qt::BrushStyle style = brush.style();
const bool isCosmetic = style >= Qt::Dense1Pattern && style <= Qt::DiagCrossPattern
&& !q->painter()->testRenderHint(QPainter::NonCosmeticBrushPatterns);
QTransform matrix;
if (!isCosmetic)
matrix = m;
matrix.translate(brushOrigin.x(), brushOrigin.y()); matrix.translate(brushOrigin.x(), brushOrigin.y());
matrix = matrix * pageMatrix(); matrix = matrix * pageMatrix();
//qDebug() << brushOrigin << matrix;
Qt::BrushStyle style = brush.style();
if (style == Qt::LinearGradientPattern || style == Qt::RadialGradientPattern) {// && style <= Qt::ConicalGradientPattern) { if (style == Qt::LinearGradientPattern || style == Qt::RadialGradientPattern) {// && style <= Qt::ConicalGradientPattern) {
*specifyColor = false; *specifyColor = false;
return gradientBrush(brush, matrix, gStateObject); return gradientBrush(brush, matrix, gStateObject);
} }
matrix = brush.transform() * matrix; if (!isCosmetic)
matrix = brush.transform() * matrix;
if ((!brush.isOpaque() && brush.style() < Qt::LinearGradientPattern) || opacity != 1.0) if ((!brush.isOpaque() && brush.style() < Qt::LinearGradientPattern) || opacity != 1.0)
*gStateObject = addConstantAlphaObject(qRound(brush.color().alpha() * opacity), *gStateObject = addConstantAlphaObject(qRound(brush.color().alpha() * opacity),

View File

@ -304,6 +304,7 @@ void QOpenGL2PaintEngineExPrivate::updateBrushUniforms()
return; return;
QTransform brushQTransform = currentBrush.transform(); QTransform brushQTransform = currentBrush.transform();
bool isCosmetic = false;
if (style == Qt::SolidPattern) { if (style == Qt::SolidPattern) {
QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity);
@ -320,6 +321,8 @@ void QOpenGL2PaintEngineExPrivate::updateBrushUniforms()
QVector2D halfViewportSize(width*0.5, height*0.5); QVector2D halfViewportSize(width*0.5, height*0.5);
shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize); shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize);
isCosmetic = !q->painter()->testRenderHint(QPainter::NonCosmeticBrushPatterns);
} }
else if (style == Qt::LinearGradientPattern) { else if (style == Qt::LinearGradientPattern) {
const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush.gradient()); const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush.gradient());
@ -394,8 +397,12 @@ void QOpenGL2PaintEngineExPrivate::updateBrushUniforms()
qWarning("QOpenGL2PaintEngineEx: Unimplemented fill style"); qWarning("QOpenGL2PaintEngineEx: Unimplemented fill style");
const QPointF &brushOrigin = q->state()->brushOrigin; const QPointF &brushOrigin = q->state()->brushOrigin;
QTransform matrix = q->state()->matrix; QTransform matrix;
if (!isCosmetic)
matrix = q->state()->matrix;
matrix.translate(brushOrigin.x(), brushOrigin.y()); matrix.translate(brushOrigin.x(), brushOrigin.y());
if (!isCosmetic)
matrix = brushQTransform * matrix;
QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y()); QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y());
qreal m22 = -1; qreal m22 = -1;
@ -405,7 +412,7 @@ void QOpenGL2PaintEngineExPrivate::updateBrushUniforms()
dy = 0; dy = 0;
} }
QTransform gl_to_qt(1, 0, 0, m22, 0, dy); QTransform gl_to_qt(1, 0, 0, m22, 0, dy);
QTransform inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate; QTransform inv_matrix = gl_to_qt * matrix.inverted() * translate;
shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BrushTransform), inv_matrix); shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BrushTransform), inv_matrix);
shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT); shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT);
@ -818,8 +825,11 @@ void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path)
} }
// Might need to call updateMatrix to re-calculate inverseScale // Might need to call updateMatrix to re-calculate inverseScale
if (matrixDirty) if (matrixDirty) {
updateMatrix(); updateMatrix();
if (currentBrush.style() > Qt::SolidPattern)
brushUniformsDirty = true;
}
const bool supportsElementIndexUint = funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint); const bool supportsElementIndexUint = funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint);
@ -1419,7 +1429,12 @@ void QOpenGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &p
void QOpenGL2PaintEngineEx::penChanged() { } void QOpenGL2PaintEngineEx::penChanged() { }
void QOpenGL2PaintEngineEx::brushChanged() { } void QOpenGL2PaintEngineEx::brushChanged() { }
void QOpenGL2PaintEngineEx::brushOriginChanged() { }
void QOpenGL2PaintEngineEx::brushOriginChanged()
{
Q_D(QOpenGL2PaintEngineEx);
d->brushUniformsDirty = true;
}
void QOpenGL2PaintEngineEx::opacityChanged() void QOpenGL2PaintEngineEx::opacityChanged()
{ {
@ -1462,7 +1477,7 @@ void QOpenGL2PaintEngineEx::renderHintsChanged()
d->lastTextureUsed = GLuint(-1); d->lastTextureUsed = GLuint(-1);
d->brushTextureDirty = true; d->brushTextureDirty = true;
// qDebug("QOpenGL2PaintEngineEx::renderHintsChanged() not implemented!"); d->brushUniformsDirty = true;
} }
void QOpenGL2PaintEngineEx::transformChanged() void QOpenGL2PaintEngineEx::transformChanged()

View File

@ -9,13 +9,14 @@ setBrush green Dense4Pattern
drawRect 0 0 40 40 drawRect 0 0 40 40
setBrush green DiagCrossPattern setBrush green DiagCrossPattern
drawRect 40 0 40 40 drawRect 40 0 40 40
setBrush green VerPattern setBrush green HorPattern
brushRotate 30 brushRotate 30
drawRect 80 0 40 40 drawRect 80 0 40 40
fillRect 120 0 40 40
save save
setPen brush 40 SolidLine FlatCap setPen brush 40 SolidLine FlatCap
setBrush NoBrush setBrush NoBrush
drawLine 120 20 160 20 drawLine 160 20 200 20
restore restore
end_block end_block
restore restore

View File

@ -0,0 +1,81 @@
# Version: 1
# CheckVsReference: 5%
# 1: Check brush origin vs (non)cosmetic brush patterns
setBrush blue CrossPattern
begin_block blockName
save
setBrushOrigin 0 0
fillRect 0 0 32 32
translate 0 32
setBrushOrigin 1 0
fillRect 0 0 32 32
translate 0 32
setBrushOrigin 2 0
fillRect 0 0 32 32
translate 0 32
setBrushOrigin 3 0
fillRect 0 0 32 32
translate 0 32
setBrushOrigin 4 0
fillRect 0 0 32 32
translate 0 32
setBrushOrigin 5 0
fillRect 0 0 32 32
translate 0 32
setBrushOrigin 6 0
fillRect 0 0 32 32
translate 0 32
setBrushOrigin 7 0
fillRect 0 0 32 32
translate 0 32
setBrushOrigin 8 0
fillRect 0 0 32 32
restore
end_block blockName
save
setBrush red CrossPattern
scale 2 1
repeat_block blockName
restore
save
translate 0 300
setRenderHint NonCosmeticBrushPatterns true
setBrush blue CrossPattern
repeat_block blockName
setBrush red CrossPattern
scale 2 1
repeat_block blockName
restore
# 2: Check brush update after only xform or hint change
translate 100 0
save
setPen NoPen
setBrush blue DiagCrossPattern
setRenderHint NonCosmeticBrushPatterns true
drawRect 10 10 200 100
scale 10 10
drawRect 22 1 20 10
drawRect 22 12 20 10
setRenderHint NonCosmeticBrushPatterns false
drawRect 1 12 20 10
restore
setBrush green DiagCrossPattern
setPen brush 100 SolidLine FlatCap
pen_setCosmetic true
setBrush NoBrush
translate 0 250
setRenderHint NonCosmeticBrushPatterns true
drawLine 10 60 210 60
scale 10 10
drawLine 22 6 42 6
drawLine 22 17 42 17
setRenderHint NonCosmeticBrushPatterns false
drawLine 1 17 21 17

View File

@ -191,6 +191,7 @@ int main(int argc, char **argv)
DeviceType type = WidgetType; DeviceType type = WidgetType;
QSurfaceFormat contextFormat; QSurfaceFormat contextFormat;
contextFormat.setStencilBufferSize(8);
bool checkers_background = true; bool checkers_background = true;
QImage::Format imageFormat = QImage::Format_ARGB32_Premultiplied; QImage::Format imageFormat = QImage::Format_ARGB32_Premultiplied;