qpa: extend drawPixmap capabilities
authorJulien Brianceau <jbrianceau@nds.com>
Tue, 11 Sep 2012 15:20:30 +0000 (17:20 +0200)
committerQt by Nokia <qt-info@nokia.com>
Wed, 12 Sep 2012 08:25:19 +0000 (10:25 +0200)
Extend drawPixmap capabilities for qpa through new ExtendedPixmapCapability
QBlittable flag and add related implementation in DirectFB platform.

Change-Id: If5436e16bfb37bf081bf864cad73a5e97394df8c
Reviewed-by: Qt Doc Bot <qt_docbot@qt-project.org>
Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com>
src/gui/painting/qblittable_p.h
src/gui/painting/qpaintengine_blitter.cpp
src/plugins/platforms/directfb/qdirectfbblitter.cpp
src/plugins/platforms/directfb/qdirectfbblitter.h

index 654a0a0..1f404a3 100644 (file)
@@ -63,6 +63,7 @@ public:
         SourceOverPixmapCapability      = 0x0004,
         SourceOverScaledPixmapCapability = 0x0008,
         AlphaFillRectCapability         = 0x0010,
+        OpacityPixmapCapability         = 0x0020,
 
         // Internal ones
         OutlineCapability               = 0x0001000
@@ -83,6 +84,14 @@ public:
         Q_UNUSED(cmode);
         qWarning("Please implement alphaFillRect function in your platform or remove AlphaFillRectCapability from it");
     }
+    virtual void drawPixmapOpacity(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect, QPainter::CompositionMode cmode, qreal opacity) {
+        Q_UNUSED(rect);
+        Q_UNUSED(pixmap);
+        Q_UNUSED(subrect);
+        Q_UNUSED(cmode);
+        Q_UNUSED(opacity);
+        qWarning("Please implement drawPixmapOpacity function in your platform or remove OpacityPixmapCapability from it");
+    }
 
     QImage *lock();
     void unlock();
index 20dd98b..f8ebaf7 100644 (file)
@@ -74,6 +74,7 @@ public:
         , drawRectMask(0)
         , drawPixmapMask(0)
         , alphaFillRectMask(0)
+        , opacityPixmapMask(0)
         , capabillitiesState(0)
     {
         if (capabilities & QBlittable::SolidRectCapability)
@@ -86,6 +87,8 @@ public:
             setSourceOverScaledPixmapMask();
         if (capabilities & QBlittable::AlphaFillRectCapability)
             setAlphaFillRectMask();
+        if (capabilities & QBlittable::OpacityPixmapCapability)
+            setOpacityPixmapMask();
     }
 
     inline bool canBlitterFillRect() const
@@ -121,6 +124,14 @@ public:
         return false;
     }
 
+    bool canBlitterDrawPixmapOpacity(const QPixmap &pm) const
+    {
+        if (pm.handle()->classId() != QPlatformPixmap::BlitterClass)
+            return false;
+
+        return checkStateAgainstMask(capabillitiesState, opacityPixmapMask);
+    }
+
     inline void updateState(uint mask, bool on) {
         updateStateBits(&capabillitiesState, mask, on);
     }
@@ -199,11 +210,29 @@ private:
         updateStateBits(&drawRectMask, STATE_XFORM_SCALE, true);
     }
 
+    void setOpacityPixmapMask() {
+        updateStateBits(&opacityPixmapMask, STATE_XFORM_SCALE, true);
+        updateStateBits(&opacityPixmapMask, STATE_XFORM_COMPLEX, false);
+
+        updateStateBits(&opacityPixmapMask, STATE_BRUSH_PATTERN, true);
+        updateStateBits(&opacityPixmapMask, STATE_BRUSH_ALPHA, true);
+
+        updateStateBits(&opacityPixmapMask, STATE_PEN_ENABLED, true);
+
+        updateStateBits(&opacityPixmapMask, STATE_ANTIALIASING, true);
+        updateStateBits(&opacityPixmapMask, STATE_ALPHA, true);
+        updateStateBits(&opacityPixmapMask, STATE_BLENDING_COMPLEX, false);
+
+        updateStateBits(&opacityPixmapMask, STATE_CLIPSYS_COMPLEX, false);
+        updateStateBits(&opacityPixmapMask, STATE_CLIP_COMPLEX, false);
+    }
+
     QBlittable::Capabilities m_capabilities;
     uint fillRectMask;
     uint drawRectMask;
     uint drawPixmapMask;
     uint alphaFillRectMask;
+    uint opacityPixmapMask;
     uint capabillitiesState;
 };
 
@@ -222,7 +251,7 @@ public:
     void lock();
     void unlock();
     void fillRect(const QRectF &rect, const QColor &color, bool alpha);
-    void clipAndDrawPixmap(const QRectF &clip, const QRectF &target, const QPixmap &pm, const QRectF &sr);
+    void clipAndDrawPixmap(const QRectF &clip, const QRectF &target, const QPixmap &pm, const QRectF &sr, bool opacity);
 
 
     void updateCompleteState(QPainterState *s);
@@ -365,8 +394,10 @@ void QBlitterPaintEnginePrivate::fillRect(const QRectF &rect, const QColor &colo
 void QBlitterPaintEnginePrivate::clipAndDrawPixmap(const QRectF &clip,
                                                    const QRectF &target,
                                                    const QPixmap &pm,
-                                                   const QRectF &sr)
+                                                   const QRectF &sr,
+                                                   bool  opacity)
 {
+    Q_Q(QBlitterPaintEngine);
     QRectF intersectedRect = clip.intersected(target);
     if (intersectedRect.isEmpty())
         return;
@@ -391,7 +422,10 @@ void QBlitterPaintEnginePrivate::clipAndDrawPixmap(const QRectF &clip,
         }
     }
     pmData->unmarkRasterOverlay(intersectedRect);
-    pmData->blittable()->drawPixmap(intersectedRect, pm, source);
+    if (opacity)
+        pmData->blittable()->drawPixmapOpacity(intersectedRect, pm, source, q->state()->compositionMode(), q->state()->opacity);
+    else
+        pmData->blittable()->drawPixmap(intersectedRect, pm, source);
 }
 
 QBlitterPaintEngine::QBlitterPaintEngine(QBlittablePlatformPixmap *p)
@@ -524,8 +558,9 @@ void QBlitterPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
         && qbrush_color(brush).alpha() == 0xff
         && d->caps.canBlitterFillRect()) {
         d->fillRect(rect, qbrush_color(brush), false);
-    } else if (brush.style() == Qt::TexturePattern
-              && d->caps.canBlitterDrawPixmap(rect, brush.texture(), rect)) {
+    } else if (brush.style() == Qt::TexturePattern &&
+                ((d->caps.canBlitterDrawPixmapOpacity(brush.texture())) ||
+                 (d->caps.canBlitterDrawPixmap(rect, brush.texture(), rect)))) {
         bool rectIsFilled = false;
         QRectF transformedRect = state()->matrix.mapRect(rect);
         qreal x = transformedRect.x();
@@ -621,7 +656,10 @@ void QBlitterPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm)
 void QBlitterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
 {
     Q_D(QBlitterPaintEngine);
-    if (d->caps.canBlitterDrawPixmap(r, pm, sr)) {
+    bool canDrawOpacity;
+
+    canDrawOpacity = d->caps.canBlitterDrawPixmapOpacity(pm);
+    if (canDrawOpacity || (d->caps.canBlitterDrawPixmap(r, pm, sr))) {
 
         d->unlock();
         QRectF targetRect = r;
@@ -630,15 +668,15 @@ void QBlitterPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const Q
         const QClipData *clipData = d->clip();
         if (clipData) {
             if (clipData->hasRectClip) {
-                d->clipAndDrawPixmap(clipData->clipRect, targetRect, pm, sr);
+                d->clipAndDrawPixmap(clipData->clipRect, targetRect, pm, sr, canDrawOpacity);
             } else if (clipData->hasRegionClip) {
                 QVector<QRect>rects = clipData->clipRegion.rects();
                 for (int i = 0; i<rects.size(); ++i)
-                    d->clipAndDrawPixmap(rects.at(i), targetRect, pm, sr);
+                    d->clipAndDrawPixmap(rects.at(i), targetRect, pm, sr, canDrawOpacity);
             }
         } else {
             QRectF deviceRect(0, 0, paintDevice()->width(), paintDevice()->height());
-            d->clipAndDrawPixmap(deviceRect, targetRect, pm, sr);
+            d->clipAndDrawPixmap(deviceRect, targetRect, pm, sr, canDrawOpacity);
         }
     }else {
         d->lock();
index 889f1cc..deca258 100644 (file)
@@ -57,7 +57,8 @@ static QBlittable::Capabilities dfb_blitter_capabilities()
                                     |QBlittable::SourcePixmapCapability
                                     |QBlittable::SourceOverPixmapCapability
                                     |QBlittable::SourceOverScaledPixmapCapability
-                                    |QBlittable::AlphaFillRectCapability);
+                                    |QBlittable::AlphaFillRectCapability
+                                    |QBlittable::OpacityPixmapCapability);
 }
 
 QDirectFbBlitter::QDirectFbBlitter(const QSize &rect, IDirectFBSurface *surface)
@@ -79,7 +80,7 @@ QDirectFbBlitter::QDirectFbBlitter(const QSize &rect, bool alpha)
     surfaceDesc.width = rect.width();
     surfaceDesc.height = rect.height();
 
-    // force alpha format for AlphaFillRectCapability support
+    // force alpha format to get AlphaFillRectCapability and ExtendedPixmapCapability support
     alpha = true;
 
     if (alpha) {
@@ -124,37 +125,7 @@ void QDirectFbBlitter::fillRect(const QRectF &rect, const QColor &color)
 
 void QDirectFbBlitter::drawPixmap(const QRectF &rect, const QPixmap &pixmap, const QRectF &srcRect)
 {
-    QPlatformPixmap *data = pixmap.handle();
-    Q_ASSERT(data->width() && data->height());
-    Q_ASSERT(data->classId() == QPlatformPixmap::BlitterClass);
-    QBlittablePlatformPixmap *blitPm = static_cast<QBlittablePlatformPixmap*>(data);
-    QDirectFbBlitter *dfbBlitter = static_cast<QDirectFbBlitter *>(blitPm->blittable());
-    dfbBlitter->unlock();
-
-    IDirectFBSurface *s = dfbBlitter->m_surface.data();
-
-    DFBSurfaceBlittingFlags blittingFlags = DSBLIT_NOFX;
-    DFBSurfacePorterDuffRule porterDuff = DSPD_SRC;
-    if (pixmap.hasAlpha()) {
-        blittingFlags = DSBLIT_BLEND_ALPHACHANNEL;
-        porterDuff = DSPD_SRC_OVER;
-    }
-
-    m_surface->SetBlittingFlags(m_surface.data(), DFBSurfaceBlittingFlags(blittingFlags));
-    m_surface->SetPorterDuff(m_surface.data(), porterDuff);
-    m_surface->SetDstBlendFunction(m_surface.data(), DSBF_INVSRCALPHA);
-
-    const DFBRectangle sRect = { int(srcRect.x()), int(srcRect.y()), int(srcRect.width()), int(srcRect.height()) };
-
-    DFBResult result;
-    if (rect.width() == srcRect.width() && rect.height() == srcRect.height())
-        result = m_surface->Blit(m_surface.data(), s, &sRect, rect.x(), rect.y());
-    else {
-        const DFBRectangle dRect = { int(rect.x()), int(rect.y()), int(rect.width()), int(rect.height()) };
-        result = m_surface->StretchBlit(m_surface.data(), s, &sRect, &dRect);
-    }
-    if (result != DFB_OK)
-        DirectFBError("QDirectFBBlitter::drawPixmap()", result);
+    drawPixmapOpacity(rect, pixmap, srcRect, QPainter::CompositionMode_SourceOver, 1.0);
 }
 
 void QDirectFbBlitter::alphaFillRect(const QRectF &rect, const QColor &color, QPainter::CompositionMode cmode)
@@ -194,6 +165,49 @@ void QDirectFbBlitter::alphaFillRect(const QRectF &rect, const QColor &color, QP
         DirectFBError("QDirectFBBlitter::alphaFillRect()", result);
 }
 
+void QDirectFbBlitter::drawPixmapOpacity(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect, QPainter::CompositionMode cmode, qreal opacity)
+{
+    QRect sQRect = subrect.toRect();
+    QRect dQRect = rect.toRect();
+    DFBRectangle sRect = { sQRect.x(), sQRect.y(), sQRect.width(), sQRect.height() };
+    DFBRectangle dRect = { dQRect.x(), dQRect.y(), dQRect.width(), dQRect.height() };
+    DFBResult result;
+
+    // skip if dst too small
+    if ((dRect.w <= 0) || (dRect.h <= 0)) return;
+
+    // correct roundings if needed
+    if (sRect.w <= 0) sRect.w = 1;
+    if (sRect.h <= 0) sRect.h = 1;
+
+    QDirectFbBlitterPlatformPixmap *blitPm = static_cast<QDirectFbBlitterPlatformPixmap *>(pixmap.handle());
+    QDirectFbBlitter *dfbBlitter = static_cast<QDirectFbBlitter *>(blitPm->blittable());
+    dfbBlitter->unlock();
+
+    IDirectFBSurface *s = dfbBlitter->m_surface.data();
+
+    DFBSurfaceBlittingFlags blittingFlags = DFBSurfaceBlittingFlags(DSBLIT_BLEND_ALPHACHANNEL);
+    DFBSurfacePorterDuffRule porterDuff = (cmode == QPainter::CompositionMode_SourceOver) ? DSPD_SRC_OVER : DSPD_SRC;
+
+    if (opacity != 1.0)
+    {
+        blittingFlags = DFBSurfaceBlittingFlags(blittingFlags | DSBLIT_BLEND_COLORALPHA | (m_premult ? DSBLIT_SRC_PREMULTCOLOR : 0));
+        m_surface->SetColor(m_surface.data(), 0xff, 0xff, 0xff, (u8) (opacity * 255.0));
+    }
+
+    m_surface->SetBlittingFlags(m_surface.data(), DFBSurfaceBlittingFlags(blittingFlags));
+    m_surface->SetPorterDuff(m_surface.data(), porterDuff);
+    m_surface->SetDstBlendFunction(m_surface.data(), DSBF_INVSRCALPHA);
+
+    if ((sRect.w == dRect.w) && (sRect.h == dRect.h))
+        result = m_surface->Blit(m_surface.data(), s, &sRect, dRect.x, dRect.y);
+    else
+        result = m_surface->StretchBlit(m_surface.data(), s, &sRect, &dRect);
+
+    if (result != DFB_OK)
+        DirectFBError("QDirectFBBlitter::drawPixmapExtended()", result);
+}
+
 QImage *QDirectFbBlitter::doLock()
 {
     Q_ASSERT(m_surface);
index 6da5fcb..950ffe7 100644 (file)
@@ -60,6 +60,7 @@ public:
     virtual void fillRect(const QRectF &rect, const QColor &color);
     virtual void drawPixmap(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect);
     void alphaFillRect(const QRectF &rect, const QColor &color, QPainter::CompositionMode cmode);
+    void drawPixmapOpacity(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect, QPainter::CompositionMode cmode, qreal opacity);
 
     IDirectFBSurface *dfbSurface() const;