Direct2D QPA: Improve software fallback mechanism

Improve the way we fall back to the raster engine by forwarding painting
state. Amongst other things this makes perspective transforms appear
correct.

Change-Id: I729de56ef3112bbc01516fc11c295f33a2aada0d
Reviewed-by: Risto Avila <risto.avila@digia.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Reviewed-by: Andrew Knight <andrew.knight@digia.com>
This commit is contained in:
Louai Al-Khanji 2014-04-23 16:07:05 +03:00 committed by The Qt Project
parent 1467b63b06
commit cc15a20d03
3 changed files with 80 additions and 45 deletions

View File

@ -84,8 +84,6 @@ Q_DECL_CONSTEXPR inline D2D1::ColorF to_d2d_color_f(const QColor &c)
Q_DECL_CONSTEXPR inline D2D1_MATRIX_3X2_F to_d2d_matrix_3x2_f(const QTransform &transform) Q_DECL_CONSTEXPR inline D2D1_MATRIX_3X2_F to_d2d_matrix_3x2_f(const QTransform &transform)
{ {
Q_ASSERT(transform.isAffine());
return D2D1::Matrix3x2F(transform.m11(), transform.m12(), return D2D1::Matrix3x2F(transform.m11(), transform.m12(),
transform.m21(), transform.m22(), transform.m21(), transform.m22(),
transform.m31(), transform.m32()); transform.m31(), transform.m32());

View File

@ -378,17 +378,13 @@ public:
: D2D1_ANTIALIAS_MODE_ALIASED; : D2D1_ANTIALIAS_MODE_ALIASED;
} }
void updateTransform() void updateTransform(const QTransform &transform)
{ {
Q_Q(const QWindowsDirect2DPaintEngine); dc()->SetTransform(to_d2d_matrix_3x2_f(transform));
// Note the loss of info going from 3x3 to 3x2 matrix here
dc()->SetTransform(to_d2d_matrix_3x2_f(q->state()->transform()));
} }
void updateOpacity() void updateOpacity(qreal opacity)
{ {
Q_Q(const QWindowsDirect2DPaintEngine);
qreal opacity = q->state()->opacity;
if (brush.brush) if (brush.brush)
brush.brush->SetOpacity(opacity); brush.brush->SetOpacity(opacity);
if (pen.brush) if (pen.brush)
@ -447,10 +443,9 @@ public:
} }
} }
void updateClipEnabled() void updateClipEnabled(bool enabled)
{ {
Q_Q(const QWindowsDirect2DPaintEngine); if (!enabled)
if (!q->state()->clipEnabled)
clearClips(); clearClips();
else if (pushedClips.isEmpty()) else if (pushedClips.isEmpty())
replayClipOperations(); replayClipOperations();
@ -472,11 +467,8 @@ public:
} }
} }
void updateCompositionMode() void updateCompositionMode(QPainter::CompositionMode mode)
{ {
Q_Q(const QWindowsDirect2DPaintEngine);
QPainter::CompositionMode mode = q->state()->compositionMode();
switch (mode) { switch (mode) {
case QPainter::CompositionMode_Source: case QPainter::CompositionMode_Source:
dc()->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY); dc()->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY);
@ -507,12 +499,10 @@ public:
} }
} }
void updateBrushOrigin() void updateBrushOrigin(const QPointF &brushOrigin)
{ {
Q_Q(const QWindowsDirect2DPaintEngine);
negateCurrentBrushOrigin(); negateCurrentBrushOrigin();
applyBrushOrigin(q->state()->brushOrigin); applyBrushOrigin(brushOrigin);
} }
void negateCurrentBrushOrigin() void negateCurrentBrushOrigin()
@ -934,26 +924,8 @@ void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &br
ensureBrush(brush); ensureBrush(brush);
if (d->brush.emulate) { if (!state()->matrix.isAffine() || d->brush.emulate) {
// We mostly (only?) get here when gradients are required. rasterFill(path, brush);
// We natively support only linear and radial gradients that have pad reflect due to D2D limitations
QImage img(d->bitmap->size(), QImage::Format_ARGB32);
img.fill(Qt::transparent);
QPainter p;
QPaintEngine *engine = img.paintEngine();
if (engine->isExtended() && p.begin(&img)) {
QPaintEngineEx *extended = static_cast<QPaintEngineEx *>(engine);
extended->fill(path, brush);
if (!p.end())
qWarning("%s: Paint Engine end returned false", __FUNCTION__);
drawImage(img.rect(), img, img.rect());
} else {
qWarning("%s: Could not fall back to QImage", __FUNCTION__);
}
return; return;
} }
@ -990,7 +962,7 @@ void QWindowsDirect2DPaintEngine::clip(const QVectorPath &path, Qt::ClipOperatio
void QWindowsDirect2DPaintEngine::clipEnabledChanged() void QWindowsDirect2DPaintEngine::clipEnabledChanged()
{ {
Q_D(QWindowsDirect2DPaintEngine); Q_D(QWindowsDirect2DPaintEngine);
d->updateClipEnabled(); d->updateClipEnabled(state()->clipEnabled);
} }
void QWindowsDirect2DPaintEngine::penChanged() void QWindowsDirect2DPaintEngine::penChanged()
@ -1008,19 +980,19 @@ void QWindowsDirect2DPaintEngine::brushChanged()
void QWindowsDirect2DPaintEngine::brushOriginChanged() void QWindowsDirect2DPaintEngine::brushOriginChanged()
{ {
Q_D(QWindowsDirect2DPaintEngine); Q_D(QWindowsDirect2DPaintEngine);
d->updateBrushOrigin(); d->updateBrushOrigin(state()->brushOrigin);
} }
void QWindowsDirect2DPaintEngine::opacityChanged() void QWindowsDirect2DPaintEngine::opacityChanged()
{ {
Q_D(QWindowsDirect2DPaintEngine); Q_D(QWindowsDirect2DPaintEngine);
d->updateOpacity(); d->updateOpacity(state()->opacity);
} }
void QWindowsDirect2DPaintEngine::compositionModeChanged() void QWindowsDirect2DPaintEngine::compositionModeChanged()
{ {
Q_D(QWindowsDirect2DPaintEngine); Q_D(QWindowsDirect2DPaintEngine);
d->updateCompositionMode(); d->updateCompositionMode(state()->compositionMode());
} }
void QWindowsDirect2DPaintEngine::renderHintsChanged() void QWindowsDirect2DPaintEngine::renderHintsChanged()
@ -1032,7 +1004,7 @@ void QWindowsDirect2DPaintEngine::renderHintsChanged()
void QWindowsDirect2DPaintEngine::transformChanged() void QWindowsDirect2DPaintEngine::transformChanged()
{ {
Q_D(QWindowsDirect2DPaintEngine); Q_D(QWindowsDirect2DPaintEngine);
d->updateTransform(); d->updateTransform(state()->transform());
} }
void QWindowsDirect2DPaintEngine::drawImage(const QRectF &rectangle, const QImage &image, void QWindowsDirect2DPaintEngine::drawImage(const QRectF &rectangle, const QImage &image,
@ -1344,4 +1316,67 @@ void QWindowsDirect2DPaintEngine::ensurePen(const QPen &pen)
d->updatePen(pen); d->updatePen(pen);
} }
void QWindowsDirect2DPaintEngine::rasterFill(const QVectorPath &path, const QBrush &brush)
{
Q_D(QWindowsDirect2DPaintEngine);
QImage img(d->bitmap->size(), QImage::Format_ARGB32);
img.fill(Qt::transparent);
QPainter p;
QPaintEngine *engine = img.paintEngine();
if (engine->isExtended() && p.begin(&img)) {
p.setRenderHints(state()->renderHints);
p.setCompositionMode(state()->compositionMode());
p.setOpacity(state()->opacity);
p.setBrushOrigin(state()->brushOrigin);
p.setBrush(state()->brush);
p.setPen(state()->pen);
QPaintEngineEx *extended = static_cast<QPaintEngineEx *>(engine);
foreach (const QPainterClipInfo &info, state()->clipInfo) {
extended->state()->matrix = info.matrix;
extended->transformChanged();
switch (info.clipType) {
case QPainterClipInfo::RegionClip:
extended->clip(info.region, info.operation);
break;
case QPainterClipInfo::PathClip:
extended->clip(info.path, info.operation);
break;
case QPainterClipInfo::RectClip:
extended->clip(info.rect, info.operation);
break;
case QPainterClipInfo::RectFClip:
qreal right = info.rectf.x() + info.rectf.width();
qreal bottom = info.rectf.y() + info.rectf.height();
qreal pts[] = { info.rectf.x(), info.rectf.y(),
right, info.rectf.y(),
right, bottom,
info.rectf.x(), bottom };
QVectorPath vp(pts, 4, 0, QVectorPath::RectangleHint);
extended->clip(vp, info.operation);
break;
}
}
extended->state()->matrix = state()->matrix;
extended->transformChanged();
extended->fill(path, brush);
if (!p.end())
qWarning("%s: Paint Engine end returned false", __FUNCTION__);
d->updateClipEnabled(false);
d->updateTransform(QTransform());
drawImage(img.rect(), img, img.rect());
transformChanged();
clipEnabledChanged();
} else {
qWarning("%s: Could not fall back to QImage", __FUNCTION__);
}
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -94,6 +94,8 @@ private:
void ensureBrush(const QBrush &brush); void ensureBrush(const QBrush &brush);
void ensurePen(); void ensurePen();
void ensurePen(const QPen &pen); void ensurePen(const QPen &pen);
void rasterFill(const QVectorPath &path, const QBrush &brush);
}; };
QT_END_NAMESPACE QT_END_NAMESPACE