source: trunk/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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