From 948fa572de1c6398df03246b7a6c124af312e967 Mon Sep 17 00:00:00 2001 From: Louai Al-Khanji Date: Tue, 29 Apr 2014 16:15:55 +0300 Subject: Direct2D QPA: Add handlers for individual primitives Directly handling primitives is faster than using the catch-all fill function which converts arbitrary paths into a direct2d geometry. So do so. Change-Id: I71ce73dbe75aa9b61e741c358d8787d0ea48ee46 Reviewed-by: Risto Avila Reviewed-by: Friedemann Kleint Reviewed-by: Andrew Knight --- .../direct2d/qwindowsdirect2dpaintengine.cpp | 272 +++++++++++++++++++-- .../direct2d/qwindowsdirect2dpaintengine.h | 18 ++ 2 files changed, 269 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index 0c3618132d..58c30b6eeb 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -72,8 +72,15 @@ QT_BEGIN_NAMESPACE // http://msdn.microsoft.com/en-us/library/windows/desktop/dd370979(v=vs.85).aspx enum { D2DDebugDrawInitialStateTag = -1, - D2DDebugDrawImageTag = 1, - D2DDebugFillTag, + D2DDebugFillTag = 1, + D2DDebugFillRectTag, + D2DDebugDrawRectsTag, + D2DDebugDrawRectFsTag, + D2DDebugDrawLinesTag, + D2DDebugDrawLineFsTag, + D2DDebugDrawEllipseTag, + D2DDebugDrawEllipseFTag, + D2DDebugDrawImageTag, D2DDebugDrawPixmapTag, D2DDebugDrawStaticTextItemTag, D2DDebugDrawTextItemTag @@ -933,7 +940,7 @@ void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &br ensureBrush(brush); - if (!state()->matrix.isAffine() || d->brush.emulate) { + if (emulationRequired(BrushEmulation)) { rasterFill(path, brush); return; } @@ -941,25 +948,13 @@ void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &br if (!d->brush.brush) return; - if (path.isRect()) { - const qreal * const points = path.points(); - D2D_RECT_F rect = { - points[0], // left - points[1], // top - points[2], // right, - points[5] // bottom - }; - - d->dc()->FillRectangle(rect, d->brush.brush.Get()); - } else { - ComPtr geometry = vectorPathToID2D1PathGeometry(path, d->antialiasMode() == D2D1_ANTIALIAS_MODE_ALIASED); - if (!geometry) { - qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__); - return; - } - - d->dc()->FillGeometry(geometry.Get(), d->brush.brush.Get()); + ComPtr geometry = vectorPathToID2D1PathGeometry(path, d->antialiasMode() == D2D1_ANTIALIAS_MODE_ALIASED); + if (!geometry) { + qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__); + return; } + + d->dc()->FillGeometry(geometry.Get(), d->brush.brush.Get()); } void QWindowsDirect2DPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) @@ -1016,6 +1011,198 @@ void QWindowsDirect2DPaintEngine::transformChanged() d->updateTransform(state()->transform()); } +void QWindowsDirect2DPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugFillRectTag); + + ensureBrush(brush); + + if (emulationRequired(BrushEmulation)) { + QPaintEngineEx::fillRect(rect, brush); + } else { + QRectF r = rect.normalized(); + adjustForAliasing(&r); + + if (d->brush.brush) + d->dc()->FillRectangle(to_d2d_rect_f(rect), d->brush.brush.Get()); + } +} + +void QWindowsDirect2DPaintEngine::drawRects(const QRect *rects, int rectCount) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawRectsTag); + + ensureBrush(); + ensurePen(); + + if (emulationRequired(BrushEmulation) || emulationRequired(PenEmulation)) { + QPaintEngineEx::drawRects(rects, rectCount); + } else { + QRectF rect; + for (int i = 0; i < rectCount; i++) { + rect = rects[i].normalized(); + adjustForAliasing(&rect); + + D2D1_RECT_F d2d_rect = to_d2d_rect_f(rect); + + if (d->brush.brush) + d->dc()->FillRectangle(d2d_rect, d->brush.brush.Get()); + + if (d->pen.brush) + d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + } + } +} + +void QWindowsDirect2DPaintEngine::drawRects(const QRectF *rects, int rectCount) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawRectFsTag); + + ensureBrush(); + ensurePen(); + + if (emulationRequired(BrushEmulation) || emulationRequired(PenEmulation)) { + QPaintEngineEx::drawRects(rects, rectCount); + } else { + QRectF rect; + for (int i = 0; i < rectCount; i++) { + rect = rects[i].normalized(); + adjustForAliasing(&rect); + + D2D1_RECT_F d2d_rect = to_d2d_rect_f(rect); + + if (d->brush.brush) + d->dc()->FillRectangle(d2d_rect, d->brush.brush.Get()); + + if (d->pen.brush) + d->dc()->DrawRectangle(d2d_rect, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + } + } +} + +void QWindowsDirect2DPaintEngine::drawLines(const QLine *lines, int lineCount) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawLinesTag); + + ensurePen(); + + if (emulationRequired(PenEmulation)) { + QPaintEngineEx::drawLines(lines, lineCount); + } else if (d->pen.brush) { + for (int i = 0; i < lineCount; i++) { + QPointF p1 = lines[i].p1(); + QPointF p2 = lines[i].p2(); + + // Match raster engine output + if (p1 == p2 && d->pen.qpen.widthF() <= 1.0) { + fillRect(QRectF(p1, QSizeF(d->pen.qpen.widthF(), d->pen.qpen.widthF())), + d->pen.qpen.brush()); + continue; + } + + adjustForAliasing(&p1); + adjustForAliasing(&p2); + + D2D1_POINT_2F d2d_p1 = to_d2d_point_2f(p1); + D2D1_POINT_2F d2d_p2 = to_d2d_point_2f(p2); + + d->dc()->DrawLine(d2d_p1, d2d_p2, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + } + } +} + +void QWindowsDirect2DPaintEngine::drawLines(const QLineF *lines, int lineCount) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawLineFsTag); + + ensurePen(); + + if (emulationRequired(PenEmulation)) { + QPaintEngineEx::drawLines(lines, lineCount); + } else if (d->pen.brush) { + for (int i = 0; i < lineCount; i++) { + QPointF p1 = lines[i].p1(); + QPointF p2 = lines[i].p2(); + + // Match raster engine output + if (p1 == p2 && d->pen.qpen.widthF() <= 1.0) { + fillRect(QRectF(p1, QSizeF(d->pen.qpen.widthF(), d->pen.qpen.widthF())), + d->pen.qpen.brush()); + continue; + } + + adjustForAliasing(&p1); + adjustForAliasing(&p2); + + D2D1_POINT_2F d2d_p1 = to_d2d_point_2f(p1); + D2D1_POINT_2F d2d_p2 = to_d2d_point_2f(p2); + + d->dc()->DrawLine(d2d_p1, d2d_p2, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + } + } +} + +void QWindowsDirect2DPaintEngine::drawEllipse(const QRectF &r) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawEllipseFTag); + + ensureBrush(); + ensurePen(); + + if (emulationRequired(BrushEmulation) || emulationRequired(PenEmulation)) { + QPaintEngineEx::drawEllipse(r); + } else { + QPointF p = r.center(); + adjustForAliasing(&p); + + D2D1_ELLIPSE ellipse = { + to_d2d_point_2f(p), + r.width() / 2.0, + r.height() / 2.0 + }; + + if (d->brush.brush) + d->dc()->FillEllipse(ellipse, d->brush.brush.Get()); + + if (d->pen.brush) + d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + } +} + +void QWindowsDirect2DPaintEngine::drawEllipse(const QRect &r) +{ + Q_D(QWindowsDirect2DPaintEngine); + D2D_TAG(D2DDebugDrawEllipseTag); + + ensureBrush(); + ensurePen(); + + if (emulationRequired(BrushEmulation) || emulationRequired(PenEmulation)) { + QPaintEngineEx::drawEllipse(r); + } else { + QPointF p = r.center(); + adjustForAliasing(&p); + + D2D1_ELLIPSE ellipse = { + to_d2d_point_2f(p), + r.width() / 2.0, + r.height() / 2.0 + }; + + if (d->brush.brush) + d->dc()->FillEllipse(ellipse, d->brush.brush.Get()); + + if (d->pen.brush) + d->dc()->DrawEllipse(ellipse, d->pen.brush.Get(), d->pen.qpen.widthF(), d->pen.strokeStyle.Get()); + } +} + void QWindowsDirect2DPaintEngine::drawImage(const QRectF &rectangle, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags) { @@ -1388,4 +1575,47 @@ void QWindowsDirect2DPaintEngine::rasterFill(const QVectorPath &path, const QBru } } +bool QWindowsDirect2DPaintEngine::emulationRequired(EmulationType type) const +{ + Q_D(const QWindowsDirect2DPaintEngine); + + if (!state()->matrix.isAffine()) + return true; + + switch (type) { + case PenEmulation: + return d->pen.emulate; + break; + case BrushEmulation: + return d->brush.emulate; + break; + } + + return false; +} + +bool QWindowsDirect2DPaintEngine::antiAliasingEnabled() const +{ + return state()->renderHints & QPainter::Antialiasing; +} + +void QWindowsDirect2DPaintEngine::adjustForAliasing(QRectF *rect) +{ + if (!antiAliasingEnabled()) { + rect->adjust(MAGICAL_ALIASING_OFFSET, + MAGICAL_ALIASING_OFFSET, + MAGICAL_ALIASING_OFFSET, + MAGICAL_ALIASING_OFFSET); + } +} + +void QWindowsDirect2DPaintEngine::adjustForAliasing(QPointF *point) +{ + static const QPointF adjustment(MAGICAL_ALIASING_OFFSET, + MAGICAL_ALIASING_OFFSET); + + if (!antiAliasingEnabled()) + (*point) += adjustment; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h index 93ccf809e4..badd7a7688 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h @@ -79,6 +79,17 @@ public: void renderHintsChanged() Q_DECL_OVERRIDE; void transformChanged() Q_DECL_OVERRIDE; + void fillRect(const QRectF &rect, const QBrush &brush) Q_DECL_OVERRIDE; + + void drawRects(const QRect *rects, int rectCount) Q_DECL_OVERRIDE; + void drawRects(const QRectF *rects, int rectCount) Q_DECL_OVERRIDE; + + void drawLines(const QLine *lines, int lineCount) Q_DECL_OVERRIDE; + void drawLines(const QLineF *lines, int lineCount) Q_DECL_OVERRIDE; + + void drawEllipse(const QRectF &r) Q_DECL_OVERRIDE; + void drawEllipse(const QRect &r) Q_DECL_OVERRIDE; + void drawImage(const QRectF &rectangle, const QImage &image, const QRectF &sr, Qt::ImageConversionFlags flags = Qt::AutoColor) Q_DECL_OVERRIDE; void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) Q_DECL_OVERRIDE; @@ -96,6 +107,13 @@ private: void ensurePen(const QPen &pen); void rasterFill(const QVectorPath &path, const QBrush &brush); + + enum EmulationType { PenEmulation, BrushEmulation }; + bool emulationRequired(EmulationType type) const; + + bool antiAliasingEnabled() const; + void adjustForAliasing(QRectF *rect); + void adjustForAliasing(QPointF *point); }; QT_END_NAMESPACE -- cgit v1.2.3