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 ®ion, 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