src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the plugins of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qdirectfbpaintengine.h"
       
    43 
       
    44 #ifndef QT_NO_QWS_DIRECTFB
       
    45 
       
    46 #include "qdirectfbwindowsurface.h"
       
    47 #include "qdirectfbscreen.h"
       
    48 #include "qdirectfbpixmap.h"
       
    49 #include <directfb.h>
       
    50 #include <qtransform.h>
       
    51 #include <qvarlengtharray.h>
       
    52 #include <qcache.h>
       
    53 #include <qmath.h>
       
    54 #include <private/qpixmapdata_p.h>
       
    55 #include <private/qpixmap_raster_p.h>
       
    56 #include <private/qimagepixmapcleanuphooks_p.h>
       
    57 
       
    58 QT_BEGIN_NAMESPACE
       
    59 
       
    60 class SurfaceCache;
       
    61 class QDirectFBPaintEnginePrivate : public QRasterPaintEnginePrivate
       
    62 {
       
    63 public:
       
    64     enum TransformationTypeFlags {
       
    65         Matrix_NegativeScale = 0x100,
       
    66         Matrix_RectsUnsupported = (QTransform::TxRotate|QTransform::TxShear|QTransform::TxProject),
       
    67         Matrix_BlitsUnsupported = (Matrix_NegativeScale|Matrix_RectsUnsupported)
       
    68     };
       
    69 
       
    70     enum CompositionModeStatus {
       
    71         PorterDuff_None = 0x0,
       
    72         PorterDuff_SupportedBlits = 0x1,
       
    73         PorterDuff_SupportedPrimitives = 0x2
       
    74     };
       
    75 
       
    76     enum ClipType {
       
    77         ClipUnset,
       
    78         NoClip,
       
    79         RectClip,
       
    80         RegionClip,
       
    81         ComplexClip
       
    82     };
       
    83 
       
    84     QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p);
       
    85     ~QDirectFBPaintEnginePrivate();
       
    86 
       
    87     inline void setTransform(const QTransform &transforma);
       
    88     inline void setPen(const QPen &pen);
       
    89     inline void setCompositionMode(QPainter::CompositionMode mode);
       
    90     inline void setRenderHints(QPainter::RenderHints hints);
       
    91 
       
    92     inline void setDFBColor(const QColor &color);
       
    93 
       
    94     inline void lock();
       
    95     inline void unlock();
       
    96     static inline void unlock(QDirectFBPaintDevice *device);
       
    97 
       
    98     inline bool isSimpleBrush(const QBrush &brush) const;
       
    99 
       
   100     void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos);
       
   101     void blit(const QRectF &dest, IDirectFBSurface *surface, const QRectF &src);
       
   102 
       
   103     inline void updateClip();
       
   104     virtual void systemStateChanged();
       
   105 
       
   106     static IDirectFBSurface *getSurface(const QImage &img, bool *release);
       
   107 
       
   108 #ifdef QT_DIRECTFB_IMAGECACHE
       
   109     static inline int cacheCost(const QImage &img) { return img.width() * img.height() * img.depth() / 8; }
       
   110 #endif
       
   111 
       
   112     void prepareForBlit(bool alpha);
       
   113 
       
   114     IDirectFBSurface *surface;
       
   115 
       
   116     bool antialiased;
       
   117     bool simplePen;
       
   118 
       
   119     uint transformationType; // this is QTransform::type() + Matrix_NegativeScale if qMin(transform.m11(), transform.m22()) < 0
       
   120 
       
   121     SurfaceCache *surfaceCache;
       
   122     IDirectFB *fb;
       
   123     quint8 opacity;
       
   124 
       
   125     ClipType clipType;
       
   126     QDirectFBPaintDevice *dfbDevice;
       
   127     uint compositionModeStatus;
       
   128 
       
   129     bool inClip;
       
   130     QRect currentClip;
       
   131 
       
   132     QDirectFBPaintEngine *q;
       
   133 };
       
   134 
       
   135 class SurfaceCache
       
   136 {
       
   137 public:
       
   138     SurfaceCache() : surface(0), buffer(0), bufsize(0) {}
       
   139     ~SurfaceCache() { clear(); }
       
   140     IDirectFBSurface *getSurface(const uint *buf, int size);
       
   141     void clear();
       
   142 private:
       
   143     IDirectFBSurface *surface;
       
   144     uint *buffer;
       
   145     int bufsize;
       
   146 };
       
   147 
       
   148 
       
   149 #ifdef QT_DIRECTFB_IMAGECACHE
       
   150 QT_BEGIN_INCLUDE_NAMESPACE
       
   151 #include <private/qimage_p.h>
       
   152 QT_END_INCLUDE_NAMESPACE
       
   153 struct CachedImage
       
   154 {
       
   155     IDirectFBSurface *surface;
       
   156     ~CachedImage()
       
   157     {
       
   158         if (surface && QDirectFBScreen::instance()) {
       
   159             QDirectFBScreen::instance()->releaseDFBSurface(surface);
       
   160         }
       
   161     }
       
   162 };
       
   163 static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB
       
   164 #endif
       
   165 
       
   166 #if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS || defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS
       
   167 #define VOID_ARG() static_cast<bool>(false)
       
   168 enum PaintOperation {
       
   169     DRAW_RECTS = 0x0001, DRAW_LINES = 0x0002, DRAW_IMAGE = 0x0004,
       
   170     DRAW_PIXMAP = 0x0008, DRAW_TILED_PIXMAP = 0x0010, STROKE_PATH = 0x0020,
       
   171     DRAW_PATH = 0x0040, DRAW_POINTS = 0x0080, DRAW_ELLIPSE = 0x0100,
       
   172     DRAW_POLYGON = 0x0200, DRAW_TEXT = 0x0400, FILL_PATH = 0x0800,
       
   173     FILL_RECT = 0x1000, DRAW_COLORSPANS = 0x2000, DRAW_ROUNDED_RECT = 0x4000,
       
   174     ALL = 0xffff
       
   175 };
       
   176 #endif
       
   177 
       
   178 #ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS
       
   179 template <typename device, typename T1, typename T2, typename T3>
       
   180 static void rasterFallbackWarn(const char *msg, const char *func, const device *dev,
       
   181                                uint transformationType, bool simplePen,
       
   182                                uint clipType, uint compositionModeStatus,
       
   183                                const char *nameOne, const T1 &one,
       
   184                                const char *nameTwo, const T2 &two,
       
   185                                const char *nameThree, const T3 &three);
       
   186 #endif
       
   187 
       
   188 #if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS && defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS
       
   189 #define RASTERFALLBACK(op, one, two, three)                             \
       
   190     if (op & (QT_DIRECTFB_WARN_ON_RASTERFALLBACKS))                     \
       
   191         rasterFallbackWarn("Disabled raster engine operation",          \
       
   192                            __FUNCTION__, state()->painter->device(),    \
       
   193                            d_func()->transformationType,                \
       
   194                            d_func()->simplePen,                         \
       
   195                            d_func()->clipType,                          \
       
   196                            d_func()->compositionModeStatus,             \
       
   197                            #one, one, #two, two, #three, three);        \
       
   198     if (op & (QT_DIRECTFB_DISABLE_RASTERFALLBACKS))                     \
       
   199         return;
       
   200 #elif defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS
       
   201 #define RASTERFALLBACK(op, one, two, three)             \
       
   202     if (op & (QT_DIRECTFB_DISABLE_RASTERFALLBACKS))     \
       
   203         return;
       
   204 #elif defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS
       
   205 #define RASTERFALLBACK(op, one, two, three)                             \
       
   206     if (op & (QT_DIRECTFB_WARN_ON_RASTERFALLBACKS))                     \
       
   207         rasterFallbackWarn("Falling back to raster engine for",         \
       
   208                            __FUNCTION__, state()->painter->device(),    \
       
   209                            d_func()->transformationType,                \
       
   210                            d_func()->simplePen,                         \
       
   211                            d_func()->clipType,                          \
       
   212                            d_func()->compositionModeStatus,             \
       
   213                            #one, one, #two, two, #three, three);
       
   214 #else
       
   215 #define RASTERFALLBACK(op, one, two, three)
       
   216 #endif
       
   217 
       
   218 template <class T>
       
   219 static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface);
       
   220 template <class T>
       
   221 static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface);
       
   222 template <class T>
       
   223 static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface);
       
   224 
       
   225 #define CLIPPED_PAINT(operation) {                                      \
       
   226         d->unlock();                                                    \
       
   227         DFBRegion clipRegion;                                           \
       
   228         switch (d->clipType) {                                          \
       
   229         case QDirectFBPaintEnginePrivate::NoClip:                       \
       
   230         case QDirectFBPaintEnginePrivate::RectClip:                     \
       
   231             operation;                                                  \
       
   232             break;                                                      \
       
   233         case QDirectFBPaintEnginePrivate::RegionClip: {                 \
       
   234             Q_ASSERT(d->clip());                                        \
       
   235             const QVector<QRect> cr = d->clip()->clipRegion.rects();    \
       
   236             const int size = cr.size();                                 \
       
   237             for (int i=0; i<size; ++i) {                                \
       
   238                 d->currentClip = cr.at(i);                              \
       
   239                 clipRegion.x1 = d->currentClip.x();                     \
       
   240                 clipRegion.y1 = d->currentClip.y();                     \
       
   241                 clipRegion.x2 = d->currentClip.right();                 \
       
   242                 clipRegion.y2 = d->currentClip.bottom();                \
       
   243                 d->surface->SetClip(d->surface, &clipRegion);           \
       
   244                 operation;                                              \
       
   245             }                                                           \
       
   246             d->updateClip();                                            \
       
   247             break; }                                                    \
       
   248         case QDirectFBPaintEnginePrivate::ComplexClip:                  \
       
   249         case QDirectFBPaintEnginePrivate::ClipUnset:                    \
       
   250             qFatal("CLIPPED_PAINT internal error %d", d->clipType);     \
       
   251             break;                                                      \
       
   252         }                                                               \
       
   253     }
       
   254 
       
   255 
       
   256 QDirectFBPaintEngine::QDirectFBPaintEngine(QPaintDevice *device)
       
   257     : QRasterPaintEngine(*(new QDirectFBPaintEnginePrivate(this)), device)
       
   258 {
       
   259 }
       
   260 
       
   261 QDirectFBPaintEngine::~QDirectFBPaintEngine()
       
   262 {
       
   263 }
       
   264 
       
   265 bool QDirectFBPaintEngine::begin(QPaintDevice *device)
       
   266 {
       
   267     Q_D(QDirectFBPaintEngine);
       
   268     if (device->devType() == QInternal::CustomRaster) {
       
   269         d->dfbDevice = static_cast<QDirectFBPaintDevice*>(device);
       
   270     } else if (device->devType() == QInternal::Pixmap) {
       
   271         QPixmapData *data = static_cast<QPixmap*>(device)->pixmapData();
       
   272         Q_ASSERT(data->classId() == QPixmapData::DirectFBClass);
       
   273         QDirectFBPixmapData *dfbPixmapData = static_cast<QDirectFBPixmapData*>(data);
       
   274         QDirectFBPaintEnginePrivate::unlock(dfbPixmapData);
       
   275         d->dfbDevice = static_cast<QDirectFBPaintDevice*>(dfbPixmapData);
       
   276     }
       
   277 
       
   278     if (d->dfbDevice)
       
   279         d->surface = d->dfbDevice->directFBSurface();
       
   280 
       
   281     if (!d->surface) {
       
   282         qFatal("QDirectFBPaintEngine used on an invalid device: 0x%x",
       
   283                device->devType());
       
   284     }
       
   285 
       
   286     d->prepare(d->dfbDevice);
       
   287     gccaps = AllFeatures;
       
   288     d->setCompositionMode(state()->composition_mode);
       
   289 
       
   290     return QRasterPaintEngine::begin(device);
       
   291 }
       
   292 
       
   293 bool QDirectFBPaintEngine::end()
       
   294 {
       
   295     Q_D(QDirectFBPaintEngine);
       
   296     d->unlock();
       
   297     d->dfbDevice = 0;
       
   298 #if (Q_DIRECTFB_VERSION >= 0x010000)
       
   299     d->surface->ReleaseSource(d->surface);
       
   300 #endif
       
   301     d->currentClip = QRect();
       
   302     d->surface->SetClip(d->surface, NULL);
       
   303     d->surface = 0;
       
   304     return QRasterPaintEngine::end();
       
   305 }
       
   306 
       
   307 void QDirectFBPaintEngine::clipEnabledChanged()
       
   308 {
       
   309     Q_D(QDirectFBPaintEngine);
       
   310     QRasterPaintEngine::clipEnabledChanged();
       
   311     d->updateClip();
       
   312 }
       
   313 
       
   314 void QDirectFBPaintEngine::penChanged()
       
   315 {
       
   316     Q_D(QDirectFBPaintEngine);
       
   317     d->setPen(state()->pen);
       
   318 
       
   319     QRasterPaintEngine::penChanged();
       
   320 }
       
   321 
       
   322 void QDirectFBPaintEngine::opacityChanged()
       
   323 {
       
   324     Q_D(QDirectFBPaintEngine);
       
   325     d->opacity = quint8(state()->opacity * 255);
       
   326     QRasterPaintEngine::opacityChanged();
       
   327 }
       
   328 
       
   329 void QDirectFBPaintEngine::compositionModeChanged()
       
   330 {
       
   331     Q_D(QDirectFBPaintEngine);
       
   332     d->setCompositionMode(state()->compositionMode());
       
   333     QRasterPaintEngine::compositionModeChanged();
       
   334 }
       
   335 
       
   336 void QDirectFBPaintEngine::renderHintsChanged()
       
   337 {
       
   338     Q_D(QDirectFBPaintEngine);
       
   339     d->setRenderHints(state()->renderHints);
       
   340     QRasterPaintEngine::renderHintsChanged();
       
   341 }
       
   342 
       
   343 void QDirectFBPaintEngine::transformChanged()
       
   344 {
       
   345     Q_D(QDirectFBPaintEngine);
       
   346     d->setTransform(state()->matrix);
       
   347     QRasterPaintEngine::transformChanged();
       
   348 }
       
   349 
       
   350 void QDirectFBPaintEngine::setState(QPainterState *state)
       
   351 {
       
   352     Q_D(QDirectFBPaintEngine);
       
   353     QRasterPaintEngine::setState(state);
       
   354     d->setPen(state->pen);
       
   355     d->opacity = quint8(state->opacity * 255);
       
   356     d->setCompositionMode(state->compositionMode());
       
   357     d->setTransform(state->transform());
       
   358     d->setRenderHints(state->renderHints);
       
   359     if (d->surface)
       
   360         d->updateClip();
       
   361 }
       
   362 
       
   363 void QDirectFBPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
       
   364 {
       
   365     Q_D(QDirectFBPaintEngine);
       
   366     const bool wasInClip = d->inClip;
       
   367     d->inClip = true;
       
   368     QRasterPaintEngine::clip(path, op);
       
   369     if (!wasInClip) {
       
   370         d->inClip = false;
       
   371         d->updateClip();
       
   372     }
       
   373 }
       
   374 
       
   375 void QDirectFBPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
       
   376 {
       
   377     Q_D(QDirectFBPaintEngine);
       
   378     const bool wasInClip = d->inClip;
       
   379     d->inClip = true;
       
   380     QRasterPaintEngine::clip(region, op);
       
   381     if (!wasInClip) {
       
   382         d->inClip = false;
       
   383         d->updateClip();
       
   384     }
       
   385 }
       
   386 
       
   387 void QDirectFBPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
       
   388 {
       
   389     Q_D(QDirectFBPaintEngine);
       
   390     const bool wasInClip = d->inClip;
       
   391     d->inClip = true;
       
   392     QRasterPaintEngine::clip(rect, op);
       
   393     if (!wasInClip) {
       
   394         d->inClip = false;
       
   395         d->updateClip();
       
   396     }
       
   397 }
       
   398 
       
   399 void QDirectFBPaintEngine::drawRects(const QRect *rects, int rectCount)
       
   400 {
       
   401     Q_D(QDirectFBPaintEngine);
       
   402     const QPen &pen = state()->pen;
       
   403     const QBrush &brush = state()->brush;
       
   404     if (brush.style() == Qt::NoBrush && pen.style() == Qt::NoPen)
       
   405         return;
       
   406 
       
   407     if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)
       
   408         || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)
       
   409         || !d->simplePen
       
   410         || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
       
   411         || !d->isSimpleBrush(brush)) {
       
   412         RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG());
       
   413         d->lock();
       
   414         QRasterPaintEngine::drawRects(rects, rectCount);
       
   415         return;
       
   416     }
       
   417 
       
   418     if (brush.style() != Qt::NoBrush) {
       
   419         d->setDFBColor(brush.color());
       
   420         CLIPPED_PAINT(QT_PREPEND_NAMESPACE(fillRects<QRect>)(rects, rectCount, state()->matrix, d->surface));
       
   421     }
       
   422 
       
   423     if (pen.style() != Qt::NoPen) {
       
   424         d->setDFBColor(pen.color());
       
   425         CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawRects<QRect>)(rects, rectCount, state()->matrix, d->surface));
       
   426     }
       
   427 }
       
   428 
       
   429 void QDirectFBPaintEngine::drawRects(const QRectF *rects, int rectCount)
       
   430 {
       
   431     Q_D(QDirectFBPaintEngine);
       
   432     const QPen &pen = state()->pen;
       
   433     const QBrush &brush = state()->brush;
       
   434     if (brush.style() == Qt::NoBrush && pen.style() == Qt::NoPen)
       
   435         return;
       
   436 
       
   437     if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)
       
   438         || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)
       
   439         || !d->simplePen
       
   440         || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
       
   441         || !d->isSimpleBrush(brush)) {
       
   442         RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG());
       
   443         d->lock();
       
   444         QRasterPaintEngine::drawRects(rects, rectCount);
       
   445         return;
       
   446     }
       
   447 
       
   448     if (brush.style() != Qt::NoBrush) {
       
   449         d->setDFBColor(brush.color());
       
   450         CLIPPED_PAINT(fillRects<QRectF>(rects, rectCount, state()->matrix, d->surface));
       
   451     }
       
   452 
       
   453     if (pen.style() != Qt::NoPen) {
       
   454         d->setDFBColor(pen.color());
       
   455         CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawRects<QRectF>)(rects, rectCount, state()->matrix, d->surface));
       
   456     }
       
   457 }
       
   458 
       
   459 void QDirectFBPaintEngine::drawLines(const QLine *lines, int lineCount)
       
   460 {
       
   461     Q_D(QDirectFBPaintEngine);
       
   462 
       
   463     if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)
       
   464         || !d->simplePen
       
   465         || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) {
       
   466         RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG());
       
   467         d->lock();
       
   468         QRasterPaintEngine::drawLines(lines, lineCount);
       
   469         return;
       
   470     }
       
   471 
       
   472     const QPen &pen = state()->pen;
       
   473     if (pen.style() != Qt::NoPen) {
       
   474         d->setDFBColor(pen.color());
       
   475         CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawLines<QLine>)(lines, lineCount, state()->matrix, d->surface));
       
   476     }
       
   477 }
       
   478 
       
   479 void QDirectFBPaintEngine::drawLines(const QLineF *lines, int lineCount)
       
   480 {
       
   481     Q_D(QDirectFBPaintEngine);
       
   482 
       
   483     if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)
       
   484         || !d->simplePen
       
   485         || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) {
       
   486         RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG());
       
   487         d->lock();
       
   488         QRasterPaintEngine::drawLines(lines, lineCount);
       
   489         return;
       
   490     }
       
   491 
       
   492     const QPen &pen = state()->pen;
       
   493     if (pen.style() != Qt::NoPen) {
       
   494         d->setDFBColor(pen.color());
       
   495         CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawLines<QLineF>)(lines, lineCount, state()->matrix, d->surface));
       
   496     }
       
   497 }
       
   498 
       
   499 void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image,
       
   500                                      const QRectF &sr,
       
   501                                      Qt::ImageConversionFlags flags)
       
   502 {
       
   503     Q_D(QDirectFBPaintEngine);
       
   504     Q_UNUSED(flags);
       
   505 
       
   506     /*  This is hard to read. The way it works is like this:
       
   507 
       
   508     - If you do not have support for preallocated surfaces and do not use an
       
   509     image cache we always fall back to raster engine.
       
   510 
       
   511     - If it's rotated/sheared/mirrored (negative scale) or we can't
       
   512     clip it we fall back to raster engine.
       
   513 
       
   514     - If we don't cache the image, but we do have support for
       
   515     preallocated surfaces we fall back to the raster engine if the
       
   516     image is in a format DirectFB can't handle.
       
   517 
       
   518     - If we do cache the image but don't have support for preallocated
       
   519     images and the cost of caching the image (bytes used) is higher
       
   520     than the max image cache size we fall back to raster engine.
       
   521     */
       
   522 
       
   523 #if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE
       
   524     if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedBlits)
       
   525         || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
       
   526         || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
       
   527 #ifndef QT_DIRECTFB_IMAGECACHE
       
   528         || QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN
       
   529 #elif defined QT_NO_DIRECTFB_PREALLOCATED
       
   530         || QDirectFBPaintEnginePrivate::cacheCost(image) > imageCache.maxCost()
       
   531 #endif
       
   532         )
       
   533 #endif
       
   534     {
       
   535         RASTERFALLBACK(DRAW_IMAGE, r, image.size(), sr);
       
   536         d->lock();
       
   537         QRasterPaintEngine::drawImage(r, image, sr, flags);
       
   538         return;
       
   539     }
       
   540 #if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE
       
   541     bool release;
       
   542     IDirectFBSurface *imgSurface = d->getSurface(image, &release);
       
   543     d->prepareForBlit(QDirectFBScreen::hasAlphaChannel(imgSurface));
       
   544     CLIPPED_PAINT(d->blit(r, imgSurface, sr));
       
   545     if (release) {
       
   546 #if (Q_DIRECTFB_VERSION >= 0x010000)
       
   547         d->surface->ReleaseSource(d->surface);
       
   548 #endif
       
   549         imgSurface->Release(imgSurface);
       
   550     }
       
   551 #endif
       
   552 }
       
   553 
       
   554 void QDirectFBPaintEngine::drawImage(const QPointF &p, const QImage &img)
       
   555 {
       
   556     drawImage(QRectF(p, img.size()), img, img.rect());
       
   557 }
       
   558 
       
   559 void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap,
       
   560                                       const QRectF &sr)
       
   561 {
       
   562     Q_D(QDirectFBPaintEngine);
       
   563 
       
   564     if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) {
       
   565         RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr);
       
   566         d->lock();
       
   567         QRasterPaintEngine::drawPixmap(r, pixmap, sr);
       
   568     } else {
       
   569         QPixmapData *data = pixmap.pixmapData();
       
   570         Q_ASSERT(data->classId() == QPixmapData::DirectFBClass);
       
   571         QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data);
       
   572         if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedBlits)
       
   573                || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
       
   574                || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
       
   575                || (state()->renderHints & QPainter::SmoothPixmapTransform
       
   576                    && state()->matrix.mapRect(r).size() != sr.size())) {
       
   577             RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr);
       
   578             const QImage *img = dfbData->buffer();
       
   579             d->lock();
       
   580             QRasterPaintEngine::drawImage(r, *img, sr);
       
   581         } else {
       
   582             QDirectFBPaintEnginePrivate::unlock(dfbData);
       
   583             d->prepareForBlit(pixmap.hasAlphaChannel());
       
   584             IDirectFBSurface *s = dfbData->directFBSurface();
       
   585             CLIPPED_PAINT(d->blit(r, s, sr));
       
   586         }
       
   587     }
       
   588 }
       
   589 
       
   590 void QDirectFBPaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm)
       
   591 {
       
   592     drawPixmap(QRectF(p, pm.size()), pm, pm.rect());
       
   593 }
       
   594 
       
   595 void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r,
       
   596                                            const QPixmap &pixmap,
       
   597                                            const QPointF &offset)
       
   598 {
       
   599     Q_D(QDirectFBPaintEngine);
       
   600     if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) {
       
   601         RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset);
       
   602         d->lock();
       
   603         QRasterPaintEngine::drawTiledPixmap(r, pixmap, offset);
       
   604     } else if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedBlits)
       
   605                || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
       
   606                || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
       
   607                || (state()->renderHints & QPainter::SmoothPixmapTransform && state()->matrix.isScaling())) {
       
   608         RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset);
       
   609         QPixmapData *pixmapData = pixmap.pixmapData();
       
   610         Q_ASSERT(pixmapData->classId() == QPixmapData::DirectFBClass);
       
   611         QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(pixmapData);
       
   612         const QImage *img = dfbData->buffer();
       
   613         d->lock();
       
   614         QRasterPixmapData *data = new QRasterPixmapData(QPixmapData::PixmapType);
       
   615         data->fromImage(*img, Qt::AutoColor);
       
   616         const QPixmap pix(data);
       
   617         QRasterPaintEngine::drawTiledPixmap(r, pix, offset);
       
   618     } else {
       
   619         CLIPPED_PAINT(d->drawTiledPixmap(r, pixmap, offset));
       
   620     }
       
   621 }
       
   622 
       
   623 
       
   624 void QDirectFBPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
       
   625 {
       
   626     RASTERFALLBACK(STROKE_PATH, path, VOID_ARG(), VOID_ARG());
       
   627     Q_D(QDirectFBPaintEngine);
       
   628     d->lock();
       
   629     QRasterPaintEngine::stroke(path, pen);
       
   630 }
       
   631 
       
   632 void QDirectFBPaintEngine::drawPath(const QPainterPath &path)
       
   633 {
       
   634     RASTERFALLBACK(DRAW_PATH, path, VOID_ARG(), VOID_ARG());
       
   635     Q_D(QDirectFBPaintEngine);
       
   636     d->lock();
       
   637     QRasterPaintEngine::drawPath(path);
       
   638 }
       
   639 
       
   640 void QDirectFBPaintEngine::drawPoints(const QPointF *points, int pointCount)
       
   641 {
       
   642     RASTERFALLBACK(DRAW_POINTS, pointCount, VOID_ARG(), VOID_ARG());
       
   643     Q_D(QDirectFBPaintEngine);
       
   644     d->lock();
       
   645     QRasterPaintEngine::drawPoints(points, pointCount);
       
   646 }
       
   647 
       
   648 void QDirectFBPaintEngine::drawPoints(const QPoint *points, int pointCount)
       
   649 {
       
   650     RASTERFALLBACK(DRAW_POINTS, pointCount, VOID_ARG(), VOID_ARG());
       
   651     Q_D(QDirectFBPaintEngine);
       
   652     d->lock();
       
   653     QRasterPaintEngine::drawPoints(points, pointCount);
       
   654 }
       
   655 
       
   656 void QDirectFBPaintEngine::drawEllipse(const QRectF &rect)
       
   657 {
       
   658     RASTERFALLBACK(DRAW_ELLIPSE, rect, VOID_ARG(), VOID_ARG());
       
   659     Q_D(QDirectFBPaintEngine);
       
   660     d->lock();
       
   661     QRasterPaintEngine::drawEllipse(rect);
       
   662 }
       
   663 
       
   664 void QDirectFBPaintEngine::drawPolygon(const QPointF *points, int pointCount,
       
   665                                        PolygonDrawMode mode)
       
   666 {
       
   667     RASTERFALLBACK(DRAW_POLYGON, pointCount, mode, VOID_ARG());
       
   668     Q_D(QDirectFBPaintEngine);
       
   669     d->lock();
       
   670     QRasterPaintEngine::drawPolygon(points, pointCount, mode);
       
   671 }
       
   672 
       
   673 void QDirectFBPaintEngine::drawPolygon(const QPoint *points, int pointCount,
       
   674                                        PolygonDrawMode mode)
       
   675 {
       
   676     RASTERFALLBACK(DRAW_POLYGON, pointCount, mode, VOID_ARG());
       
   677     Q_D(QDirectFBPaintEngine);
       
   678     d->lock();
       
   679     QRasterPaintEngine::drawPolygon(points, pointCount, mode);
       
   680 }
       
   681 
       
   682 void QDirectFBPaintEngine::drawTextItem(const QPointF &p,
       
   683                                         const QTextItem &textItem)
       
   684 {
       
   685     RASTERFALLBACK(DRAW_TEXT, p, textItem.text(), VOID_ARG());
       
   686     Q_D(QDirectFBPaintEngine);
       
   687     d->lock();
       
   688     QRasterPaintEngine::drawTextItem(p, textItem);
       
   689 }
       
   690 
       
   691 void QDirectFBPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
       
   692 {
       
   693     if (brush.style() == Qt::NoBrush)
       
   694         return;
       
   695     RASTERFALLBACK(FILL_PATH, path, brush, VOID_ARG());
       
   696     Q_D(QDirectFBPaintEngine);
       
   697     d->lock();
       
   698     QRasterPaintEngine::fill(path, brush);
       
   699 }
       
   700 
       
   701 void QDirectFBPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode)
       
   702 {
       
   703     RASTERFALLBACK(DRAW_ROUNDED_RECT, rect, xrad, yrad);
       
   704     Q_D(QDirectFBPaintEngine);
       
   705     d->lock();
       
   706     QRasterPaintEngine::drawRoundedRect(rect, xrad, yrad, mode);
       
   707 }
       
   708 
       
   709 void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
       
   710 {
       
   711     Q_D(QDirectFBPaintEngine);
       
   712     if (brush.style() == Qt::NoBrush)
       
   713         return;
       
   714     if (d->clipType != QDirectFBPaintEnginePrivate::ComplexClip) {
       
   715         switch (brush.style()) {
       
   716         case Qt::SolidPattern: {
       
   717             if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)
       
   718                 || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)) {
       
   719                 break;
       
   720             }
       
   721             const QColor color = brush.color();
       
   722             if (!color.isValid())
       
   723                 return;
       
   724             d->setDFBColor(color);
       
   725             const QRect r = state()->matrix.mapRect(rect).toRect();
       
   726             CLIPPED_PAINT(d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height()));
       
   727             return; }
       
   728 
       
   729         case Qt::TexturePattern: {
       
   730             if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedBlits)
       
   731                 || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
       
   732                 || (state()->renderHints & QPainter::SmoothPixmapTransform && state()->matrix.isScaling())) {
       
   733                 break;
       
   734             }
       
   735 
       
   736             const QPixmap texture = brush.texture();
       
   737             if (texture.pixmapData()->classId() != QPixmapData::DirectFBClass)
       
   738                 break;
       
   739 
       
   740             CLIPPED_PAINT(d->drawTiledPixmap(rect, texture, rect.topLeft() - state()->brushOrigin));
       
   741             return; }
       
   742         default:
       
   743             break;
       
   744         }
       
   745     }
       
   746     RASTERFALLBACK(FILL_RECT, rect, brush, VOID_ARG());
       
   747     d->lock();
       
   748     QRasterPaintEngine::fillRect(rect, brush);
       
   749 }
       
   750 
       
   751 void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QColor &color)
       
   752 {
       
   753     if (!color.isValid())
       
   754         return;
       
   755     Q_D(QDirectFBPaintEngine);
       
   756     if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)
       
   757         || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)
       
   758         || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) {
       
   759         RASTERFALLBACK(FILL_RECT, rect, color, VOID_ARG());
       
   760         d->lock();
       
   761         QRasterPaintEngine::fillRect(rect, color);
       
   762     } else {
       
   763         d->setDFBColor(color);
       
   764         const QRect r = state()->matrix.mapRect(rect).toRect();
       
   765         CLIPPED_PAINT(d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height()));
       
   766     }
       
   767 }
       
   768 
       
   769 void QDirectFBPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
       
   770                                           int x, int y, int length,
       
   771                                           uint const_alpha)
       
   772 {
       
   773     Q_D(QDirectFBPaintEngine);
       
   774     IDirectFBSurface *src = d->surfaceCache->getSurface(buffer, bufsize);
       
   775     // ### how does this play with setDFBColor
       
   776     src->SetColor(src, 0, 0, 0, const_alpha);
       
   777     const DFBRectangle rect = { 0, 0, length, 1 };
       
   778     d->surface->Blit(d->surface, src, &rect, x, y);
       
   779 }
       
   780 
       
   781 #ifdef QT_DIRECTFB_IMAGECACHE
       
   782 static void cachedImageCleanupHook(qint64 key)
       
   783 {
       
   784     delete imageCache.take(key);
       
   785 }
       
   786 void QDirectFBPaintEngine::initImageCache(int size)
       
   787 {
       
   788     Q_ASSERT(size >= 0);
       
   789     imageCache.setMaxCost(size);
       
   790     QImagePixmapCleanupHooks::instance()->addImageHook(cachedImageCleanupHook);
       
   791 }
       
   792 
       
   793 #endif // QT_DIRECTFB_IMAGECACHE
       
   794 
       
   795 // ---- QDirectFBPaintEnginePrivate ----
       
   796 
       
   797 
       
   798 QDirectFBPaintEnginePrivate::QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p)
       
   799     : surface(0), antialiased(false), simplePen(false),
       
   800       transformationType(0), opacity(255),
       
   801       clipType(ClipUnset), dfbDevice(0),
       
   802       compositionModeStatus(0), inClip(false), q(p)
       
   803 {
       
   804     fb = QDirectFBScreen::instance()->dfb();
       
   805     surfaceCache = new SurfaceCache;
       
   806 }
       
   807 
       
   808 QDirectFBPaintEnginePrivate::~QDirectFBPaintEnginePrivate()
       
   809 {
       
   810     delete surfaceCache;
       
   811 }
       
   812 
       
   813 bool QDirectFBPaintEnginePrivate::isSimpleBrush(const QBrush &brush) const
       
   814 {
       
   815     return (brush.style() == Qt::NoBrush) || (brush.style() == Qt::SolidPattern && !antialiased);
       
   816 }
       
   817 
       
   818 void QDirectFBPaintEnginePrivate::lock()
       
   819 {
       
   820     // We will potentially get a new pointer to the buffer after a
       
   821     // lock so we need to call the base implementation of prepare so
       
   822     // it updates its rasterBuffer to point to the new buffer address.
       
   823     Q_ASSERT(dfbDevice);
       
   824     if (dfbDevice->lockSurface(DSLF_READ|DSLF_WRITE)) {
       
   825         prepare(dfbDevice);
       
   826     }
       
   827 }
       
   828 
       
   829 void QDirectFBPaintEnginePrivate::unlock()
       
   830 {
       
   831     Q_ASSERT(dfbDevice);
       
   832 #ifdef QT_DIRECTFB_SUBSURFACE
       
   833     dfbDevice->syncPending = true;
       
   834 #else
       
   835     QDirectFBPaintEnginePrivate::unlock(dfbDevice);
       
   836 #endif
       
   837 }
       
   838 
       
   839 void QDirectFBPaintEnginePrivate::unlock(QDirectFBPaintDevice *device)
       
   840 {
       
   841 #ifdef QT_NO_DIRECTFB_SUBSURFACE
       
   842     Q_ASSERT(device);
       
   843     device->unlockSurface();
       
   844 #else
       
   845     Q_UNUSED(device);
       
   846 #endif
       
   847 }
       
   848 
       
   849 void QDirectFBPaintEnginePrivate::setTransform(const QTransform &transform)
       
   850 {
       
   851     transformationType = transform.type();
       
   852     if (qMin(transform.m11(), transform.m22()) < 0) {
       
   853         transformationType |= QDirectFBPaintEnginePrivate::Matrix_NegativeScale;
       
   854     }
       
   855     setPen(q->state()->pen);
       
   856 }
       
   857 
       
   858 void QDirectFBPaintEnginePrivate::setPen(const QPen &pen)
       
   859 {
       
   860     if (pen.style() == Qt::NoPen) {
       
   861         simplePen = true;
       
   862     } else if (pen.style() == Qt::SolidLine
       
   863                && !antialiased
       
   864                && pen.brush().style() == Qt::SolidPattern
       
   865                && pen.widthF() <= 1.0
       
   866                && (transformationType < QTransform::TxScale || pen.isCosmetic())) {
       
   867         simplePen = true;
       
   868     } else {
       
   869         simplePen = false;
       
   870     }
       
   871 }
       
   872 
       
   873 void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode mode)
       
   874 {
       
   875     if (!surface)
       
   876         return;
       
   877 
       
   878     static const bool forceRasterFallBack = qgetenv("QT_DIRECTFB_FORCE_RASTER").toInt() > 0;
       
   879     if (forceRasterFallBack) {
       
   880         compositionModeStatus = 0;
       
   881         return;
       
   882     }
       
   883 
       
   884     compositionModeStatus = PorterDuff_SupportedBlits;
       
   885     switch (mode) {
       
   886     case QPainter::CompositionMode_Clear:
       
   887         surface->SetPorterDuff(surface, DSPD_CLEAR);
       
   888         break;
       
   889     case QPainter::CompositionMode_Source:
       
   890         surface->SetPorterDuff(surface, DSPD_SRC);
       
   891         break;
       
   892     case QPainter::CompositionMode_SourceOver:
       
   893         compositionModeStatus |= PorterDuff_SupportedPrimitives;
       
   894         surface->SetPorterDuff(surface, DSPD_SRC_OVER);
       
   895         break;
       
   896     case QPainter::CompositionMode_DestinationOver:
       
   897         surface->SetPorterDuff(surface, DSPD_DST_OVER);
       
   898         break;
       
   899     case QPainter::CompositionMode_SourceIn:
       
   900         surface->SetPorterDuff(surface, DSPD_SRC_IN);
       
   901         break;
       
   902     case QPainter::CompositionMode_DestinationIn:
       
   903         surface->SetPorterDuff(surface, DSPD_DST_IN);
       
   904         break;
       
   905     case QPainter::CompositionMode_SourceOut:
       
   906         surface->SetPorterDuff(surface, DSPD_SRC_OUT);
       
   907         break;
       
   908     case QPainter::CompositionMode_DestinationOut:
       
   909         surface->SetPorterDuff(surface, DSPD_DST_OUT);
       
   910         break;
       
   911 #if (Q_DIRECTFB_VERSION >= 0x010000)
       
   912     case QPainter::CompositionMode_SourceAtop:
       
   913         surface->SetPorterDuff(surface, DSPD_SRC_ATOP);
       
   914         break;
       
   915     case QPainter::CompositionMode_DestinationAtop:
       
   916         surface->SetPorterDuff(surface, DSPD_DST_ATOP);
       
   917         break;
       
   918     case QPainter::CompositionMode_Plus:
       
   919         surface->SetPorterDuff(surface, DSPD_ADD);
       
   920         break;
       
   921     case QPainter::CompositionMode_Xor:
       
   922         surface->SetPorterDuff(surface, DSPD_XOR);
       
   923         break;
       
   924 #endif
       
   925     default:
       
   926         compositionModeStatus = 0;
       
   927         break;
       
   928     }
       
   929 }
       
   930 
       
   931 void QDirectFBPaintEnginePrivate::setRenderHints(QPainter::RenderHints hints)
       
   932 {
       
   933     const bool old = antialiased;
       
   934     antialiased = bool(hints & QPainter::Antialiasing);
       
   935     if (old != antialiased) {
       
   936         setPen(q->state()->pen);
       
   937     }
       
   938 }
       
   939 
       
   940 void QDirectFBPaintEnginePrivate::prepareForBlit(bool alpha)
       
   941 {
       
   942     DFBSurfaceBlittingFlags blittingFlags = alpha ? DSBLIT_BLEND_ALPHACHANNEL : DSBLIT_NOFX;
       
   943     if (opacity != 255) {
       
   944         blittingFlags |= DSBLIT_BLEND_COLORALPHA;
       
   945     }
       
   946     surface->SetColor(surface, 0xff, 0xff, 0xff, opacity);
       
   947     surface->SetBlittingFlags(surface, blittingFlags);
       
   948 }
       
   949 
       
   950 static inline uint ALPHA_MUL(uint x, uint a)
       
   951 {
       
   952     uint t = x * a;
       
   953     t = ((t + (t >> 8) + 0x80) >> 8) & 0xff;
       
   954     return t;
       
   955 }
       
   956 
       
   957 void QDirectFBPaintEnginePrivate::setDFBColor(const QColor &color)
       
   958 {
       
   959     Q_ASSERT(surface);
       
   960     const quint8 alpha = (opacity == 255 ?
       
   961                           color.alpha() : ALPHA_MUL(color.alpha(), opacity));
       
   962     surface->SetColor(surface, color.red(), color.green(), color.blue(), alpha);
       
   963     surface->SetPorterDuff(surface, DSPD_NONE);
       
   964     surface->SetDrawingFlags(surface, alpha == 255 ? DSDRAW_NOFX : DSDRAW_BLEND);
       
   965 }
       
   966 
       
   967 IDirectFBSurface *QDirectFBPaintEnginePrivate::getSurface(const QImage &img, bool *release)
       
   968 {
       
   969 #ifdef QT_NO_DIRECTFB_IMAGECACHE
       
   970     *release = true;
       
   971     return QDirectFBScreen::instance()->createDFBSurface(img, img.format(), QDirectFBScreen::DontTrackSurface);
       
   972 #else
       
   973     const qint64 key = img.cacheKey();
       
   974     *release = false;
       
   975     if (imageCache.contains(key)) {
       
   976         return imageCache[key]->surface;
       
   977     }
       
   978 
       
   979     const int cost = cacheCost(img);
       
   980     const bool cache = cost <= imageCache.maxCost();
       
   981     QDirectFBScreen *screen = QDirectFBScreen::instance();
       
   982     const QImage::Format format = (img.format() == screen->alphaPixmapFormat() || QDirectFBPixmapData::hasAlphaChannel(img)
       
   983                                    ? screen->alphaPixmapFormat() : screen->pixelFormat());
       
   984 
       
   985     IDirectFBSurface *surface = screen->createDFBSurface(img, format,
       
   986                                                          cache
       
   987                                                          ? QDirectFBScreen::TrackSurface
       
   988                                                          : QDirectFBScreen::DontTrackSurface);
       
   989     if (cache) {
       
   990         CachedImage *cachedImage = new CachedImage;
       
   991         const_cast<QImage&>(img).data_ptr()->is_cached = true;
       
   992         cachedImage->surface = surface;
       
   993         imageCache.insert(key, cachedImage, cost);
       
   994     } else {
       
   995         *release = true;
       
   996     }
       
   997     return surface;
       
   998 #endif
       
   999 }
       
  1000 
       
  1001 
       
  1002 void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s, const QRectF &src)
       
  1003 {
       
  1004     const QRect sr = src.toRect();
       
  1005     const QRect dr = q->state()->matrix.mapRect(dest).toRect();
       
  1006     if (dr.isEmpty())
       
  1007         return;
       
  1008     const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() };
       
  1009     DFBResult result;
       
  1010 
       
  1011     if (dr.size() == sr.size()) {
       
  1012         result = surface->Blit(surface, s, &sRect, dr.x(), dr.y());
       
  1013     } else {
       
  1014         const DFBRectangle dRect = { dr.x(), dr.y(), dr.width(), dr.height() };
       
  1015         result = surface->StretchBlit(surface, s, &sRect, &dRect);
       
  1016     }
       
  1017     if (result != DFB_OK)
       
  1018         DirectFBError("QDirectFBPaintEngine::drawPixmap()", result);
       
  1019 }
       
  1020 
       
  1021 static inline qreal fixCoord(qreal rect_pos, qreal pixmapSize, qreal offset)
       
  1022 {
       
  1023     qreal pos = rect_pos - offset;
       
  1024     while (pos > rect_pos)
       
  1025         pos -= pixmapSize;
       
  1026     while (pos + pixmapSize < rect_pos)
       
  1027         pos += pixmapSize;
       
  1028     return pos;
       
  1029 }
       
  1030 
       
  1031 void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &off)
       
  1032 {
       
  1033     Q_ASSERT(!(transformationType & Matrix_BlitsUnsupported));
       
  1034     const QTransform &transform = q->state()->matrix;
       
  1035     const QRect destinationRect = transform.mapRect(dest).toRect().normalized();
       
  1036     QRect newClip = destinationRect;
       
  1037     if (!currentClip.isEmpty())
       
  1038         newClip &= currentClip;
       
  1039 
       
  1040     if (newClip.isNull())
       
  1041         return;
       
  1042 
       
  1043     const DFBRegion clip = {
       
  1044         newClip.x(),
       
  1045         newClip.y(),
       
  1046         newClip.right(),
       
  1047         newClip.bottom()
       
  1048     };
       
  1049     surface->SetClip(surface, &clip);
       
  1050 
       
  1051     QPointF offset = off;
       
  1052     Q_ASSERT(transform.type() <= QTransform::TxScale);
       
  1053     prepareForBlit(pixmap.hasAlphaChannel());
       
  1054     QPixmapData *data = pixmap.pixmapData();
       
  1055     Q_ASSERT(data->classId() == QPixmapData::DirectFBClass);
       
  1056     QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data);
       
  1057     QDirectFBPaintEnginePrivate::unlock(dfbData);
       
  1058     const QSize pixmapSize = dfbData->size();
       
  1059     IDirectFBSurface *sourceSurface = dfbData->directFBSurface();
       
  1060     if (transform.isScaling()) {
       
  1061         Q_ASSERT(qMin(transform.m11(), transform.m22()) >= 0);
       
  1062         offset.rx() *= transform.m11();
       
  1063         offset.ry() *= transform.m22();
       
  1064 
       
  1065         const QSizeF mappedSize(pixmapSize.width() * transform.m11(), pixmapSize.height() * transform.m22());
       
  1066         qreal y = fixCoord(destinationRect.y(), mappedSize.height(), offset.y());
       
  1067         const qreal startX = fixCoord(destinationRect.x(), mappedSize.width(), offset.x());
       
  1068         while (y <= destinationRect.bottom()) {
       
  1069             qreal x = startX;
       
  1070             while (x <= destinationRect.right()) {
       
  1071                 const DFBRectangle destination = { qRound(x), qRound(y), mappedSize.width(), mappedSize.height() };
       
  1072                 surface->StretchBlit(surface, sourceSurface, 0, &destination);
       
  1073                 x += mappedSize.width();
       
  1074             }
       
  1075             y += mappedSize.height();
       
  1076         }
       
  1077     } else {
       
  1078         qreal y = fixCoord(destinationRect.y(), pixmapSize.height(), offset.y());
       
  1079         const qreal startX = fixCoord(destinationRect.x(), pixmapSize.width(), offset.x());
       
  1080         int horizontal = qMax(1, destinationRect.width() / pixmapSize.width()) + 1;
       
  1081         if (startX != destinationRect.x())
       
  1082             ++horizontal;
       
  1083         int vertical = qMax(1, destinationRect.height() / pixmapSize.height()) + 1;
       
  1084         if (y != destinationRect.y())
       
  1085             ++vertical;
       
  1086 
       
  1087         const int maxCount = (vertical * horizontal);
       
  1088         QVarLengthArray<DFBRectangle, 16> sourceRects(maxCount);
       
  1089         QVarLengthArray<DFBPoint, 16> points(maxCount);
       
  1090 
       
  1091         int i = 0;
       
  1092         while (y <= destinationRect.bottom()) {
       
  1093             Q_ASSERT(i < maxCount);
       
  1094             qreal x = startX;
       
  1095             while (x <= destinationRect.right()) {
       
  1096                 points[i].x = qRound(x);
       
  1097                 points[i].y = qRound(y);
       
  1098                 sourceRects[i].x = 0;
       
  1099                 sourceRects[i].y = 0;
       
  1100                 sourceRects[i].w = int(pixmapSize.width());
       
  1101                 sourceRects[i].h = int(pixmapSize.height());
       
  1102                 x += pixmapSize.width();
       
  1103                 ++i;
       
  1104             }
       
  1105             y += pixmapSize.height();
       
  1106         }
       
  1107         surface->BatchBlit(surface, sourceSurface, sourceRects.constData(), points.constData(), i);
       
  1108     }
       
  1109 
       
  1110     if (currentClip.isEmpty()) {
       
  1111         surface->SetClip(surface, 0);
       
  1112     } else {
       
  1113         const DFBRegion clip = {
       
  1114             currentClip.x(),
       
  1115             currentClip.y(),
       
  1116             currentClip.right(),
       
  1117             currentClip.bottom()
       
  1118         };
       
  1119         surface->SetClip(surface, &clip);
       
  1120     }
       
  1121 }
       
  1122 
       
  1123 void QDirectFBPaintEnginePrivate::updateClip()
       
  1124 {
       
  1125     Q_ASSERT(surface);
       
  1126     currentClip = QRect();
       
  1127     const QClipData *clipData = clip();
       
  1128     if (!clipData || !clipData->enabled) {
       
  1129         surface->SetClip(surface, NULL);
       
  1130         clipType = NoClip;
       
  1131     } else if (clipData->hasRectClip) {
       
  1132         const DFBRegion r = {
       
  1133             clipData->clipRect.x(),
       
  1134             clipData->clipRect.y(),
       
  1135             clipData->clipRect.right(),
       
  1136             clipData->clipRect.bottom()
       
  1137         };
       
  1138         surface->SetClip(surface, &r);
       
  1139         currentClip = clipData->clipRect.normalized();
       
  1140         // ### is this guaranteed to always be normalized?
       
  1141         clipType = RectClip;
       
  1142     } else if (clipData->hasRegionClip) {
       
  1143         clipType = RegionClip;
       
  1144     } else {
       
  1145         clipType = ComplexClip;
       
  1146     }
       
  1147 }
       
  1148 
       
  1149 void QDirectFBPaintEnginePrivate::systemStateChanged()
       
  1150 {
       
  1151     QRasterPaintEnginePrivate::systemStateChanged();
       
  1152     updateClip();
       
  1153 }
       
  1154 
       
  1155 IDirectFBSurface *SurfaceCache::getSurface(const uint *buf, int size)
       
  1156 {
       
  1157     if (buffer == buf && bufsize == size)
       
  1158         return surface;
       
  1159 
       
  1160     clear();
       
  1161 
       
  1162     const DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(buf, size);
       
  1163     surface = QDirectFBScreen::instance()->createDFBSurface(description, QDirectFBScreen::TrackSurface, 0);
       
  1164     if (!surface)
       
  1165         qWarning("QDirectFBPaintEngine: SurfaceCache: Unable to create surface");
       
  1166 
       
  1167     buffer = const_cast<uint*>(buf);
       
  1168     bufsize = size;
       
  1169 
       
  1170     return surface;
       
  1171 }
       
  1172 
       
  1173 void SurfaceCache::clear()
       
  1174 {
       
  1175     if (surface && QDirectFBScreen::instance())
       
  1176         QDirectFBScreen::instance()->releaseDFBSurface(surface);
       
  1177     surface = 0;
       
  1178     buffer = 0;
       
  1179     bufsize = 0;
       
  1180 }
       
  1181 
       
  1182 
       
  1183 static inline QRect mapRect(const QTransform &transform, const QRect &rect) { return transform.mapRect(rect); }
       
  1184 static inline QRect mapRect(const QTransform &transform, const QRectF &rect) { return transform.mapRect(rect).toRect(); }
       
  1185 static inline QLine map(const QTransform &transform, const QLine &line) { return transform.map(line); }
       
  1186 static inline QLine map(const QTransform &transform, const QLineF &line) { return transform.map(line).toLine(); }
       
  1187 template <class T>
       
  1188 static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface)
       
  1189 {
       
  1190     if (n == 1) {
       
  1191         const QLine l = map(transform, lines[0]);
       
  1192         surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2());
       
  1193     } else {
       
  1194         QVarLengthArray<DFBRegion, 32> lineArray(n);
       
  1195         for (int i=0; i<n; ++i) {
       
  1196             const QLine l = map(transform, lines[i]);
       
  1197             lineArray[i].x1 = l.x1();
       
  1198             lineArray[i].y1 = l.y1();
       
  1199             lineArray[i].x2 = l.x2();
       
  1200             lineArray[i].y2 = l.y2();
       
  1201         }
       
  1202         surface->DrawLines(surface, lineArray.constData(), n);
       
  1203     }
       
  1204 }
       
  1205 
       
  1206 template <class T>
       
  1207 static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface)
       
  1208 {
       
  1209     if (n == 1) {
       
  1210         const QRect r = mapRect(transform, rects[0]);
       
  1211         surface->FillRectangle(surface, r.x(), r.y(), r.width(), r.height());
       
  1212     } else {
       
  1213         QVarLengthArray<DFBRectangle, 32> rectArray(n);
       
  1214         for (int i=0; i<n; ++i) {
       
  1215             const QRect r = mapRect(transform, rects[i]);
       
  1216             rectArray[i].x = r.x();
       
  1217             rectArray[i].y = r.y();
       
  1218             rectArray[i].w = r.width();
       
  1219             rectArray[i].h = r.height();
       
  1220         }
       
  1221         surface->FillRectangles(surface, rectArray.constData(), n);
       
  1222     }
       
  1223 }
       
  1224 
       
  1225 template <class T>
       
  1226 static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface)
       
  1227 {
       
  1228     for (int i=0; i<n; ++i) {
       
  1229         const QRect r = mapRect(transform, rects[i]);
       
  1230         surface->DrawRectangle(surface, r.x(), r.y(), r.width(), r.height());
       
  1231     }
       
  1232 }
       
  1233 
       
  1234 #ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS
       
  1235 template <typename T> inline const T *ptr(const T &t) { return &t; }
       
  1236 template <> inline const bool* ptr<bool>(const bool &) { return 0; }
       
  1237 template <typename device, typename T1, typename T2, typename T3>
       
  1238 static void rasterFallbackWarn(const char *msg, const char *func, const device *dev,
       
  1239                                uint transformationType, bool simplePen,
       
  1240                                uint clipType, uint compositionModeStatus,
       
  1241                                const char *nameOne, const T1 &one,
       
  1242                                const char *nameTwo, const T2 &two,
       
  1243                                const char *nameThree, const T3 &three)
       
  1244 {
       
  1245     QString out;
       
  1246     QDebug dbg(&out);
       
  1247     dbg << msg << (QByteArray(func) + "()")  << "painting on";
       
  1248     if (dev->devType() == QInternal::Widget) {
       
  1249         dbg << static_cast<const QWidget*>(dev);
       
  1250     } else {
       
  1251         dbg << dev << "of type" << dev->devType();
       
  1252     }
       
  1253 
       
  1254     dbg << QString::fromLatin1("transformationType 0x%1").arg(transformationType, 3, 16, QLatin1Char('0'))
       
  1255         << "simplePen" << simplePen
       
  1256         << "clipType" << clipType
       
  1257         << "compositionModeStatus" << compositionModeStatus;
       
  1258 
       
  1259     const T1 *t1 = ptr(one);
       
  1260     const T2 *t2 = ptr(two);
       
  1261     const T3 *t3 = ptr(three);
       
  1262 
       
  1263     if (t1) {
       
  1264         dbg << nameOne << *t1;
       
  1265         if (t2) {
       
  1266             dbg << nameTwo << *t2;
       
  1267             if (t3) {
       
  1268                 dbg << nameThree << *t3;
       
  1269             }
       
  1270         }
       
  1271     }
       
  1272     qWarning("%s", qPrintable(out));
       
  1273 }
       
  1274 
       
  1275 #endif // QT_DIRECTFB_WARN_ON_RASTERFALLBACKS
       
  1276 
       
  1277 QT_END_NAMESPACE
       
  1278 
       
  1279 #endif // QT_NO_QWS_DIRECTFB