diff options
5 files changed, 188 insertions, 22 deletions
diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp index 6e4f64e6f5..23e6118132 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.cpp @@ -125,4 +125,38 @@ bool QWindowsDirect2DDeviceContext::end() return d->end(); } +void QWindowsDirect2DDeviceContext::suspend() +{ + Q_D(QWindowsDirect2DDeviceContext); + if (d->refCount > 0) + d->deviceContext->EndDraw(); +} + +void QWindowsDirect2DDeviceContext::resume() +{ + Q_D(QWindowsDirect2DDeviceContext); + if (d->refCount > 0) + d->deviceContext->BeginDraw(); +} + +QWindowsDirect2DDeviceContextSuspender::QWindowsDirect2DDeviceContextSuspender(QWindowsDirect2DDeviceContext *dc) + : m_dc(dc) +{ + Q_ASSERT(m_dc); + m_dc->suspend(); +} + +QWindowsDirect2DDeviceContextSuspender::~QWindowsDirect2DDeviceContextSuspender() +{ + resume(); +} + +void QWindowsDirect2DDeviceContextSuspender::resume() +{ + if (m_dc) { + m_dc->resume(); + m_dc = Q_NULLPTR; + } +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h index b46b850305..458f8a2598 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2ddevicecontext.h @@ -69,6 +69,7 @@ class QWindowsDirect2DDeviceContextPrivate; class QWindowsDirect2DDeviceContext { Q_DECLARE_PRIVATE(QWindowsDirect2DDeviceContext) + friend class QWindowsDirect2DDeviceContextSuspender; public: QWindowsDirect2DDeviceContext(ID2D1DeviceContext *dc); ~QWindowsDirect2DDeviceContext(); @@ -79,9 +80,23 @@ public: bool end(); private: + void suspend(); + void resume(); + QScopedPointer<QWindowsDirect2DDeviceContextPrivate> d_ptr; }; +class QWindowsDirect2DDeviceContextSuspender { + Q_DISABLE_COPY(QWindowsDirect2DDeviceContextSuspender) + + QWindowsDirect2DDeviceContext *m_dc; +public: + QWindowsDirect2DDeviceContextSuspender(QWindowsDirect2DDeviceContext *dc); + ~QWindowsDirect2DDeviceContextSuspender(); + + void resume(); +}; + QT_END_NAMESPACE #endif // QWINDOWSDIRECT2DDEVICECONTEXT_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index 16cfa773f6..d963cbd463 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -230,6 +230,7 @@ public: } QWindowsDirect2DBitmap *bitmap; + QImage fallbackImage; unsigned int clipFlags; QStack<ClipType> pushedClips; @@ -393,7 +394,10 @@ public: break; default: - qWarning("Unsupported composition mode: %d", mode); + // Activating an unsupported mode at any time will cause the QImage + // fallback to be used for the remainder of the active paint session + dc()->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY); + flags |= QWindowsDirect2DPaintEngine::EmulateComposition; break; } } @@ -968,7 +972,17 @@ bool QWindowsDirect2DPaintEngine::begin(QPaintDevice * pdev) bool QWindowsDirect2DPaintEngine::end() { Q_D(QWindowsDirect2DPaintEngine); - // First pop any user-applied clipping + + // Always clear all emulation-related things so we are in a clean state for our next painting run + const bool emulatingComposition = d->flags.testFlag(EmulateComposition); + d->flags &= ~QWindowsDirect2DPaintEngine::EmulateComposition; + if (!d->fallbackImage.isNull()) { + if (emulatingComposition) + drawImage(d->fallbackImage.rect(), d->fallbackImage, d->fallbackImage.rect()); + d->fallbackImage = QImage(); + } + + // Pop any user-applied clipping d->clearClips(); // Now the system clip from begin() above if (d->clipFlags & SimpleSystemClip) { @@ -977,6 +991,7 @@ bool QWindowsDirect2DPaintEngine::end() } else { d->dc()->PopLayer(); } + return d->bitmap->deviceContext()->end(); } @@ -1406,6 +1421,19 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, return; } + if (d->flags.testFlag(EmulateComposition)) { + const qreal points[] = { + r.x(), r.y(), + r.x() + r.width(), r.y(), + r.x() + r.width(), r.y() + r.height(), + r.x(), r.y() + r.height() + }; + const QVectorPath vp(points, 4, 0, QVectorPath::RectangleHint); + const QBrush brush(sr.isValid() ? pm.copy(sr.toRect()) : pm); + rasterFill(vp, brush); + return; + } + QWindowsDirect2DPlatformPixmap *pp = static_cast<QWindowsDirect2DPlatformPixmap *>(pm.handle()); QWindowsDirect2DBitmap *bitmap = pp->bitmap(); @@ -1589,9 +1617,17 @@ void QWindowsDirect2DPaintEngine::rasterFill(const QVectorPath &path, const QBru { Q_D(QWindowsDirect2DPaintEngine); - QImage img(d->bitmap->size(), QImage::Format_ARGB32); - img.fill(Qt::transparent); + if (d->fallbackImage.isNull()) { + if (d->flags.testFlag(EmulateComposition)) { + QWindowsDirect2DPaintEngineSuspender suspender(this); + d->fallbackImage = d->bitmap->toImage(); + } else { + d->fallbackImage = QImage(d->bitmap->size(), QImage::Format_ARGB32_Premultiplied); + d->fallbackImage.fill(Qt::transparent); + } + } + QImage &img = d->fallbackImage; QPainter p; QPaintEngine *engine = img.paintEngine(); @@ -1638,11 +1674,14 @@ void QWindowsDirect2DPaintEngine::rasterFill(const QVectorPath &path, const QBru 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(); + if (!d->flags.testFlag(EmulateComposition)) { // Emulated fallback will be flattened in end() + d->updateClipEnabled(false); + d->updateTransform(QTransform()); + drawImage(img.rect(), img, img.rect()); + d->fallbackImage = QImage(); + transformChanged(); + clipEnabledChanged(); + } } else { qWarning("%s: Could not fall back to QImage", __FUNCTION__); } @@ -1652,6 +1691,9 @@ bool QWindowsDirect2DPaintEngine::emulationRequired(EmulationType type) const { Q_D(const QWindowsDirect2DPaintEngine); + if (d->flags.testFlag(EmulateComposition)) + return true; + if (!state()->matrix.isAffine()) return true; @@ -1691,4 +1733,71 @@ void QWindowsDirect2DPaintEngine::adjustForAliasing(QPointF *point) (*point) += adjustment; } +void QWindowsDirect2DPaintEngine::suspend() +{ + end(); +} + +void QWindowsDirect2DPaintEngine::resume() +{ + begin(paintDevice()); + clipEnabledChanged(); + penChanged(); + brushChanged(); + brushOriginChanged(); + opacityChanged(); + compositionModeChanged(); + renderHintsChanged(); + transformChanged(); +} + +class QWindowsDirect2DPaintEngineSuspenderImpl +{ + Q_DISABLE_COPY(QWindowsDirect2DPaintEngineSuspenderImpl) + QWindowsDirect2DPaintEngine *m_engine; + bool m_active; +public: + QWindowsDirect2DPaintEngineSuspenderImpl(QWindowsDirect2DPaintEngine *engine) + : m_engine(engine) + , m_active(engine->isActive()) + { + if (m_active) + m_engine->suspend(); + } + + ~QWindowsDirect2DPaintEngineSuspenderImpl() + { + if (m_active) + m_engine->resume(); + } +}; + +class QWindowsDirect2DPaintEngineSuspenderPrivate +{ +public: + QWindowsDirect2DPaintEngineSuspenderPrivate(QWindowsDirect2DPaintEngine *engine) + : engineSuspender(engine) + , dcSuspender(static_cast<QWindowsDirect2DPaintEnginePrivate *>(engine->d_ptr.data())->bitmap->deviceContext()) + { + } + + QWindowsDirect2DPaintEngineSuspenderImpl engineSuspender; + QWindowsDirect2DDeviceContextSuspender dcSuspender; +}; + +QWindowsDirect2DPaintEngineSuspender::QWindowsDirect2DPaintEngineSuspender(QWindowsDirect2DPaintEngine *engine) + : d_ptr(new QWindowsDirect2DPaintEngineSuspenderPrivate(engine)) +{ + +} + +QWindowsDirect2DPaintEngineSuspender::~QWindowsDirect2DPaintEngineSuspender() +{ +} + +void QWindowsDirect2DPaintEngineSuspender::resume() +{ + d_ptr.reset(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h index e723fce148..39cbfdc6cb 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.h @@ -49,11 +49,13 @@ class QWindowsDirect2DBitmap; class QWindowsDirect2DPaintEngine : public QPaintEngineEx { Q_DECLARE_PRIVATE(QWindowsDirect2DPaintEngine) - + friend class QWindowsDirect2DPaintEngineSuspenderImpl; + friend class QWindowsDirect2DPaintEngineSuspenderPrivate; public: enum Flag { NoFlag = 0, - TranslucentTopLevelWindow = 1 + TranslucentTopLevelWindow = 1, + EmulateComposition = 2, }; Q_DECLARE_FLAGS(Flags, Flag) @@ -116,9 +118,24 @@ private: bool antiAliasingEnabled() const; void adjustForAliasing(QRectF *rect); void adjustForAliasing(QPointF *point); + + void suspend(); + void resume(); }; Q_DECLARE_OPERATORS_FOR_FLAGS(QWindowsDirect2DPaintEngine::Flags) +class QWindowsDirect2DPaintEngineSuspenderPrivate; +class QWindowsDirect2DPaintEngineSuspender +{ + Q_DISABLE_COPY(QWindowsDirect2DPaintEngineSuspender) + Q_DECLARE_PRIVATE(QWindowsDirect2DPaintEngineSuspender) + QScopedPointer<QWindowsDirect2DPaintEngineSuspenderPrivate> d_ptr; +public: + QWindowsDirect2DPaintEngineSuspender(QWindowsDirect2DPaintEngine *engine); + ~QWindowsDirect2DPaintEngineSuspender(); + void resume(); +}; + QT_END_NAMESPACE #endif // QWINDOWSDIRECT2DPAINTENGINE_H diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp index ac0676a2b0..d3dad1cbb9 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.cpp @@ -161,17 +161,8 @@ QImage QWindowsDirect2DPlatformPixmap::toImage(const QRect &rect) const { Q_D(const QWindowsDirect2DPlatformPixmap); - bool active = d->device->paintEngine()->isActive(); - - if (active) - d->device->paintEngine()->end(); - - QImage result = d->bitmap->toImage(rect); - - if (active) - d->device->paintEngine()->begin(d->device.data()); - - return result; + QWindowsDirect2DPaintEngineSuspender suspender(static_cast<QWindowsDirect2DPaintEngine *>(d->device->paintEngine())); + return d->bitmap->toImage(rect); } QPaintEngine* QWindowsDirect2DPlatformPixmap::paintEngine() const |