1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 
59 QT_BEGIN_NAMESPACE
60 
61 class SurfaceCache;
62 class QDirectFBPaintEnginePrivate : public QRasterPaintEnginePrivate
63 {
64 public:
65     enum TransformationTypeFlags {
66         Matrix_NegativeScaleX = 0x100,
67         Matrix_NegativeScaleY = 0x200,
68         Matrix_RectsUnsupported = (QTransform::TxRotate|QTransform::TxShear|QTransform::TxProject),
69 #if (Q_DIRECTFB_VERSION >= 0x010403)
70         Matrix_BlitsUnsupported = (Matrix_RectsUnsupported)
71 #else
72         Matrix_BlitsUnsupported = (Matrix_RectsUnsupported|Matrix_NegativeScaleX|Matrix_NegativeScaleY)
73 #endif
74     };
75 
getTransformationType(const QTransform & transform)76     inline static uint getTransformationType(const QTransform &transform)
77     {
78         int ret = transform.type();
79         if (transform.m11() < 0)
80             ret |= QDirectFBPaintEnginePrivate::Matrix_NegativeScaleX;
81         if (transform.m22() < 0)
82             ret |= QDirectFBPaintEnginePrivate::Matrix_NegativeScaleY;
83         return ret;
84     }
85 
86     enum ClipType {
87         ClipUnset,
88         NoClip,
89         RectClip,
90         RegionClip,
91         ComplexClip
92     };
93 
94     QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p);
95     ~QDirectFBPaintEnginePrivate();
96 
97     void setBrush(const QBrush &brush);
98     void setCompositionMode(QPainter::CompositionMode mode);
99     void setPen(const QPen &pen);
100     void setTransform(const QTransform &transforma);
101     void setRenderHints(QPainter::RenderHints hints);
102 
103     bool prepareForDraw(const QColor &color);
104 
105     void lock();
106     void unlock();
107     static inline void unlock(QDirectFBPaintDevice *device);
108 
109     void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos, const QTransform &pixmapTransform);
110     void blit(const QRectF &dest, IDirectFBSurface *surface, const QRectF &src);
111 
112     bool supportsStretchBlit() const;
113 
114     void updateClip();
115     virtual void systemStateChanged();
116 
117     static IDirectFBSurface *getSurface(const QImage &img, bool *release);
118 
119 #ifdef QT_DIRECTFB_IMAGECACHE
cacheCost(const QImage & img)120     static inline int cacheCost(const QImage &img) { return img.width() * img.height() * img.depth() / 8; }
121 #endif
122 
123     enum BlitFlag {
124         HasAlpha = 0x1,
125         Premultiplied = 0x2
126     };
127     void prepareForBlit(uint blitFlags);
128 
129     IDirectFBSurface *surface;
130 
131     bool antialiased;
132     bool supportedBrush;
133     bool supportedPen;
134 
135     uint transformationType; // this is QTransform::type() + Matrix_NegativeScale if qMin(transform.m11(), transform.m22()) < 0
136 
137     SurfaceCache *surfaceCache;
138     IDirectFB *fb;
139     quint8 opacity;
140 
141     ClipType clipType;
142     QDirectFBPaintDevice *dfbDevice;
143     bool supportedComposition;
144     bool isPremultiplied;
145 
146     bool inClip;
147     QRect currentClip;
148 
149     QDirectFBPaintEngine *engine;
150 };
151 
152 class SurfaceCache
153 {
154 public:
SurfaceCache()155     SurfaceCache() : surface(0), buffer(0), bufsize(0) {}
~SurfaceCache()156     ~SurfaceCache() { clear(); }
157     IDirectFBSurface *getSurface(const uint *buf, int size);
158     void clear();
159 private:
160     IDirectFBSurface *surface;
161     uint *buffer;
162     int bufsize;
163 };
164 
165 
166 #ifdef QT_DIRECTFB_IMAGECACHE
167 QT_BEGIN_INCLUDE_NAMESPACE
168 #include <private/qimage_p.h>
169 QT_END_INCLUDE_NAMESPACE
170 struct CachedImage
171 {
172     IDirectFBSurface *surface;
~CachedImageCachedImage173     ~CachedImage()
174     {
175         if (surface && QDirectFBScreen::instance()) {
176             QDirectFBScreen::instance()->releaseDFBSurface(surface);
177         }
178     }
179 };
180 static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB
181 #endif
182 
183 #define VOID_ARG() static_cast<bool>(false)
184 enum PaintOperation {
185     DRAW_RECTS          = 0x0001,
186     DRAW_LINES          = 0x0002,
187     DRAW_IMAGE          = 0x0004,
188     DRAW_PIXMAP         = 0x0008,
189     DRAW_TILED_PIXMAP   = 0x0010,
190     STROKE_PATH         = 0x0020,
191     DRAW_PATH           = 0x0040,
192     DRAW_POINTS         = 0x0080,
193     DRAW_ELLIPSE        = 0x0100,
194     DRAW_POLYGON        = 0x0200,
195     DRAW_TEXT           = 0x0400,
196     FILL_PATH           = 0x0800,
197     FILL_RECT           = 0x1000,
198     DRAW_COLORSPANS     = 0x2000,
199     DRAW_ROUNDED_RECT   = 0x4000,
200     DRAW_STATICTEXT     = 0x8000,
201     ALL                 = 0xffff
202 };
203 
204 //#define QT_DIRECTFB_WARN_ON_RASTERFALLBACKS ALL
205 
206 enum { RasterWarn = 1, RasterDisable = 2 };
rasterFallbacksMask(PaintOperation op)207 static inline uint rasterFallbacksMask(PaintOperation op)
208 {
209     uint ret = 0;
210 #ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS
211     if (op & QT_DIRECTFB_WARN_ON_RASTERFALLBACKS)
212         ret |= RasterWarn;
213 #endif
214 #ifdef QT_DIRECTFB_DISABLE_RASTERFALLBACKS
215     if (op & QT_DIRECTFB_DISABLE_RASTERFALLBACKS)
216         ret |= RasterDisable;
217 #endif
218     static int warningMask = -1;
219     static int disableMask = -1;
220     if (warningMask < 0) {
221         struct {
222             const char *name;
223             PaintOperation operation;
224         } const operations[] = {
225             { "DRAW_RECTS", DRAW_RECTS },
226             { "DRAW_LINES", DRAW_LINES },
227             { "DRAW_IMAGE", DRAW_IMAGE },
228             { "DRAW_PIXMAP", DRAW_PIXMAP },
229             { "DRAW_TILED_PIXMAP", DRAW_TILED_PIXMAP },
230             { "STROKE_PATH", STROKE_PATH },
231             { "DRAW_PATH", DRAW_PATH },
232             { "DRAW_POINTS", DRAW_POINTS },
233             { "DRAW_ELLIPSE", DRAW_ELLIPSE },
234             { "DRAW_POLYGON", DRAW_POLYGON },
235             { "DRAW_TEXT", DRAW_TEXT },
236             { "FILL_PATH", FILL_PATH },
237             { "FILL_RECT", FILL_RECT },
238             { "DRAW_COLORSPANS", DRAW_COLORSPANS },
239             { "DRAW_ROUNDED_RECT", DRAW_ROUNDED_RECT },
240             { "ALL", ALL },
241             { 0, ALL }
242         };
243 
244         QStringList warning = QString::fromLatin1(qgetenv("QT_DIRECTFB_WARN_ON_RASTERFALLBACKS")).toUpper().split(QLatin1Char('|'),
245                                                                                                                   QString::SkipEmptyParts);
246         QStringList disable = QString::fromLatin1(qgetenv("QT_DIRECTFB_DISABLE_RASTERFALLBACKS")).toUpper().split(QLatin1Char('|'),
247                                                                                                                   QString::SkipEmptyParts);
248         warningMask = 0;
249         disableMask = 0;
250         if (!warning.isEmpty() || !disable.isEmpty()) {
251             for (int i=0; operations[i].name; ++i) {
252                 const QString name = QString::fromLatin1(operations[i].name);
253                 int idx = warning.indexOf(name);
254                 if (idx != -1) {
255                     warningMask |= operations[i].operation;
256                     warning.erase(warning.begin() + idx);
257                 }
258                 idx = disable.indexOf(name);
259                 if (idx != -1) {
260                     disableMask |= operations[i].operation;
261                     disable.erase(disable.begin() + idx);
262                 }
263             }
264         }
265         if (!warning.isEmpty()) {
266             qWarning("QDirectFBPaintEngine QT_DIRECTFB_WARN_ON_RASTERFALLBACKS Unknown operation(s): %s",
267                      qPrintable(warning.join(QLatin1String("|"))));
268         }
269         if (!disable.isEmpty()) {
270             qWarning("QDirectFBPaintEngine QT_DIRECTFB_DISABLE_RASTERFALLBACKS Unknown operation(s): %s",
271                      qPrintable(disable.join(QLatin1String("|"))));
272         }
273     }
274     if (op & warningMask)
275         ret |= RasterWarn;
276     if (op & disableMask)
277         ret |= RasterDisable;
278     return ret;
279 }
280 
281 template <typename device, typename T1, typename T2, typename T3>
282 static void rasterFallbackWarn(const char *msg, const char *func, const device *dev,
283                                QDirectFBPaintEnginePrivate *priv,
284                                const char *nameOne, const T1 &one,
285                                const char *nameTwo, const T2 &two,
286                                const char *nameThree, const T3 &three);
287 
288 #define RASTERFALLBACK(op, one, two, three)                             \
289     {                                                                   \
290         static const uint rasterFallbacks = rasterFallbacksMask(op);    \
291         switch (rasterFallbacks) {                                      \
292         case 0: break;                                                  \
293         case RasterWarn:                                                \
294             rasterFallbackWarn("Falling back to raster engine for",     \
295                                __FUNCTION__,                            \
296                                state()->painter->device(),              \
297                                d_func(),                                \
298                                #one, one, #two, two, #three, three);    \
299             break;                                                      \
300         case RasterDisable|RasterWarn:                                  \
301             rasterFallbackWarn("Disabled raster engine operation",      \
302                                __FUNCTION__,                            \
303                                state()->painter->device(),              \
304                                d_func(),                                \
305                                #one, one, #two, two, #three, three);    \
306         case RasterDisable:                                             \
307             return;                                                     \
308         }                                                               \
309     }
310 
311 template <class T>
312 static inline void drawPoints(const T *points, int n, const QTransform &transform, IDirectFBSurface *surface);
313 template <class T>
314 static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface);
315 template <class T>
316 static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface);
317 template <class T>
318 static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface);
319 
320 #define CLIPPED_PAINT(operation) {                                      \
321         d->unlock();                                                    \
322         DFBRegion clipRegion;                                           \
323         switch (d->clipType) {                                          \
324         case QDirectFBPaintEnginePrivate::NoClip:                       \
325         case QDirectFBPaintEnginePrivate::RectClip:                     \
326             operation;                                                  \
327             break;                                                      \
328         case QDirectFBPaintEnginePrivate::RegionClip: {                 \
329             Q_ASSERT(d->clip());                                        \
330             const QVector<QRect> cr = d->clip()->clipRegion.rects();    \
331             const int size = cr.size();                                 \
332             for (int i=0; i<size; ++i) {                                \
333                 d->currentClip = cr.at(i);                              \
334                 clipRegion.x1 = d->currentClip.x();                     \
335                 clipRegion.y1 = d->currentClip.y();                     \
336                 clipRegion.x2 = d->currentClip.right();                 \
337                 clipRegion.y2 = d->currentClip.bottom();                \
338                 d->surface->SetClip(d->surface, &clipRegion);           \
339                 operation;                                              \
340             }                                                           \
341             d->updateClip();                                            \
342             break; }                                                    \
343         case QDirectFBPaintEnginePrivate::ComplexClip:                  \
344         case QDirectFBPaintEnginePrivate::ClipUnset:                    \
345             qFatal("CLIPPED_PAINT internal error %d", d->clipType);     \
346             break;                                                      \
347         }                                                               \
348     }
349 
350 
QDirectFBPaintEngine(QPaintDevice * device)351 QDirectFBPaintEngine::QDirectFBPaintEngine(QPaintDevice *device)
352     : QRasterPaintEngine(*(new QDirectFBPaintEnginePrivate(this)), device)
353 {
354 }
355 
~QDirectFBPaintEngine()356 QDirectFBPaintEngine::~QDirectFBPaintEngine()
357 {
358 }
359 
begin(QPaintDevice * device)360 bool QDirectFBPaintEngine::begin(QPaintDevice *device)
361 {
362     Q_D(QDirectFBPaintEngine);
363     if (device->devType() == QInternal::CustomRaster) {
364         d->dfbDevice = static_cast<QDirectFBPaintDevice*>(device);
365     } else if (device->devType() == QInternal::Pixmap) {
366         QPixmapData *data = static_cast<QPixmap*>(device)->pixmapData();
367         Q_ASSERT(data->classId() == QPixmapData::DirectFBClass);
368         QDirectFBPixmapData *dfbPixmapData = static_cast<QDirectFBPixmapData*>(data);
369         QDirectFBPaintEnginePrivate::unlock(dfbPixmapData);
370         d->dfbDevice = static_cast<QDirectFBPaintDevice*>(dfbPixmapData);
371     }
372 
373     if (d->dfbDevice)
374         d->surface = d->dfbDevice->directFBSurface();
375 
376     if (!d->surface) {
377         qFatal("QDirectFBPaintEngine used on an invalid device: 0x%x",
378                device->devType());
379     }
380     d->isPremultiplied = QDirectFBScreen::isPremultiplied(d->dfbDevice->format());
381 
382     d->prepare(d->dfbDevice);
383     gccaps = AllFeatures;
384     d->setCompositionMode(state()->composition_mode);
385 
386     return QRasterPaintEngine::begin(device);
387 }
388 
end()389 bool QDirectFBPaintEngine::end()
390 {
391     Q_D(QDirectFBPaintEngine);
392     d->unlock();
393     d->dfbDevice = 0;
394 #if (Q_DIRECTFB_VERSION >= 0x010000)
395     d->surface->ReleaseSource(d->surface);
396 #endif
397     d->currentClip = QRect();
398     d->surface->SetClip(d->surface, NULL);
399     d->surface = 0;
400     return QRasterPaintEngine::end();
401 }
402 
clipEnabledChanged()403 void QDirectFBPaintEngine::clipEnabledChanged()
404 {
405     Q_D(QDirectFBPaintEngine);
406     QRasterPaintEngine::clipEnabledChanged();
407     d->updateClip();
408 }
409 
brushChanged()410 void QDirectFBPaintEngine::brushChanged()
411 {
412     Q_D(QDirectFBPaintEngine);
413     d->setBrush(state()->brush);
414 
415     QRasterPaintEngine::brushChanged();
416 }
417 
penChanged()418 void QDirectFBPaintEngine::penChanged()
419 {
420     Q_D(QDirectFBPaintEngine);
421     d->setPen(state()->pen);
422 
423     QRasterPaintEngine::penChanged();
424 }
425 
opacityChanged()426 void QDirectFBPaintEngine::opacityChanged()
427 {
428     Q_D(QDirectFBPaintEngine);
429     d->opacity = quint8(state()->opacity * 255);
430     QRasterPaintEngine::opacityChanged();
431 }
432 
compositionModeChanged()433 void QDirectFBPaintEngine::compositionModeChanged()
434 {
435     Q_D(QDirectFBPaintEngine);
436     d->setCompositionMode(state()->compositionMode());
437     QRasterPaintEngine::compositionModeChanged();
438 }
439 
renderHintsChanged()440 void QDirectFBPaintEngine::renderHintsChanged()
441 {
442     Q_D(QDirectFBPaintEngine);
443     d->setRenderHints(state()->renderHints);
444     QRasterPaintEngine::renderHintsChanged();
445 }
446 
transformChanged()447 void QDirectFBPaintEngine::transformChanged()
448 {
449     Q_D(QDirectFBPaintEngine);
450     d->setTransform(state()->matrix);
451     QRasterPaintEngine::transformChanged();
452 }
453 
setState(QPainterState * state)454 void QDirectFBPaintEngine::setState(QPainterState *state)
455 {
456     Q_D(QDirectFBPaintEngine);
457     QRasterPaintEngine::setState(state);
458     d->setPen(state->pen);
459     d->opacity = quint8(state->opacity * 255);
460     d->setCompositionMode(state->compositionMode());
461     d->setTransform(state->transform());
462     d->setRenderHints(state->renderHints);
463     if (d->surface)
464         d->updateClip();
465 }
466 
clip(const QVectorPath & path,Qt::ClipOperation op)467 void QDirectFBPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
468 {
469     Q_D(QDirectFBPaintEngine);
470     const bool wasInClip = d->inClip;
471     d->inClip = true;
472     QRasterPaintEngine::clip(path, op);
473     if (!wasInClip) {
474         d->inClip = false;
475         d->updateClip();
476     }
477 }
478 
clip(const QRegion & region,Qt::ClipOperation op)479 void QDirectFBPaintEngine::clip(const QRegion &region, Qt::ClipOperation op)
480 {
481     Q_D(QDirectFBPaintEngine);
482     const bool wasInClip = d->inClip;
483     d->inClip = true;
484     QRasterPaintEngine::clip(region, op);
485     if (!wasInClip) {
486         d->inClip = false;
487         d->updateClip();
488     }
489 }
490 
clip(const QRect & rect,Qt::ClipOperation op)491 void QDirectFBPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
492 {
493     Q_D(QDirectFBPaintEngine);
494     const bool wasInClip = d->inClip;
495     d->inClip = true;
496     QRasterPaintEngine::clip(rect, op);
497     if (!wasInClip) {
498         d->inClip = false;
499         d->updateClip();
500     }
501 }
502 
drawRects(const QRect * rects,int rectCount)503 void QDirectFBPaintEngine::drawRects(const QRect *rects, int rectCount)
504 {
505     Q_D(QDirectFBPaintEngine);
506     const QPen &pen = state()->pen;
507     const QBrush &brush = state()->brush;
508     if (brush.style() == Qt::NoBrush && pen.style() == Qt::NoPen)
509         return;
510 
511     if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)
512         || !d->supportedPen
513         || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
514         || !d->supportedBrush
515         || !d->supportedComposition) {
516         RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG());
517         d->lock();
518         QRasterPaintEngine::drawRects(rects, rectCount);
519         return;
520     }
521 
522     if (brush.style() != Qt::NoBrush && d->prepareForDraw(brush.color())) {
523         CLIPPED_PAINT(QT_PREPEND_NAMESPACE(fillRects<QRect>)(rects, rectCount, state()->matrix, d->surface));
524     }
525 
526     if (pen.style() != Qt::NoPen && d->prepareForDraw(pen.color())) {
527         CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawRects<QRect>)(rects, rectCount, state()->matrix, d->surface));
528     }
529 }
530 
drawRects(const QRectF * rects,int rectCount)531 void QDirectFBPaintEngine::drawRects(const QRectF *rects, int rectCount)
532 {
533     Q_D(QDirectFBPaintEngine);
534     const QPen &pen = state()->pen;
535     const QBrush &brush = state()->brush;
536     if (brush.style() == Qt::NoBrush && pen.style() == Qt::NoPen)
537         return;
538 
539     if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)
540         || !d->supportedPen
541         || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
542         || !d->supportedBrush
543         || !d->supportedComposition) {
544         RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG());
545         d->lock();
546         QRasterPaintEngine::drawRects(rects, rectCount);
547         return;
548     }
549 
550     if (brush.style() != Qt::NoBrush && d->prepareForDraw(brush.color())) {
551         CLIPPED_PAINT(fillRects<QRectF>(rects, rectCount, state()->matrix, d->surface));
552     }
553 
554     if (pen.style() != Qt::NoPen && d->prepareForDraw(pen.color())) {
555         CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawRects<QRectF>)(rects, rectCount, state()->matrix, d->surface));
556     }
557 }
558 
drawLines(const QLine * lines,int lineCount)559 void QDirectFBPaintEngine::drawLines(const QLine *lines, int lineCount)
560 {
561     Q_D(QDirectFBPaintEngine);
562 
563     const QPen &pen = state()->pen;
564     if (!d->supportedPen
565         || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
566         || !d->supportedComposition) {
567         RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG());
568         d->lock();
569         QRasterPaintEngine::drawLines(lines, lineCount);
570         return;
571     }
572 
573     if (pen.style() != Qt::NoPen && d->prepareForDraw(pen.color())) {
574         CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawLines<QLine>)(lines, lineCount, state()->matrix, d->surface));
575     }
576 }
577 
drawLines(const QLineF * lines,int lineCount)578 void QDirectFBPaintEngine::drawLines(const QLineF *lines, int lineCount)
579 {
580     Q_D(QDirectFBPaintEngine);
581 
582     const QPen &pen = state()->pen;
583     if (!d->supportedPen
584         || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
585         || !d->supportedComposition) {
586         RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG());
587         d->lock();
588         QRasterPaintEngine::drawLines(lines, lineCount);
589         return;
590     }
591 
592     if (pen.style() != Qt::NoPen && d->prepareForDraw(pen.color())) {
593         CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawLines<QLineF>)(lines, lineCount, state()->matrix, d->surface));
594     }
595 }
596 
drawImage(const QRectF & r,const QImage & image,const QRectF & sr,Qt::ImageConversionFlags flags)597 void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image,
598                                      const QRectF &sr,
599                                      Qt::ImageConversionFlags flags)
600 {
601     Q_D(QDirectFBPaintEngine);
602     Q_UNUSED(flags);
603 
604     /*  This is hard to read. The way it works is like this:
605 
606     - If you do not have support for preallocated surfaces and do not use an
607     image cache we always fall back to raster engine.
608 
609     - If it's rotated/sheared/mirrored (negative scale) or we can't
610     clip it we fall back to raster engine.
611 
612     - If we don't cache the image, but we do have support for
613     preallocated surfaces we fall back to the raster engine if the
614     image is in a format DirectFB can't handle.
615 
616     - If we do cache the image but don't have support for preallocated
617     images and the cost of caching the image (bytes used) is higher
618     than the max image cache size we fall back to raster engine.
619     */
620 
621 #if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE
622     if (!d->supportedComposition
623         || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
624         || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip)
625         || (!d->supportsStretchBlit() && state()->matrix.mapRect(r).size() != sr.size())
626 #ifndef QT_DIRECTFB_IMAGECACHE
627         || (QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN)
628 #elif defined QT_NO_DIRECTFB_PREALLOCATED
629         || (QDirectFBPaintEnginePrivate::cacheCost(image) > imageCache.maxCost())
630 #endif
631         )
632 #endif
633     {
634         RASTERFALLBACK(DRAW_IMAGE, r, image.size(), sr);
635         d->lock();
636         QRasterPaintEngine::drawImage(r, image, sr, flags);
637         return;
638     }
639 #if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE
640     bool release;
641     IDirectFBSurface *imgSurface = d->getSurface(image, &release);
642     uint blitFlags = 0;
643     if (image.hasAlphaChannel())
644         blitFlags |= QDirectFBPaintEnginePrivate::HasAlpha;
645     if (QDirectFBScreen::isPremultiplied(image.format()))
646         blitFlags |= QDirectFBPaintEnginePrivate::Premultiplied;
647     d->prepareForBlit(blitFlags);
648     CLIPPED_PAINT(d->blit(r, imgSurface, sr));
649     if (release) {
650 #if (Q_DIRECTFB_VERSION >= 0x010000)
651         d->surface->ReleaseSource(d->surface);
652 #endif
653         imgSurface->Release(imgSurface);
654     }
655 #endif
656 }
657 
drawImage(const QPointF & p,const QImage & img)658 void QDirectFBPaintEngine::drawImage(const QPointF &p, const QImage &img)
659 {
660     drawImage(QRectF(p, img.size()), img, img.rect());
661 }
662 
drawPixmap(const QRectF & r,const QPixmap & pixmap,const QRectF & sr)663 void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap,
664                                       const QRectF &sr)
665 {
666     Q_D(QDirectFBPaintEngine);
667 
668     if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) {
669         RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr);
670         d->lock();
671         QRasterPaintEngine::drawPixmap(r, pixmap, sr);
672     } else {
673         QPixmapData *data = pixmap.pixmapData();
674         Q_ASSERT(data->classId() == QPixmapData::DirectFBClass);
675         QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data);
676         if (!d->supportedComposition
677             || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
678             || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip)
679             || (!d->supportsStretchBlit() && state()->matrix.mapRect(r).size() != sr.size())) {
680             RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr);
681             const QImage *img = dfbData->buffer();
682             d->lock();
683             QRasterPaintEngine::drawImage(r, *img, sr);
684         } else {
685             QDirectFBPaintEnginePrivate::unlock(dfbData);
686             IDirectFBSurface *s = dfbData->directFBSurface();
687             uint blitFlags = 0;
688             if (pixmap.hasAlphaChannel())
689                 blitFlags |= QDirectFBPaintEnginePrivate::HasAlpha;
690             if (QDirectFBScreen::isPremultiplied(dfbData->pixelFormat()))
691                 blitFlags |= QDirectFBPaintEnginePrivate::Premultiplied;
692 
693             d->prepareForBlit(blitFlags);
694             CLIPPED_PAINT(d->blit(r, s, sr));
695         }
696     }
697 }
698 
drawPixmap(const QPointF & p,const QPixmap & pm)699 void QDirectFBPaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm)
700 {
701     drawPixmap(QRectF(p, pm.size()), pm, pm.rect());
702 }
703 
drawTiledPixmap(const QRectF & r,const QPixmap & pixmap,const QPointF & offset)704 void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r,
705                                            const QPixmap &pixmap,
706                                            const QPointF &offset)
707 {
708     Q_D(QDirectFBPaintEngine);
709     if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) {
710         RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset);
711         d->lock();
712         QRasterPaintEngine::drawTiledPixmap(r, pixmap, offset);
713     } else if (!d->supportedComposition
714                || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
715                || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip)
716                || (!d->supportsStretchBlit() && state()->matrix.isScaling())) {
717         RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset);
718         QPixmapData *pixmapData = pixmap.pixmapData();
719         Q_ASSERT(pixmapData->classId() == QPixmapData::DirectFBClass);
720         QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(pixmapData);
721         const QImage *img = dfbData->buffer();
722         d->lock();
723         QRasterPixmapData *data = new QRasterPixmapData(QPixmapData::PixmapType);
724         data->fromImage(*img, Qt::AutoColor);
725         const QPixmap pix(data);
726         QRasterPaintEngine::drawTiledPixmap(r, pix, offset);
727     } else {
728         QTransform transform(state()->matrix);
729         CLIPPED_PAINT(d->drawTiledPixmap(r, pixmap, offset, transform));
730     }
731 }
732 
733 
stroke(const QVectorPath & path,const QPen & pen)734 void QDirectFBPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
735 {
736     RASTERFALLBACK(STROKE_PATH, path, VOID_ARG(), VOID_ARG());
737     Q_D(QDirectFBPaintEngine);
738     d->lock();
739     QRasterPaintEngine::stroke(path, pen);
740 }
741 
drawPath(const QPainterPath & path)742 void QDirectFBPaintEngine::drawPath(const QPainterPath &path)
743 {
744     RASTERFALLBACK(DRAW_PATH, path, VOID_ARG(), VOID_ARG());
745     Q_D(QDirectFBPaintEngine);
746     d->lock();
747     QRasterPaintEngine::drawPath(path);
748 }
749 
drawPoints(const QPointF * points,int pointCount)750 void QDirectFBPaintEngine::drawPoints(const QPointF *points, int pointCount)
751 {
752     Q_D(QDirectFBPaintEngine);
753 
754     const QPen &pen = state()->pen;
755     if (!d->supportedPen
756         || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
757         || !d->supportedComposition) {
758         RASTERFALLBACK(DRAW_POINTS, pointCount, VOID_ARG(), VOID_ARG());
759         d->lock();
760         QRasterPaintEngine::drawPoints(points, pointCount);
761         return;
762     }
763 
764     if (pen.style() != Qt::NoPen && d->prepareForDraw(pen.color())) {
765         CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawPoints<QPointF>)(points, pointCount, state()->matrix, d->surface));
766     }
767 }
768 
drawPoints(const QPoint * points,int pointCount)769 void QDirectFBPaintEngine::drawPoints(const QPoint *points, int pointCount)
770 {
771     Q_D(QDirectFBPaintEngine);
772 
773     const QPen &pen = state()->pen;
774     if (!d->supportedPen
775         || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
776         || !d->supportedComposition) {
777         RASTERFALLBACK(DRAW_POINTS, pointCount, VOID_ARG(), VOID_ARG());
778         d->lock();
779         QRasterPaintEngine::drawPoints(points, pointCount);
780         return;
781     }
782 
783     if (pen.style() != Qt::NoPen && d->prepareForDraw(pen.color())) {
784         CLIPPED_PAINT(QT_PREPEND_NAMESPACE(drawPoints<QPoint>)(points, pointCount, state()->matrix, d->surface));
785     }
786 }
787 
drawEllipse(const QRectF & rect)788 void QDirectFBPaintEngine::drawEllipse(const QRectF &rect)
789 {
790     RASTERFALLBACK(DRAW_ELLIPSE, rect, VOID_ARG(), VOID_ARG());
791     Q_D(QDirectFBPaintEngine);
792     d->lock();
793     QRasterPaintEngine::drawEllipse(rect);
794 }
795 
drawPolygon(const QPointF * points,int pointCount,PolygonDrawMode mode)796 void QDirectFBPaintEngine::drawPolygon(const QPointF *points, int pointCount,
797                                        PolygonDrawMode mode)
798 {
799     RASTERFALLBACK(DRAW_POLYGON, pointCount, mode, VOID_ARG());
800     Q_D(QDirectFBPaintEngine);
801     d->lock();
802     QRasterPaintEngine::drawPolygon(points, pointCount, mode);
803 }
804 
drawPolygon(const QPoint * points,int pointCount,PolygonDrawMode mode)805 void QDirectFBPaintEngine::drawPolygon(const QPoint *points, int pointCount,
806                                        PolygonDrawMode mode)
807 {
808     RASTERFALLBACK(DRAW_POLYGON, pointCount, mode, VOID_ARG());
809     Q_D(QDirectFBPaintEngine);
810     d->lock();
811     QRasterPaintEngine::drawPolygon(points, pointCount, mode);
812 }
813 
drawTextItem(const QPointF & p,const QTextItem & textItem)814 void QDirectFBPaintEngine::drawTextItem(const QPointF &p,
815                                         const QTextItem &textItem)
816 {
817     RASTERFALLBACK(DRAW_TEXT, p, textItem.text(), VOID_ARG());
818     Q_D(QDirectFBPaintEngine);
819     d->lock();
820     QRasterPaintEngine::drawTextItem(p, textItem);
821 }
822 
fill(const QVectorPath & path,const QBrush & brush)823 void QDirectFBPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
824 {
825     if (brush.style() == Qt::NoBrush)
826         return;
827 
828     if (path.elementCount() == 5 && path.shape() == QVectorPath::RectangleHint) {
829         const QPainterPath rectPath = path.convertToPainterPath();
830         if (rectPath.elementAt(0).type == QPainterPath::MoveToElement
831             && rectPath.elementAt(1).type == QPainterPath::LineToElement
832             && rectPath.elementAt(2).type == QPainterPath::LineToElement
833             && rectPath.elementAt(3).type == QPainterPath::LineToElement
834             && rectPath.elementAt(4).type == QPainterPath::LineToElement) {
835 
836             const qreal *points = path.points();
837             if (points[1] == points[3]
838                 && points[2] == points[4]
839                 && points[5] == points[7]
840                 && points[6] == points[0]) {
841                 QRectF rect( points[0], points[1], points[4], points[5] );
842 
843                 fillRect( rect, brush );
844                 return;
845             }
846         }
847     }
848 
849     RASTERFALLBACK(FILL_PATH, path, brush, VOID_ARG());
850     Q_D(QDirectFBPaintEngine);
851     d->lock();
852     QRasterPaintEngine::fill(path, brush);
853 }
854 
drawRoundedRect(const QRectF & rect,qreal xrad,qreal yrad,Qt::SizeMode mode)855 void QDirectFBPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode)
856 {
857     RASTERFALLBACK(DRAW_ROUNDED_RECT, rect, xrad, yrad);
858     Q_D(QDirectFBPaintEngine);
859     d->lock();
860     QRasterPaintEngine::drawRoundedRect(rect, xrad, yrad, mode);
861 }
862 
drawStaticTextItem(QStaticTextItem * item)863 void QDirectFBPaintEngine::drawStaticTextItem(QStaticTextItem *item)
864 {
865     RASTERFALLBACK(DRAW_STATICTEXT, item, VOID_ARG(), VOID_ARG());
866     Q_D(QDirectFBPaintEngine);
867     d->lock();
868     QRasterPaintEngine::drawStaticTextItem(item);
869 }
870 
fillRect(const QRectF & rect,const QBrush & brush)871 void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
872 {
873     Q_D(QDirectFBPaintEngine);
874     if (brush.style() == Qt::NoBrush)
875         return;
876     if (d->clipType != QDirectFBPaintEnginePrivate::ComplexClip) {
877         switch (brush.style()) {
878         case Qt::SolidPattern: {
879             const QColor color = brush.color();
880             if (!color.isValid())
881                 return;
882 
883             if (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported
884                 || !d->supportedComposition) {
885                 break;
886             }
887             if (d->prepareForDraw(color)) {
888                 const QRect r = state()->matrix.mapRect(rect).toRect();
889                 CLIPPED_PAINT(d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height()));
890             }
891             return; }
892 
893         case Qt::TexturePattern: {
894             const QPointF &brushOrigin = state()->brushOrigin;
895             const QTransform stateTransform = state()->matrix;
896             QTransform transform(stateTransform);
897             transform.translate(brushOrigin.x(), brushOrigin.y());
898             transform = brush.transform() * transform;
899             if (!d->supportedComposition
900                 || (QDirectFBPaintEnginePrivate::getTransformationType(transform) & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
901                 || (!d->supportsStretchBlit() && transform.isScaling())) {
902                 break;
903             }
904 
905             const QPixmap texture = brush.texture();
906             if (texture.pixmapData()->classId() != QPixmapData::DirectFBClass)
907                 break;
908 
909             CLIPPED_PAINT(d->drawTiledPixmap(stateTransform.mapRect(rect), texture, rect.topLeft() - brushOrigin, transform));
910             return; }
911         default:
912             break;
913         }
914     }
915     RASTERFALLBACK(FILL_RECT, rect, brush, VOID_ARG());
916     d->lock();
917     QRasterPaintEngine::fillRect(rect, brush);
918 }
919 
fillRect(const QRectF & rect,const QColor & color)920 void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QColor &color)
921 {
922     if (!color.isValid())
923         return;
924     Q_D(QDirectFBPaintEngine);
925     if ((d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)
926         || (d->clipType == QDirectFBPaintEnginePrivate::ComplexClip)
927         || !d->supportedComposition) {
928         RASTERFALLBACK(FILL_RECT, rect, color, VOID_ARG());
929         d->lock();
930         QRasterPaintEngine::fillRect(rect, color);
931     } else if (d->prepareForDraw(color)) {
932         const QRect r = state()->matrix.mapRect(rect).toRect();
933         CLIPPED_PAINT(d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height()));
934     }
935 }
936 
drawBufferSpan(const uint * buffer,int bufsize,int x,int y,int length,uint const_alpha)937 void QDirectFBPaintEngine::drawBufferSpan(const uint *buffer, int bufsize,
938                                           int x, int y, int length,
939                                           uint const_alpha)
940 {
941     Q_D(QDirectFBPaintEngine);
942     IDirectFBSurface *src = d->surfaceCache->getSurface(buffer, bufsize);
943     // ### how does this play with setDFBColor
944     src->SetColor(src, 0, 0, 0, const_alpha);
945     const DFBRectangle rect = { 0, 0, length, 1 };
946     d->surface->Blit(d->surface, src, &rect, x, y);
947 }
948 
949 #ifdef QT_DIRECTFB_IMAGECACHE
cachedImageCleanupHook(qint64 key)950 static void cachedImageCleanupHook(qint64 key)
951 {
952     delete imageCache.take(key);
953 }
initImageCache(int size)954 void QDirectFBPaintEngine::initImageCache(int size)
955 {
956     Q_ASSERT(size >= 0);
957     imageCache.setMaxCost(size);
958     QImagePixmapCleanupHooks::instance()->addImageHook(cachedImageCleanupHook);
959 }
960 
961 #endif // QT_DIRECTFB_IMAGECACHE
962 
963 // ---- QDirectFBPaintEnginePrivate ----
964 
QDirectFBPaintEnginePrivate(QDirectFBPaintEngine * p)965 QDirectFBPaintEnginePrivate::QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p)
966     : surface(0), antialiased(false), supportedBrush(false), supportedPen(false),
967       transformationType(0), opacity(255),
968       clipType(ClipUnset), dfbDevice(0),
969       supportedComposition(false), isPremultiplied(false), inClip(false), engine(p)
970 {
971     fb = QDirectFBScreen::instance()->dfb();
972     surfaceCache = new SurfaceCache;
973 }
974 
~QDirectFBPaintEnginePrivate()975 QDirectFBPaintEnginePrivate::~QDirectFBPaintEnginePrivate()
976 {
977     delete surfaceCache;
978 }
979 
lock()980 void QDirectFBPaintEnginePrivate::lock()
981 {
982     // We will potentially get a new pointer to the buffer after a
983     // lock so we need to call the base implementation of prepare so
984     // it updates its rasterBuffer to point to the new buffer address.
985     Q_ASSERT(dfbDevice);
986     if (dfbDevice->lockSurface(DSLF_READ|DSLF_WRITE)) {
987         prepare(dfbDevice);
988     }
989 }
990 
unlock()991 void QDirectFBPaintEnginePrivate::unlock()
992 {
993     Q_ASSERT(dfbDevice);
994 #ifdef QT_DIRECTFB_SUBSURFACE
995     dfbDevice->syncPending = true;
996 #else
997     QDirectFBPaintEnginePrivate::unlock(dfbDevice);
998 #endif
999 }
1000 
unlock(QDirectFBPaintDevice * device)1001 void QDirectFBPaintEnginePrivate::unlock(QDirectFBPaintDevice *device)
1002 {
1003 #ifdef QT_NO_DIRECTFB_SUBSURFACE
1004     Q_ASSERT(device);
1005     device->unlockSurface();
1006 #else
1007     Q_UNUSED(device);
1008 #endif
1009 }
1010 
setBrush(const QBrush & brush)1011 void QDirectFBPaintEnginePrivate::setBrush(const QBrush &brush)
1012 {
1013      supportedBrush = (brush.style() == Qt::NoBrush) || (brush.style() == Qt::SolidPattern && !antialiased);
1014 }
1015 
setCompositionMode(QPainter::CompositionMode mode)1016 void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode mode)
1017 {
1018     if (!surface)
1019         return;
1020 
1021     static const bool forceRasterFallBack = qgetenv("QT_DIRECTFB_FORCE_RASTER").toInt() > 0;
1022     if (forceRasterFallBack) {
1023         supportedComposition = false;
1024         return;
1025     }
1026 
1027     supportedComposition = true;
1028     switch (mode) {
1029     case QPainter::CompositionMode_Clear:
1030         surface->SetPorterDuff(surface, DSPD_CLEAR);
1031         break;
1032     case QPainter::CompositionMode_Source:
1033         surface->SetPorterDuff(surface, DSPD_SRC);
1034         break;
1035     case QPainter::CompositionMode_SourceOver:
1036         surface->SetPorterDuff(surface, DSPD_SRC_OVER);
1037         break;
1038     case QPainter::CompositionMode_DestinationOver:
1039         surface->SetPorterDuff(surface, DSPD_DST_OVER);
1040         break;
1041     case QPainter::CompositionMode_SourceIn:
1042         surface->SetPorterDuff(surface, DSPD_SRC_IN);
1043         break;
1044     case QPainter::CompositionMode_DestinationIn:
1045         surface->SetPorterDuff(surface, DSPD_DST_IN);
1046         break;
1047     case QPainter::CompositionMode_SourceOut:
1048         surface->SetPorterDuff(surface, DSPD_SRC_OUT);
1049         break;
1050     case QPainter::CompositionMode_DestinationOut:
1051         surface->SetPorterDuff(surface, DSPD_DST_OUT);
1052         break;
1053     case QPainter::CompositionMode_Destination:
1054         surface->SetSrcBlendFunction(surface, DSBF_ZERO);
1055         surface->SetDstBlendFunction(surface, DSBF_ONE);
1056         break;
1057 #if (Q_DIRECTFB_VERSION >= 0x010000)
1058     case QPainter::CompositionMode_SourceAtop:
1059         surface->SetPorterDuff(surface, DSPD_SRC_ATOP);
1060         break;
1061     case QPainter::CompositionMode_DestinationAtop:
1062         surface->SetPorterDuff(surface, DSPD_DST_ATOP);
1063         break;
1064     case QPainter::CompositionMode_Plus:
1065         surface->SetPorterDuff(surface, DSPD_ADD);
1066         break;
1067     case QPainter::CompositionMode_Xor:
1068         surface->SetPorterDuff(surface, DSPD_XOR);
1069         break;
1070 #endif
1071     default:
1072         supportedComposition = false;
1073         break;
1074     }
1075 }
1076 
setPen(const QPen & pen)1077 void QDirectFBPaintEnginePrivate::setPen(const QPen &pen)
1078 {
1079     if (pen.style() == Qt::NoPen) {
1080         supportedPen = true;
1081     } else if (pen.style() == Qt::SolidLine
1082                && !antialiased
1083                && pen.brush().style() == Qt::SolidPattern
1084                && pen.widthF() <= 1.0
1085                && (transformationType < QTransform::TxScale || pen.isCosmetic())) {
1086         supportedPen = true;
1087     } else {
1088         supportedPen = false;
1089     }
1090 }
1091 
setTransform(const QTransform & transform)1092 void QDirectFBPaintEnginePrivate::setTransform(const QTransform &transform)
1093 {
1094     transformationType = getTransformationType(transform);
1095     setPen(engine->state()->pen);
1096 }
1097 
setRenderHints(QPainter::RenderHints hints)1098 void QDirectFBPaintEnginePrivate::setRenderHints(QPainter::RenderHints hints)
1099 {
1100     const bool old = antialiased;
1101     antialiased = bool(hints & QPainter::Antialiasing);
1102     if (old != antialiased) {
1103         setPen(engine->state()->pen);
1104     }
1105 }
1106 
prepareForBlit(uint flags)1107 void QDirectFBPaintEnginePrivate::prepareForBlit(uint flags)
1108 {
1109     DFBSurfaceBlittingFlags blittingFlags = DSBLIT_NOFX;
1110 
1111 #if (Q_DIRECTFB_VERSION >= 0x010403)
1112     if (transformationType & Matrix_NegativeScaleX)
1113         blittingFlags |= DSBLIT_FLIP_HORIZONTAL;
1114 
1115     if (transformationType & Matrix_NegativeScaleY)
1116         blittingFlags |= DSBLIT_FLIP_VERTICAL;
1117 #endif
1118 
1119     if (flags & HasAlpha)
1120         blittingFlags |= DSBLIT_BLEND_ALPHACHANNEL;
1121 
1122     if (opacity != 255) {
1123         blittingFlags |= DSBLIT_BLEND_COLORALPHA;
1124         surface->SetColor(surface, 0xff, 0xff, 0xff, opacity);
1125     }
1126 
1127     if (flags & Premultiplied) {
1128         if (blittingFlags & DSBLIT_BLEND_COLORALPHA)
1129             blittingFlags |= DSBLIT_SRC_PREMULTCOLOR;
1130     } else {
1131         if (blittingFlags & (DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_BLEND_COLORALPHA))
1132             blittingFlags |= DSBLIT_SRC_PREMULTIPLY;
1133     }
1134 
1135     surface->SetBlittingFlags(surface, blittingFlags);
1136 }
1137 
ALPHA_MUL(uint x,uint a)1138 static inline uint ALPHA_MUL(uint x, uint a)
1139 {
1140     uint t = x * a;
1141     t = ((t + (t >> 8) + 0x80) >> 8) & 0xff;
1142     return t;
1143 }
1144 
prepareForDraw(const QColor & color)1145 bool QDirectFBPaintEnginePrivate::prepareForDraw(const QColor &color)
1146 {
1147     Q_ASSERT(surface);
1148     Q_ASSERT(supportedComposition);
1149     const quint8 alpha = (opacity == 255 ?
1150                           color.alpha() : ALPHA_MUL(color.alpha(), opacity));
1151     QColor col;
1152     if (isPremultiplied) {
1153         col = QColor(ALPHA_MUL(color.red(), alpha),
1154                      ALPHA_MUL(color.green(), alpha),
1155                      ALPHA_MUL(color.blue(), alpha),
1156                      alpha);
1157     } else {
1158         col = QColor(color.red(), color.green(), color.blue(), alpha);
1159     }
1160     surface->SetColor(surface, col.red(), col.green(), col.blue(), col.alpha());
1161 
1162     bool blend = false;
1163 
1164     switch (engine->state()->composition_mode) {
1165     case QPainter::CompositionMode_Clear:
1166     case QPainter::CompositionMode_Source:
1167         break;
1168     case QPainter::CompositionMode_SourceOver:
1169         if (alpha == 0)
1170             return false;
1171 
1172         if (alpha != 255)
1173             blend = true;
1174         break;
1175     default:
1176         blend = true;
1177         break;
1178     }
1179 
1180     surface->SetDrawingFlags(surface, blend ? DSDRAW_BLEND : DSDRAW_NOFX);
1181 
1182     return true;
1183 }
1184 
getSurface(const QImage & img,bool * release)1185 IDirectFBSurface *QDirectFBPaintEnginePrivate::getSurface(const QImage &img, bool *release)
1186 {
1187 #ifdef QT_NO_DIRECTFB_IMAGECACHE
1188     *release = true;
1189     return QDirectFBScreen::instance()->createDFBSurface(img, img.format(), QDirectFBScreen::DontTrackSurface);
1190 #else
1191     const qint64 key = img.cacheKey();
1192     *release = false;
1193     if (imageCache.contains(key)) {
1194         return imageCache[key]->surface;
1195     }
1196 
1197     const int cost = cacheCost(img);
1198     const bool cache = cost <= imageCache.maxCost();
1199     QDirectFBScreen *screen = QDirectFBScreen::instance();
1200     const QImage::Format format = (img.format() == screen->alphaPixmapFormat() || QDirectFBPixmapData::hasAlphaChannel(img)
1201                                    ? screen->alphaPixmapFormat() : screen->pixelFormat());
1202 
1203     IDirectFBSurface *surface = screen->createDFBSurface(img, format,
1204                                                          cache
1205                                                          ? QDirectFBScreen::TrackSurface
1206                                                          : QDirectFBScreen::DontTrackSurface);
1207     if (cache) {
1208         CachedImage *cachedImage = new CachedImage;
1209         const_cast<QImage&>(img).data_ptr()->is_cached = true;
1210         cachedImage->surface = surface;
1211         imageCache.insert(key, cachedImage, cost);
1212     } else {
1213         *release = true;
1214     }
1215     return surface;
1216 #endif
1217 }
1218 
1219 
blit(const QRectF & dest,IDirectFBSurface * s,const QRectF & src)1220 void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s, const QRectF &src)
1221 {
1222     const QRect sr = src.toRect();
1223     const QRect dr = engine->state()->matrix.mapRect(dest).toRect();
1224     if (dr.isEmpty())
1225         return;
1226     const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() };
1227     DFBResult result;
1228 
1229     if (dr.size() == sr.size()) {
1230         result = surface->Blit(surface, s, &sRect, dr.x(), dr.y());
1231     } else {
1232         Q_ASSERT(supportsStretchBlit());
1233         const DFBRectangle dRect = { dr.x(), dr.y(), dr.width(), dr.height() };
1234         result = surface->StretchBlit(surface, s, &sRect, &dRect);
1235     }
1236     if (result != DFB_OK)
1237         DirectFBError("QDirectFBPaintEngine::drawPixmap()", result);
1238 }
1239 
fixCoord(qreal rect_pos,qreal pixmapSize,qreal offset)1240 static inline qreal fixCoord(qreal rect_pos, qreal pixmapSize, qreal offset)
1241 {
1242     qreal pos = rect_pos - offset;
1243     while (pos > rect_pos)
1244         pos -= pixmapSize;
1245     while (pos + pixmapSize < rect_pos)
1246         pos += pixmapSize;
1247     return pos;
1248 }
1249 
drawTiledPixmap(const QRectF & dest,const QPixmap & pixmap,const QPointF & off,const QTransform & pixmapTransform)1250 void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap,
1251                                                   const QPointF &off, const QTransform &pixmapTransform)
1252 {
1253     const QTransform &transform = engine->state()->matrix;
1254     Q_ASSERT(!(getTransformationType(transform) & Matrix_BlitsUnsupported) &&
1255              !(getTransformationType(pixmapTransform) & Matrix_BlitsUnsupported));
1256     const QRect destinationRect = dest.toRect();
1257     QRect newClip = destinationRect;
1258     if (!currentClip.isEmpty())
1259         newClip &= currentClip;
1260 
1261     if (newClip.isNull())
1262         return;
1263 
1264     const DFBRegion clip = {
1265         newClip.x(),
1266         newClip.y(),
1267         newClip.right(),
1268         newClip.bottom()
1269     };
1270     surface->SetClip(surface, &clip);
1271 
1272     QPointF offset = off;
1273     Q_ASSERT(transform.type() <= QTransform::TxScale);
1274     QPixmapData *data = pixmap.pixmapData();
1275     Q_ASSERT(data->classId() == QPixmapData::DirectFBClass);
1276     QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data);
1277     IDirectFBSurface *sourceSurface = dfbData->directFBSurface();
1278     uint blitFlags = 0;
1279     if (dfbData->hasAlphaChannel())
1280         blitFlags |= HasAlpha;
1281     if (QDirectFBScreen::isPremultiplied(dfbData->pixelFormat()))
1282         blitFlags |= Premultiplied;
1283     prepareForBlit(blitFlags);
1284     QDirectFBPaintEnginePrivate::unlock(dfbData);
1285     const QSize pixmapSize = dfbData->size();
1286     if (transform.isScaling() || pixmapTransform.isScaling()) {
1287         Q_ASSERT(supportsStretchBlit());
1288         Q_ASSERT(qMin(transform.m11(), transform.m22()) >= 0);
1289         offset.rx() *= transform.m11();
1290         offset.ry() *= transform.m22();
1291 
1292         const QSizeF mappedSize(pixmapSize.width() * pixmapTransform.m11(), pixmapSize.height() * pixmapTransform.m22());
1293         qreal y = fixCoord(destinationRect.y(), mappedSize.height(), offset.y());
1294         const qreal startX = fixCoord(destinationRect.x(), mappedSize.width(), offset.x());
1295         while (y <= destinationRect.bottom()) {
1296             qreal x = startX;
1297             while (x <= destinationRect.right()) {
1298                 const DFBRectangle destination = { qRound(x), qRound(y), mappedSize.width(), mappedSize.height() };
1299                 surface->StretchBlit(surface, sourceSurface, 0, &destination);
1300                 x += mappedSize.width();
1301             }
1302             y += mappedSize.height();
1303         }
1304     } else {
1305         qreal y = fixCoord(destinationRect.y(), pixmapSize.height(), offset.y());
1306         const qreal startX = fixCoord(destinationRect.x(), pixmapSize.width(), offset.x());
1307         int horizontal = qMax(1, destinationRect.width() / pixmapSize.width()) + 1;
1308         if (startX != destinationRect.x())
1309             ++horizontal;
1310         int vertical = qMax(1, destinationRect.height() / pixmapSize.height()) + 1;
1311         if (y != destinationRect.y())
1312             ++vertical;
1313 
1314         const int maxCount = (vertical * horizontal);
1315         QVarLengthArray<DFBRectangle, 16> sourceRects(maxCount);
1316         QVarLengthArray<DFBPoint, 16> points(maxCount);
1317 
1318         int i = 0;
1319         while (y <= destinationRect.bottom()) {
1320             Q_ASSERT(i < maxCount);
1321             qreal x = startX;
1322             while (x <= destinationRect.right()) {
1323                 points[i].x = qRound(x);
1324                 points[i].y = qRound(y);
1325                 sourceRects[i].x = 0;
1326                 sourceRects[i].y = 0;
1327                 sourceRects[i].w = int(pixmapSize.width());
1328                 sourceRects[i].h = int(pixmapSize.height());
1329                 x += pixmapSize.width();
1330                 ++i;
1331             }
1332             y += pixmapSize.height();
1333         }
1334         surface->BatchBlit(surface, sourceSurface, sourceRects.constData(), points.constData(), i);
1335     }
1336 
1337     if (currentClip.isEmpty()) {
1338         surface->SetClip(surface, 0);
1339     } else {
1340         const DFBRegion clip = {
1341             currentClip.x(),
1342             currentClip.y(),
1343             currentClip.right(),
1344             currentClip.bottom()
1345         };
1346         surface->SetClip(surface, &clip);
1347     }
1348 }
1349 
updateClip()1350 void QDirectFBPaintEnginePrivate::updateClip()
1351 {
1352     Q_ASSERT(surface);
1353     currentClip = QRect();
1354     const QClipData *clipData = clip();
1355     if (!clipData || !clipData->enabled) {
1356         surface->SetClip(surface, NULL);
1357         clipType = NoClip;
1358     } else if (clipData->hasRectClip) {
1359         const DFBRegion r = {
1360             clipData->clipRect.x(),
1361             clipData->clipRect.y(),
1362             clipData->clipRect.right(),
1363             clipData->clipRect.bottom()
1364         };
1365         surface->SetClip(surface, &r);
1366         currentClip = clipData->clipRect.normalized();
1367         // ### is this guaranteed to always be normalized?
1368         clipType = RectClip;
1369     } else if (clipData->hasRegionClip) {
1370         clipType = RegionClip;
1371     } else {
1372         clipType = ComplexClip;
1373     }
1374 }
1375 
supportsStretchBlit() const1376 bool QDirectFBPaintEnginePrivate::supportsStretchBlit() const
1377 {
1378 #ifdef QT_DIRECTFB_STRETCHBLIT
1379     DFBGraphicsDeviceDescription desc;
1380 
1381     fb->GetDeviceDescription(fb, &desc);
1382 
1383     return !(engine->state()->renderHints & QPainter::SmoothPixmapTransform)
1384                || (desc.acceleration_mask & DFXL_STRETCHBLIT);
1385 #else
1386     return false;
1387 #endif
1388 }
1389 
1390 
systemStateChanged()1391 void QDirectFBPaintEnginePrivate::systemStateChanged()
1392 {
1393     QRasterPaintEnginePrivate::systemStateChanged();
1394     updateClip();
1395 }
1396 
getSurface(const uint * buf,int size)1397 IDirectFBSurface *SurfaceCache::getSurface(const uint *buf, int size)
1398 {
1399     if (buffer == buf && bufsize == size)
1400         return surface;
1401 
1402     clear();
1403 
1404     const DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(buf, size);
1405     surface = QDirectFBScreen::instance()->createDFBSurface(description, QDirectFBScreen::TrackSurface, 0);
1406     if (!surface)
1407         qWarning("QDirectFBPaintEngine: SurfaceCache: Unable to create surface");
1408 
1409     buffer = const_cast<uint*>(buf);
1410     bufsize = size;
1411 
1412     return surface;
1413 }
1414 
clear()1415 void SurfaceCache::clear()
1416 {
1417     if (surface && QDirectFBScreen::instance())
1418         QDirectFBScreen::instance()->releaseDFBSurface(surface);
1419     surface = 0;
1420     buffer = 0;
1421     bufsize = 0;
1422 }
1423 
1424 
map(const QTransform & transform,const QRect & rect)1425 static inline QRect map(const QTransform &transform, const QRect &rect) { return transform.mapRect(rect); }
map(const QTransform & transform,const QRectF & rect)1426 static inline QRect map(const QTransform &transform, const QRectF &rect) { return transform.mapRect(rect).toRect(); }
map(const QTransform & transform,const QLine & line)1427 static inline QLine map(const QTransform &transform, const QLine &line) { return transform.map(line); }
map(const QTransform & transform,const QLineF & line)1428 static inline QLine map(const QTransform &transform, const QLineF &line) { return transform.map(line).toLine(); }
map(const QTransform & transform,const QPoint & point)1429 static inline QPoint map(const QTransform &transform, const QPoint &point) { return transform.map(point); }
map(const QTransform & transform,const QPointF & point)1430 static inline QPoint map(const QTransform &transform, const QPointF &point) { return transform.map(point).toPoint(); }
1431 
1432 template <class T>
drawPoints(const T * points,int n,const QTransform & transform,IDirectFBSurface * surface)1433 static inline void drawPoints(const T *points, int n, const QTransform &transform, IDirectFBSurface *surface)
1434 {
1435     if (n == 1) {
1436         const QPoint p = map(transform, points[0]);
1437         surface->FillRectangle(surface, p.x(), p.y(), 1, 1);
1438     } else {
1439         QVarLengthArray<DFBRectangle, 32> rectArray(n);
1440         for (int i=0; i<n; ++i) {
1441             const QPoint p = map(transform, points[i]);
1442             rectArray[i].x = p.x();
1443             rectArray[i].y = p.y();
1444             rectArray[i].w = 1;
1445             rectArray[i].h = 1;
1446         }
1447         surface->FillRectangles(surface, rectArray.constData(), n);
1448     }
1449 }
1450 
1451 template <class T>
drawLines(const T * lines,int n,const QTransform & transform,IDirectFBSurface * surface)1452 static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface)
1453 {
1454     if (n == 1) {
1455         const QLine l = map(transform, lines[0]);
1456         surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2());
1457     } else {
1458         QVarLengthArray<DFBRegion, 32> lineArray(n);
1459         for (int i=0; i<n; ++i) {
1460             const QLine l = map(transform, lines[i]);
1461             lineArray[i].x1 = l.x1();
1462             lineArray[i].y1 = l.y1();
1463             lineArray[i].x2 = l.x2();
1464             lineArray[i].y2 = l.y2();
1465         }
1466         surface->DrawLines(surface, lineArray.constData(), n);
1467     }
1468 }
1469 
1470 template <class T>
fillRects(const T * rects,int n,const QTransform & transform,IDirectFBSurface * surface)1471 static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface)
1472 {
1473     if (n == 1) {
1474         const QRect r = map(transform, rects[0]);
1475         surface->FillRectangle(surface, r.x(), r.y(), r.width(), r.height());
1476     } else {
1477         QVarLengthArray<DFBRectangle, 32> rectArray(n);
1478         for (int i=0; i<n; ++i) {
1479             const QRect r = map(transform, rects[i]);
1480             rectArray[i].x = r.x();
1481             rectArray[i].y = r.y();
1482             rectArray[i].w = r.width();
1483             rectArray[i].h = r.height();
1484         }
1485         surface->FillRectangles(surface, rectArray.constData(), n);
1486     }
1487 }
1488 
1489 template <class T>
drawRects(const T * rects,int n,const QTransform & transform,IDirectFBSurface * surface)1490 static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface)
1491 {
1492     for (int i=0; i<n; ++i) {
1493         const QRect r = map(transform, rects[i]);
1494         surface->DrawRectangle(surface, r.x(), r.y(), r.width(), r.height());
1495     }
1496 }
1497 
ptr(const T & t)1498 template <typename T> inline const T *ptr(const T &t) { return &t; }
ptr(const bool &)1499 template <> inline const bool* ptr<bool>(const bool &) { return 0; }
1500 template <typename device, typename T1, typename T2, typename T3>
rasterFallbackWarn(const char * msg,const char * func,const device * dev,QDirectFBPaintEnginePrivate * priv,const char * nameOne,const T1 & one,const char * nameTwo,const T2 & two,const char * nameThree,const T3 & three)1501 static void rasterFallbackWarn(const char *msg, const char *func, const device *dev,
1502                                QDirectFBPaintEnginePrivate *priv,
1503                                const char *nameOne, const T1 &one,
1504                                const char *nameTwo, const T2 &two,
1505                                const char *nameThree, const T3 &three)
1506 {
1507     QString out;
1508     QDebug dbg(&out);
1509 
1510 
1511     dbg << "***";
1512 
1513 
1514     dbg << msg << (QByteArray(func) + "()")  << "painting on";
1515     if (dev->devType() == QInternal::Widget) {
1516         dbg << static_cast<const QWidget*>(dev);
1517     } else {
1518         dbg << dev << "of type" << dev->devType();
1519     }
1520 
1521     dbg << "\n\t";
1522 
1523 
1524     dbg << ((priv->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported) ? "*" : "") << QString::fromLatin1("transformationType 0x%1").arg(priv->transformationType, 3, 16, QLatin1Char('0'));
1525 
1526     dbg << priv->engine->state()->matrix;
1527 
1528     dbg << "\n\t";
1529 
1530 
1531 
1532     dbg << (priv->supportedBrush ? "" : "*") << "supportedBrush" << priv->supportedBrush;
1533 
1534     dbg << priv->engine->state()->brush;
1535 
1536     dbg << "\n\t";
1537 
1538     const QGradient *gradient = priv->engine->state()->brush.gradient();
1539     if (gradient) {
1540         const QGradientStops &stops = gradient->stops();
1541 
1542         dbg << "gradient: " << *gradient;
1543         dbg << "stops: " << stops.count();
1544         dbg << "\n\t";
1545 
1546         for (int i=0; i<stops.count(); i++) {
1547             dbg << stops[i].first << stops[i].second;
1548         }
1549         dbg << "\n\t";
1550     }
1551 
1552 
1553     dbg << (priv->supportedPen ? "" : "*") << "supportedPen" << priv->supportedPen;
1554 
1555     dbg << priv->engine->state()->pen;
1556 
1557     dbg << "\n\t";
1558 
1559 
1560 
1561     dbg << (priv->clipType == QDirectFBPaintEnginePrivate::ComplexClip ? "*" : "") << "clipType" << priv->clipType;
1562 
1563     dbg << "\n\t";
1564 
1565 
1566     dbg << (priv->supportedComposition ? "" : "*") << "supportedComposition" << priv->supportedComposition;
1567 
1568     dbg << "\n\t";
1569 
1570 
1571     const T1 *t1 = ptr(one);
1572     const T2 *t2 = ptr(two);
1573     const T3 *t3 = ptr(three);
1574 
1575     if (t1) {
1576         dbg << nameOne << *t1;
1577         if (t2) {
1578             dbg << nameTwo << *t2;
1579             if (t3) {
1580                 dbg << nameThree << *t3;
1581             }
1582         }
1583     }
1584     qWarning("%s", qPrintable(out));
1585 }
1586 
1587 QT_END_NAMESPACE
1588 
1589 #endif // QT_NO_QWS_DIRECTFB
1590 
1591