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