source: trunk/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.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: 19.2 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 "qdirectfbpixmap.h"
43
44#ifndef QT_NO_QWS_DIRECTFB
45
46#include "qdirectfbscreen.h"
47#include "qdirectfbpaintengine.h"
48
49#include <QtGui/qbitmap.h>
50#include <QtCore/qfile.h>
51#include <directfb.h>
52
53
54QT_BEGIN_NAMESPACE
55
56static int global_ser_no = 0;
57
58QDirectFBPixmapData::QDirectFBPixmapData(QDirectFBScreen *screen, PixelType pixelType)
59 : QPixmapData(pixelType, DirectFBClass), QDirectFBPaintDevice(screen),
60 alpha(false)
61{
62 setSerialNumber(0);
63}
64
65QDirectFBPixmapData::~QDirectFBPixmapData()
66{
67}
68
69void QDirectFBPixmapData::resize(int width, int height)
70{
71 if (width <= 0 || height <= 0) {
72 invalidate();
73 return;
74 }
75
76 imageFormat = screen->pixelFormat();
77 dfbSurface = screen->createDFBSurface(QSize(width, height),
78 imageFormat,
79 QDirectFBScreen::TrackSurface);
80 d = QDirectFBScreen::depth(imageFormat);
81 alpha = false;
82 if (!dfbSurface) {
83 invalidate();
84 qWarning("QDirectFBPixmapData::resize(): Unable to allocate surface");
85 return;
86 }
87
88 w = width;
89 h = height;
90 is_null = (w <= 0 || h <= 0);
91 setSerialNumber(++global_ser_no);
92}
93
94#ifdef QT_DIRECTFB_OPAQUE_DETECTION
95// mostly duplicated from qimage.cpp (QImageData::checkForAlphaPixels)
96static bool checkForAlphaPixels(const QImage &img)
97{
98 const uchar *bits = img.bits();
99 const int bytes_per_line = img.bytesPerLine();
100 const uchar *end_bits = bits + bytes_per_line;
101 const int width = img.width();
102 const int height = img.height();
103 switch (img.format()) {
104 case QImage::Format_Indexed8:
105 return img.hasAlphaChannel();
106 case QImage::Format_ARGB32:
107 case QImage::Format_ARGB32_Premultiplied:
108 for (int y=0; y<height; ++y) {
109 for (int x=0; x<width; ++x) {
110 if ((((uint *)bits)[x] & 0xff000000) != 0xff000000) {
111 return true;
112 }
113 }
114 bits += bytes_per_line;
115 }
116 break;
117
118 case QImage::Format_ARGB8555_Premultiplied:
119 case QImage::Format_ARGB8565_Premultiplied:
120 for (int y=0; y<height; ++y) {
121 while (bits < end_bits) {
122 if (bits[0] != 0) {
123 return true;
124 }
125 bits += 3;
126 }
127 bits = end_bits;
128 end_bits += bytes_per_line;
129 }
130 break;
131
132 case QImage::Format_ARGB6666_Premultiplied:
133 for (int y=0; y<height; ++y) {
134 while (bits < end_bits) {
135 if ((bits[0] & 0xfc) != 0) {
136 return true;
137 }
138 bits += 3;
139 }
140 bits = end_bits;
141 end_bits += bytes_per_line;
142 }
143 break;
144
145 case QImage::Format_ARGB4444_Premultiplied:
146 for (int y=0; y<height; ++y) {
147 while (bits < end_bits) {
148 if ((bits[0] & 0xf0) != 0) {
149 return true;
150 }
151 bits += 2;
152 }
153 bits = end_bits;
154 end_bits += bytes_per_line;
155 }
156 break;
157
158 default:
159 break;
160 }
161
162 return false;
163}
164#endif // QT_DIRECTFB_OPAQUE_DETECTION
165
166bool QDirectFBPixmapData::hasAlphaChannel(const QImage &img, Qt::ImageConversionFlags flags)
167{
168 if (img.depth() == 1)
169 return true;
170#ifdef QT_DIRECTFB_OPAQUE_DETECTION
171 return ((flags & Qt::NoOpaqueDetection) ? img.hasAlphaChannel() : checkForAlphaPixels(img));
172#else
173 Q_UNUSED(flags);
174 return img.hasAlphaChannel();
175#endif
176}
177
178#ifdef QT_DIRECTFB_IMAGEPROVIDER
179bool QDirectFBPixmapData::fromFile(const QString &filename, const char *format,
180 Qt::ImageConversionFlags flags)
181{
182 if (!QFile::exists(filename))
183 return false;
184 if (flags == Qt::AutoColor) {
185 if (filename.startsWith(QLatin1Char(':'))) { // resource
186 QFile file(filename);
187 if (!file.open(QIODevice::ReadOnly))
188 return false;
189 const QByteArray data = file.readAll();
190 file.close();
191 return fromData(reinterpret_cast<const uchar*>(data.constData()), data.size(), format, flags);
192 } else {
193 DFBDataBufferDescription description;
194 description.flags = DBDESC_FILE;
195 const QByteArray fileNameData = filename.toLocal8Bit();
196 description.file = fileNameData.constData();
197 if (fromDataBufferDescription(description)) {
198 return true;
199 }
200 // fall back to Qt
201 }
202 }
203 return QPixmapData::fromFile(filename, format, flags);
204}
205
206bool QDirectFBPixmapData::fromData(const uchar *buffer, uint len, const char *format,
207 Qt::ImageConversionFlags flags)
208{
209 if (flags == Qt::AutoColor) {
210 DFBDataBufferDescription description;
211 description.flags = DBDESC_MEMORY;
212 description.memory.data = buffer;
213 description.memory.length = len;
214 if (fromDataBufferDescription(description))
215 return true;
216 // fall back to Qt
217 }
218 return QPixmapData::fromData(buffer, len, format, flags);
219}
220
221template <typename T> struct QDirectFBInterfaceCleanupHandler
222{
223 static void cleanup(T *t) { if (t) t->Release(t); }
224};
225
226template <typename T>
227class QDirectFBPointer : public QScopedPointer<T, QDirectFBInterfaceCleanupHandler<T> >
228{
229public:
230 QDirectFBPointer(T *t = 0)
231 : QScopedPointer<T, QDirectFBInterfaceCleanupHandler<T> >(t)
232 {}
233};
234
235bool QDirectFBPixmapData::fromDataBufferDescription(const DFBDataBufferDescription &dataBufferDescription)
236{
237 IDirectFB *dfb = screen->dfb();
238 Q_ASSERT(dfb);
239 DFBResult result = DFB_OK;
240 IDirectFBDataBuffer *dataBufferPtr;
241 if ((result = dfb->CreateDataBuffer(dfb, &dataBufferDescription, &dataBufferPtr)) != DFB_OK) {
242 DirectFBError("QDirectFBPixmapData::fromDataBufferDescription()", result);
243 return false;
244 }
245 QDirectFBPointer<IDirectFBDataBuffer> dataBuffer(dataBufferPtr);
246
247 IDirectFBImageProvider *providerPtr;
248 if ((result = dataBuffer->CreateImageProvider(dataBuffer.data(), &providerPtr)) != DFB_OK) {
249 DirectFBError("QDirectFBPixmapData::fromDataBufferDescription(): Can't create image provider", result);
250 return false;
251 }
252 QDirectFBPointer<IDirectFBImageProvider> provider(providerPtr);
253
254 DFBImageDescription imageDescription;
255 result = provider->GetImageDescription(provider.data(), &imageDescription);
256 if (result != DFB_OK) {
257 DirectFBError("QDirectFBPixmapData::fromSurfaceDescription(): Can't get image description", result);
258 return false;
259 }
260
261 if (imageDescription.caps & DICAPS_COLORKEY) {
262 return false;
263 }
264
265 DFBSurfaceDescription surfaceDescription;
266 if ((result = provider->GetSurfaceDescription(provider.data(), &surfaceDescription)) != DFB_OK) {
267 DirectFBError("QDirectFBPixmapData::fromDataBufferDescription(): Can't get surface description", result);
268 return false;
269 }
270
271 alpha = imageDescription.caps & DICAPS_ALPHACHANNEL;
272 imageFormat = alpha ? screen->alphaPixmapFormat() : screen->pixelFormat();
273
274 dfbSurface = screen->createDFBSurface(QSize(surfaceDescription.width, surfaceDescription.height),
275 imageFormat, QDirectFBScreen::TrackSurface);
276
277 result = provider->RenderTo(provider.data(), dfbSurface, 0);
278 if (result != DFB_OK) {
279 DirectFBError("QDirectFBPixmapData::fromSurfaceDescription(): Can't render to surface", result);
280 return false;
281 }
282
283 w = surfaceDescription.width;
284 h = surfaceDescription.height;
285 is_null = (w <= 0 || h <= 0);
286 d = QDirectFBScreen::depth(imageFormat);
287 setSerialNumber(++global_ser_no);
288
289#if defined QT_DIRECTFB_IMAGEPROVIDER_KEEPALIVE
290 screen->setDirectFBImageProvider(providerPtr);
291 provider.take();
292#endif
293
294 return true;
295}
296
297#endif
298
299void QDirectFBPixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags)
300{
301 alpha = QDirectFBPixmapData::hasAlphaChannel(img, flags);
302 imageFormat = alpha ? screen->alphaPixmapFormat() : screen->pixelFormat();
303 QImage image;
304 if ((flags & ~Qt::NoOpaqueDetection) != Qt::AutoColor) {
305 image = img.convertToFormat(imageFormat, flags);
306 flags = Qt::AutoColor;
307 } else if (img.format() == QImage::Format_RGB32 || img.depth() == 1) {
308 image = img.convertToFormat(imageFormat, flags);
309 } else {
310 image = img;
311 }
312
313 IDirectFBSurface *imageSurface = screen->createDFBSurface(image, image.format(), QDirectFBScreen::DontTrackSurface);
314 if (!imageSurface) {
315 qWarning("QDirectFBPixmapData::fromImage()");
316 invalidate();
317 return;
318 }
319
320 dfbSurface = screen->createDFBSurface(image.size(), imageFormat, QDirectFBScreen::TrackSurface);
321 if (!dfbSurface) {
322 qWarning("QDirectFBPixmapData::fromImage()");
323 invalidate();
324 return;
325 }
326
327 if (image.hasAlphaChannel()) {
328 dfbSurface->Clear(dfbSurface, 0, 0, 0, 0);
329 dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_BLEND_ALPHACHANNEL);
330 } else {
331 dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX);
332 }
333
334 dfbSurface->Blit(dfbSurface, imageSurface, 0, 0, 0);
335 imageSurface->Release(imageSurface);
336
337 w = image.width();
338 h = image.height();
339 is_null = (w <= 0 || h <= 0);
340 d = QDirectFBScreen::depth(imageFormat);
341 setSerialNumber(++global_ser_no);
342#ifdef QT_NO_DIRECTFB_OPAQUE_DETECTION
343 Q_UNUSED(flags);
344#endif
345}
346
347void QDirectFBPixmapData::copy(const QPixmapData *data, const QRect &rect)
348{
349 if (data->classId() != DirectFBClass) {
350 QPixmapData::copy(data, rect);
351 return;
352 }
353
354 const QDirectFBPixmapData *otherData = static_cast<const QDirectFBPixmapData*>(data);
355#ifdef QT_NO_DIRECTFB_SUBSURFACE
356 if (otherData->lockFlags()) {
357 const_cast<QDirectFBPixmapData*>(otherData)->unlockSurface();
358 }
359#endif
360 IDirectFBSurface *src = otherData->directFBSurface();
361 alpha = data->hasAlphaChannel();
362 imageFormat = (alpha
363 ? QDirectFBScreen::instance()->alphaPixmapFormat()
364 : QDirectFBScreen::instance()->pixelFormat());
365
366
367 dfbSurface = screen->createDFBSurface(rect.size(), imageFormat,
368 QDirectFBScreen::TrackSurface);
369 if (!dfbSurface) {
370 qWarning("QDirectFBPixmapData::copy()");
371 invalidate();
372 return;
373 }
374
375 if (alpha) {
376 dfbSurface->Clear(dfbSurface, 0, 0, 0, 0);
377 dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_BLEND_ALPHACHANNEL);
378 } else {
379 dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX);
380 }
381 const DFBRectangle blitRect = { rect.x(), rect.y(),
382 rect.width(), rect.height() };
383 w = rect.width();
384 h = rect.height();
385 d = otherData->d;
386 is_null = (w <= 0 || h <= 0);
387 unlockSurface();
388 DFBResult result = dfbSurface->Blit(dfbSurface, src, &blitRect, 0, 0);
389#if (Q_DIRECTFB_VERSION >= 0x010000)
390 dfbSurface->ReleaseSource(dfbSurface);
391#endif
392 if (result != DFB_OK) {
393 DirectFBError("QDirectFBPixmapData::copy()", result);
394 invalidate();
395 return;
396 }
397
398 setSerialNumber(++global_ser_no);
399}
400
401static inline bool isOpaqueFormat(QImage::Format format)
402{
403 switch (format) {
404 case QImage::Format_RGB32:
405 case QImage::Format_RGB16:
406 case QImage::Format_RGB666:
407 case QImage::Format_RGB555:
408 case QImage::Format_RGB888:
409 case QImage::Format_RGB444:
410 return true;
411 default:
412 break;
413 }
414 return false;
415}
416
417void QDirectFBPixmapData::fill(const QColor &color)
418{
419 if (!serialNumber())
420 return;
421
422 Q_ASSERT(dfbSurface);
423
424 alpha |= (color.alpha() < 255);
425
426 if (alpha && isOpaqueFormat(imageFormat)) {
427 QSize size;
428 dfbSurface->GetSize(dfbSurface, &size.rwidth(), &size.rheight());
429 screen->releaseDFBSurface(dfbSurface);
430 imageFormat = screen->alphaPixmapFormat();
431 d = QDirectFBScreen::depth(imageFormat);
432 dfbSurface = screen->createDFBSurface(size, screen->alphaPixmapFormat(), QDirectFBScreen::TrackSurface);
433 setSerialNumber(++global_ser_no);
434 if (!dfbSurface) {
435 qWarning("QDirectFBPixmapData::fill()");
436 invalidate();
437 return;
438 }
439 }
440
441 dfbSurface->Clear(dfbSurface, color.red(), color.green(), color.blue(), color.alpha());
442}
443
444QPixmap QDirectFBPixmapData::transformed(const QTransform &transform,
445 Qt::TransformationMode mode) const
446{
447 QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this);
448#ifdef QT_NO_DIRECTFB_SUBSURFACE
449 if (lockFlags())
450 that->unlockSurface();
451#endif
452
453 if (!dfbSurface || transform.type() != QTransform::TxScale
454 || mode != Qt::FastTransformation)
455 {
456 const QImage *image = that->buffer();
457 Q_ASSERT(image);
458 const QImage transformed = image->transformed(transform, mode);
459 QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType);
460 data->fromImage(transformed, Qt::AutoColor);
461 return QPixmap(data);
462 }
463
464 const QSize size = transform.mapRect(QRect(0, 0, w, h)).size();
465 if (size.isEmpty())
466 return QPixmap();
467
468 QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType);
469 data->setSerialNumber(++global_ser_no);
470 DFBSurfaceBlittingFlags flags = DSBLIT_NOFX;
471 data->alpha = alpha;
472 if (alpha) {
473 flags = DSBLIT_BLEND_ALPHACHANNEL;
474 }
475 data->dfbSurface = screen->createDFBSurface(size,
476 imageFormat,
477 QDirectFBScreen::TrackSurface);
478 if (flags & DSBLIT_BLEND_ALPHACHANNEL) {
479 data->dfbSurface->Clear(data->dfbSurface, 0, 0, 0, 0);
480 }
481 data->dfbSurface->SetBlittingFlags(data->dfbSurface, flags);
482
483 const DFBRectangle destRect = { 0, 0, size.width(), size.height() };
484 data->dfbSurface->StretchBlit(data->dfbSurface, dfbSurface, 0, &destRect);
485 data->w = size.width();
486 data->h = size.height();
487 data->is_null = (data->w <= 0 || data->h <= 0);
488
489#if (Q_DIRECTFB_VERSION >= 0x010000)
490 data->dfbSurface->ReleaseSource(data->dfbSurface);
491#endif
492 return QPixmap(data);
493}
494
495QImage QDirectFBPixmapData::toImage() const
496{
497 if (!dfbSurface)
498 return QImage();
499
500#if 0
501 // In later versions of DirectFB one can set a flag to tell
502 // DirectFB not to move the surface to videomemory. When that
503 // happens we can use this (hopefully faster) codepath
504#ifndef QT_NO_DIRECTFB_PREALLOCATED
505 QImage ret(w, h, QDirectFBScreen::getImageFormat(dfbSurface));
506 if (IDirectFBSurface *imgSurface = screen->createDFBSurface(ret, QDirectFBScreen::DontTrackSurface)) {
507 if (hasAlphaChannel()) {
508 imgSurface->SetBlittingFlags(imgSurface, DSBLIT_BLEND_ALPHACHANNEL);
509 imgSurface->Clear(imgSurface, 0, 0, 0, 0);
510 } else {
511 imgSurface->SetBlittingFlags(imgSurface, DSBLIT_NOFX);
512 }
513 imgSurface->Blit(imgSurface, dfbSurface, 0, 0, 0);
514#if (Q_DIRECTFB_VERSION >= 0x010000)
515 imgSurface->ReleaseSource(imgSurface);
516#endif
517 imgSurface->Release(imgSurface);
518 return ret;
519 }
520#endif
521#endif
522
523 QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this);
524 const QImage *img = that->buffer();
525 return img->copy();
526}
527
528/* This is QPixmapData::paintEngine(), not QPaintDevice::paintEngine() */
529
530QPaintEngine *QDirectFBPixmapData::paintEngine() const
531{
532 if (!engine) {
533 // QDirectFBPixmapData is also a QCustomRasterPaintDevice, so pass
534 // that to the paint engine:
535 QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this);
536 that->engine = new QDirectFBPaintEngine(that);
537 }
538 return engine;
539}
540
541QImage *QDirectFBPixmapData::buffer()
542{
543 if (!lockFlgs) {
544 lockSurface(DSLF_READ|DSLF_WRITE);
545 }
546 Q_ASSERT(lockFlgs);
547 Q_ASSERT(!lockedImage.isNull());
548 return &lockedImage;
549}
550
551
552bool QDirectFBPixmapData::scroll(int dx, int dy, const QRect &rect)
553{
554 if (!dfbSurface) {
555 return false;
556 }
557 unlockSurface();
558 DFBResult result = dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX);
559 if (result != DFB_OK) {
560 DirectFBError("QDirectFBPixmapData::scroll", result);
561 return false;
562 }
563 result = dfbSurface->SetPorterDuff(dfbSurface, DSPD_NONE);
564 if (result != DFB_OK) {
565 DirectFBError("QDirectFBPixmapData::scroll", result);
566 return false;
567 }
568
569 const DFBRectangle source = { rect.x(), rect.y(), rect.width(), rect.height() };
570 result = dfbSurface->Blit(dfbSurface, dfbSurface, &source, source.x + dx, source.y + dy);
571 if (result != DFB_OK) {
572 DirectFBError("QDirectFBPixmapData::scroll", result);
573 return false;
574 }
575
576 return true;
577}
578
579void QDirectFBPixmapData::invalidate()
580{
581 if (dfbSurface) {
582 screen->releaseDFBSurface(dfbSurface);
583 dfbSurface = 0;
584 }
585 setSerialNumber(0);
586 alpha = false;
587 d = w = h = 0;
588 is_null = true;
589 imageFormat = QImage::Format_Invalid;
590}
591
592Q_GUI_EXPORT IDirectFBSurface *qt_directfb_surface_for_pixmap(const QPixmap &pixmap)
593{
594 const QPixmapData *data = pixmap.pixmapData();
595 if (!data || data->classId() != QPixmapData::DirectFBClass)
596 return 0;
597 const QDirectFBPixmapData *dfbData = static_cast<const QDirectFBPixmapData*>(data);
598 return dfbData->directFBSurface();
599}
600
601QT_END_NAMESPACE
602
603#endif // QT_NO_QWS_DIRECTFB
Note: See TracBrowser for help on using the repository browser.