source: trunk/src/gui/image/qpixmap_s60.cpp@ 1056

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

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

  • Property svn:eol-style set to native
File size: 29.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module 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 [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41#include <exception>
42#include <w32std.h>
43#include <fbs.h>
44
45#include <private/qapplication_p.h>
46#include <private/qgraphicssystem_p.h>
47#include <private/qt_s60_p.h>
48#include <private/qpaintengine_s60_p.h>
49
50#include "qpixmap.h"
51#include "qpixmap_raster_p.h"
52#include <qwidget.h>
53#include "qpixmap_s60_p.h"
54#include "qnativeimage_p.h"
55#include "qbitmap.h"
56#include "qimage.h"
57#include "qimage_p.h"
58
59#include <fbs.h>
60
61QT_BEGIN_NAMESPACE
62
63const uchar qt_pixmap_bit_mask[] = { 0x01, 0x02, 0x04, 0x08,
64 0x10, 0x20, 0x40, 0x80 };
65
66static bool cleanup_function_registered = false;
67static QS60PixmapData *firstPixmap = 0;
68
69// static
70void QS60PixmapData::qt_symbian_register_pixmap(QS60PixmapData *pd)
71{
72 if (!cleanup_function_registered) {
73 qAddPostRoutine(qt_symbian_release_pixmaps);
74 cleanup_function_registered = true;
75 }
76
77 pd->next = firstPixmap;
78 pd->prev = 0;
79 if (firstPixmap)
80 firstPixmap->prev = pd;
81 firstPixmap = pd;
82}
83
84// static
85void QS60PixmapData::qt_symbian_unregister_pixmap(QS60PixmapData *pd)
86{
87 if (pd->next)
88 pd->next->prev = pd->prev;
89 if (pd->prev)
90 pd->prev->next = pd->next;
91 else
92 firstPixmap = pd->next;
93}
94
95// static
96void QS60PixmapData::qt_symbian_release_pixmaps()
97{
98 // Scan all QS60PixmapData objects in the system and destroy them.
99 QS60PixmapData *pd = firstPixmap;
100 while (pd != 0) {
101 pd->release();
102 pd = pd->next;
103 }
104}
105
106/*
107 \class QSymbianFbsClient
108 \since 4.6
109 \internal
110
111 Symbian Font And Bitmap server client that is
112 used to lock the global bitmap heap. Only used in
113 S60 v3.1 and S60 v3.2.
114*/
115_LIT(KFBSERVLargeBitmapAccessName,"FbsLargeBitmapAccess");
116class QSymbianFbsClient
117{
118public:
119
120 QSymbianFbsClient() : heapLocked(false)
121 {
122 heapLock.OpenGlobal(KFBSERVLargeBitmapAccessName);
123 }
124
125 ~QSymbianFbsClient()
126 {
127 heapLock.Close();
128 }
129
130 bool lockHeap()
131 {
132 bool wasLocked = heapLocked;
133
134 if (heapLock.Handle() && !heapLocked) {
135 heapLock.Wait();
136 heapLocked = true;
137 }
138
139 return wasLocked;
140 }
141
142 bool unlockHeap()
143 {
144 bool wasLocked = heapLocked;
145
146 if (heapLock.Handle() && heapLocked) {
147 heapLock.Signal();
148 heapLocked = false;
149 }
150
151 return wasLocked;
152 }
153
154
155private:
156
157 RMutex heapLock;
158 bool heapLocked;
159};
160
161Q_GLOBAL_STATIC(QSymbianFbsClient, qt_symbianFbsClient);
162
163
164
165// QSymbianFbsHeapLock
166
167QSymbianFbsHeapLock::QSymbianFbsHeapLock(LockAction a)
168: action(a), wasLocked(false)
169{
170 QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion();
171 if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3)
172 wasLocked = qt_symbianFbsClient()->unlockHeap();
173}
174
175QSymbianFbsHeapLock::~QSymbianFbsHeapLock()
176{
177 // Do nothing
178}
179
180void QSymbianFbsHeapLock::relock()
181{
182 QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion();
183 if (wasLocked && (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3))
184 qt_symbianFbsClient()->lockHeap();
185}
186
187/*
188 \class QSymbianBitmapDataAccess
189 \since 4.6
190 \internal
191
192 Data access class that is used to locks/unlocks pixel data
193 when drawing or modifying CFbsBitmap pixel data.
194*/
195class QSymbianBitmapDataAccess
196{
197public:
198
199 static int heapRefCount;
200 QSysInfo::SymbianVersion symbianVersion;
201
202 explicit QSymbianBitmapDataAccess()
203 {
204 symbianVersion = QSysInfo::symbianVersion();
205 };
206
207 ~QSymbianBitmapDataAccess() {};
208
209 inline void beginDataAccess(CFbsBitmap *bitmap)
210 {
211 if (symbianVersion == QSysInfo::SV_9_2) {
212 if (heapRefCount == 0)
213 qt_symbianFbsClient()->lockHeap();
214 } else {
215 bitmap->LockHeap(ETrue);
216 }
217
218 heapRefCount++;
219 }
220
221 inline void endDataAccess(CFbsBitmap *bitmap)
222 {
223 heapRefCount--;
224
225 if (symbianVersion == QSysInfo::SV_9_2) {
226 if (heapRefCount == 0)
227 qt_symbianFbsClient()->unlockHeap();
228 } else {
229 bitmap->UnlockHeap(ETrue);
230 }
231 }
232};
233
234int QSymbianBitmapDataAccess::heapRefCount = 0;
235
236
237#define UPDATE_BUFFER() \
238 { \
239 beginDataAccess(); \
240 endDataAccess(); \
241}
242
243
244static CFbsBitmap* createSymbianCFbsBitmap(const TSize& size, TDisplayMode mode)
245{
246 QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
247
248 CFbsBitmap* bitmap = 0;
249 QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap);
250
251 if (bitmap->Create(size, mode) != KErrNone) {
252 delete bitmap;
253 bitmap = 0;
254 }
255
256 lock.relock();
257
258 return bitmap;
259}
260
261static CFbsBitmap* uncompress(CFbsBitmap* bitmap)
262{
263 if(bitmap->IsCompressedInRAM()) {
264 QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
265
266 CFbsBitmap *uncompressed = 0;
267 QT_TRAP_THROWING(uncompressed = new (ELeave) CFbsBitmap);
268
269 if (uncompressed->Create(bitmap->SizeInPixels(), bitmap->DisplayMode()) != KErrNone) {
270 delete bitmap;
271 bitmap = 0;
272 lock.relock();
273
274 return bitmap;
275 }
276
277 lock.relock();
278
279 CFbsBitmapDevice* bitmapDevice = 0;
280 CFbsBitGc *bitmapGc = 0;
281 QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(uncompressed));
282 QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL());
283 bitmapGc->Activate(bitmapDevice);
284
285 bitmapGc->BitBlt(TPoint(), bitmap);
286
287 delete bitmapGc;
288 delete bitmapDevice;
289
290 return uncompressed;
291 } else {
292 return bitmap;
293 }
294}
295
296QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h)
297{
298 CWsScreenDevice* screenDevice = S60->screenDevice();
299 TSize screenSize = screenDevice->SizeInPixels();
300
301 TSize srcSize;
302 // Find out if this is one of our windows.
303 QSymbianControl *sControl;
304 sControl = winId->MopGetObject(sControl);
305 if (sControl && sControl->widget()->windowType() == Qt::Desktop) {
306 // Grabbing desktop widget
307 srcSize = screenSize;
308 } else {
309 TPoint relativePos = winId->PositionRelativeToScreen();
310 x += relativePos.iX;
311 y += relativePos.iY;
312 srcSize = winId->Size();
313 }
314
315 TRect srcRect(TPoint(x, y), srcSize);
316 // Clip to the screen
317 srcRect.Intersection(TRect(screenSize));
318
319 if (w > 0 && h > 0) {
320 TRect subRect(TPoint(x, y), TSize(w, h));
321 // Clip to the subRect
322 srcRect.Intersection(subRect);
323 }
324
325 if (srcRect.IsEmpty())
326 return QPixmap();
327
328 CFbsBitmap* temporary = createSymbianCFbsBitmap(srcRect.Size(), screenDevice->DisplayMode());
329
330 QPixmap pix;
331
332 if (temporary && screenDevice->CopyScreenToBitmap(temporary, srcRect) == KErrNone) {
333 pix = QPixmap::fromSymbianCFbsBitmap(temporary);
334 }
335
336 delete temporary;
337 return pix;
338}
339
340/*!
341 \fn CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const
342 \since 4.6
343
344 Creates a \c CFbsBitmap that is equivalent to the QPixmap. Internally this
345 function will try to duplicate the handle instead of copying the data,
346 however in scenarios where this is not possible the data will be copied.
347 If the creation fails or the pixmap is null, then this function returns 0.
348
349 It is the caller's responsibility to release the \c CFbsBitmap data
350 after use either by deleting the bitmap or calling \c Reset().
351
352 \warning On S60 3.1 and S60 3.2, semi-transparent pixmaps are always copied
353 and not duplicated.
354 \warning This function is only available on Symbian OS.
355
356 \sa fromSymbianCFbsBitmap()
357*/
358CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const
359{
360 QPixmapData *data = pixmapData();
361 if (!data || data->isNull())
362 return 0;
363
364 return reinterpret_cast<CFbsBitmap*>(data->toNativeType(QPixmapData::FbsBitmap));
365}
366
367/*!
368 \fn QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap)
369 \since 4.6
370
371 Creates a QPixmap from a \c CFbsBitmap \a bitmap. Internally this function
372 will try to duplicate the bitmap handle instead of copying the data, however
373 in scenarios where this is not possible the data will be copied.
374 To be sure that QPixmap does not modify your original instance, you should
375 make a copy of your \c CFbsBitmap before calling this function.
376 If the CFbsBitmap is not valid this function will return a null QPixmap.
377
378 \warning This function is only available on Symbian OS.
379
380 \sa toSymbianCFbsBitmap(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
381*/
382QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap)
383{
384 if (!bitmap)
385 return QPixmap();
386
387 QScopedPointer<QPixmapData> data(QPixmapData::create(0,0, QPixmapData::PixmapType));
388 data->fromNativeType(reinterpret_cast<void*>(bitmap), QPixmapData::FbsBitmap);
389 QPixmap pixmap(data.take());
390 return pixmap;
391}
392
393QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type),
394 symbianBitmapDataAccess(new QSymbianBitmapDataAccess),
395 cfbsBitmap(0),
396 pengine(0),
397 bytes(0),
398 formatLocked(false),
399 next(0),
400 prev(0)
401{
402 qt_symbian_register_pixmap(this);
403}
404
405QS60PixmapData::~QS60PixmapData()
406{
407 release();
408 delete symbianBitmapDataAccess;
409 qt_symbian_unregister_pixmap(this);
410}
411
412void QS60PixmapData::resize(int width, int height)
413{
414 if (width <= 0 || height <= 0) {
415 w = width;
416 h = height;
417 is_null = true;
418
419 release();
420 return;
421 } else if (!cfbsBitmap) {
422 TDisplayMode mode;
423 if (pixelType() == BitmapType)
424 mode = EGray2;
425 else
426 mode = EColor16MU;
427
428 CFbsBitmap* bitmap = createSymbianCFbsBitmap(TSize(width, height), mode);
429 fromSymbianBitmap(bitmap);
430 } else {
431
432 TSize newSize(width, height);
433
434 if(cfbsBitmap->SizeInPixels() != newSize) {
435 cfbsBitmap->Resize(TSize(width, height));
436 if(pengine) {
437 delete pengine;
438 pengine = 0;
439 }
440 }
441
442 UPDATE_BUFFER();
443 }
444}
445
446void QS60PixmapData::release()
447{
448 if (cfbsBitmap) {
449 QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
450 delete cfbsBitmap;
451 lock.relock();
452 }
453
454 delete pengine;
455 image = QImage();
456 cfbsBitmap = 0;
457 pengine = 0;
458 bytes = 0;
459}
460
461/*!
462 * Takes ownership of bitmap. Used by window surface
463 */
464void QS60PixmapData::fromSymbianBitmap(CFbsBitmap* bitmap, bool lockFormat)
465{
466 Q_ASSERT(bitmap);
467
468 release();
469
470 cfbsBitmap = bitmap;
471 formatLocked = lockFormat;
472
473 setSerialNumber(cfbsBitmap->Handle());
474
475 UPDATE_BUFFER();
476
477 // Create default palette if needed
478 if (cfbsBitmap->DisplayMode() == EGray2) {
479 image.setColorCount(2);
480 image.setColor(0, QColor(Qt::color0).rgba());
481 image.setColor(1, QColor(Qt::color1).rgba());
482
483 //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
484 //So invert mono bitmaps so that masks work correctly.
485 image.invertPixels();
486 } else if (cfbsBitmap->DisplayMode() == EGray256) {
487 for (int i=0; i < 256; ++i)
488 image.setColor(i, qRgb(i, i, i));
489 } else if (cfbsBitmap->DisplayMode() == EColor256) {
490 const TColor256Util *palette = TColor256Util::Default();
491 for (int i=0; i < 256; ++i)
492 image.setColor(i, (QRgb)(palette->Color256(i).Value()));
493 }
494}
495
496QImage QS60PixmapData::toImage(const QRect &r) const
497{
498 QS60PixmapData *that = const_cast<QS60PixmapData*>(this);
499 that->beginDataAccess();
500 QImage copy = that->image.copy(r);
501 that->endDataAccess();
502
503 return copy;
504}
505
506void QS60PixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags)
507{
508 release();
509
510 QImage sourceImage;
511
512 if (pixelType() == BitmapType) {
513 sourceImage = img.convertToFormat(QImage::Format_MonoLSB);
514 } else {
515 if (img.depth() == 1) {
516 sourceImage = img.hasAlphaChannel()
517 ? img.convertToFormat(QImage::Format_ARGB32_Premultiplied)
518 : img.convertToFormat(QImage::Format_RGB32);
519 } else {
520
521 QImage::Format opaqueFormat = QNativeImage::systemFormat();
522 QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied;
523
524 if (!img.hasAlphaChannel()
525 || ((flags & Qt::NoOpaqueDetection) == 0
526 && !const_cast<QImage &>(img).data_ptr()->checkForAlphaPixels())) {
527 sourceImage = img.convertToFormat(opaqueFormat);
528 } else {
529 sourceImage = img.convertToFormat(alphaFormat);
530 }
531 }
532 }
533
534
535 QImage::Format destFormat = sourceImage.format();
536 TDisplayMode mode;
537 switch (destFormat) {
538 case QImage::Format_MonoLSB:
539 mode = EGray2;
540 break;
541 case QImage::Format_RGB32:
542 mode = EColor16MU;
543 break;
544 case QImage::Format_ARGB32_Premultiplied:
545 if (S60->supportsPremultipliedAlpha) {
546 mode = Q_SYMBIAN_ECOLOR16MAP;
547 break;
548 } else {
549 destFormat = QImage::Format_ARGB32;
550 }
551 // Fall through intended
552 case QImage::Format_ARGB32:
553 mode = EColor16MA;
554 break;
555 case QImage::Format_Invalid:
556 return;
557 default:
558 qWarning("Image format not supported: %d", image.format());
559 return;
560 }
561
562 cfbsBitmap = createSymbianCFbsBitmap(TSize(sourceImage.width(), sourceImage.height()), mode);
563 if (!cfbsBitmap) {
564 qWarning("Could not create CFbsBitmap");
565 release();
566 return;
567 }
568
569 setSerialNumber(cfbsBitmap->Handle());
570
571 const uchar *sptr = const_cast<const QImage &>(sourceImage).bits();
572 symbianBitmapDataAccess->beginDataAccess(cfbsBitmap);
573 uchar *dptr = (uchar*)cfbsBitmap->DataAddress();
574 Mem::Copy(dptr, sptr, sourceImage.byteCount());
575 symbianBitmapDataAccess->endDataAccess(cfbsBitmap);
576
577 UPDATE_BUFFER();
578
579 if (destFormat == QImage::Format_MonoLSB) {
580 image.setColorCount(2);
581 image.setColor(0, QColor(Qt::color0).rgba());
582 image.setColor(1, QColor(Qt::color1).rgba());
583 } else {
584 image.setColorTable(sourceImage.colorTable());
585 }
586}
587
588void QS60PixmapData::copy(const QPixmapData *data, const QRect &rect)
589{
590 const QS60PixmapData *s60Data = static_cast<const QS60PixmapData*>(data);
591 fromImage(s60Data->toImage(rect), Qt::AutoColor | Qt::OrderedAlphaDither);
592}
593
594bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect)
595{
596 beginDataAccess();
597 bool res = QRasterPixmapData::scroll(dx, dy, rect);
598 endDataAccess();
599 return res;
600}
601
602Q_GUI_EXPORT int qt_defaultDpiX();
603Q_GUI_EXPORT int qt_defaultDpiY();
604
605int QS60PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
606{
607 if (!cfbsBitmap)
608 return 0;
609
610 switch (metric) {
611 case QPaintDevice::PdmWidth:
612 return cfbsBitmap->SizeInPixels().iWidth;
613 case QPaintDevice::PdmHeight:
614 return cfbsBitmap->SizeInPixels().iHeight;
615 case QPaintDevice::PdmWidthMM:
616 return qRound(cfbsBitmap->SizeInPixels().iWidth * 25.4 / qt_defaultDpiX());
617 case QPaintDevice::PdmHeightMM:
618 return qRound(cfbsBitmap->SizeInPixels().iHeight * 25.4 / qt_defaultDpiY());
619 case QPaintDevice::PdmNumColors:
620 return TDisplayModeUtils::NumDisplayModeColors(cfbsBitmap->DisplayMode());
621 case QPaintDevice::PdmDpiX:
622 case QPaintDevice::PdmPhysicalDpiX:
623 return qt_defaultDpiX();
624 case QPaintDevice::PdmDpiY:
625 case QPaintDevice::PdmPhysicalDpiY:
626 return qt_defaultDpiY();
627 case QPaintDevice::PdmDepth:
628 return TDisplayModeUtils::NumDisplayModeBitsPerPixel(cfbsBitmap->DisplayMode());
629 default:
630 qWarning("QPixmap::metric: Invalid metric command");
631 }
632 return 0;
633
634}
635
636void QS60PixmapData::fill(const QColor &color)
637{
638 if (color.alpha() != 255) {
639 QImage im(width(), height(), QImage::Format_ARGB32_Premultiplied);
640 im.fill(PREMUL(color.rgba()));
641 release();
642 fromImage(im, Qt::AutoColor | Qt::OrderedAlphaDither);
643 } else {
644 beginDataAccess();
645 QRasterPixmapData::fill(color);
646 endDataAccess();
647 }
648}
649
650void QS60PixmapData::setMask(const QBitmap &mask)
651{
652 if (mask.size().isEmpty()) {
653 if (image.depth() != 1) {
654 QImage newImage = image.convertToFormat(QImage::Format_RGB32);
655 release();
656 fromImage(newImage, Qt::AutoColor | Qt::OrderedAlphaDither);
657 }
658 } else if (image.depth() == 1) {
659 beginDataAccess();
660 QRasterPixmapData::setMask(mask);
661 endDataAccess();
662 } else {
663 const int w = image.width();
664 const int h = image.height();
665
666 const QImage imageMask = mask.toImage().convertToFormat(QImage::Format_MonoLSB);
667 QImage newImage = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
668 for (int y = 0; y < h; ++y) {
669 const uchar *mscan = imageMask.scanLine(y);
670 QRgb *tscan = (QRgb *)newImage.scanLine(y);
671 for (int x = 0; x < w; ++x) {
672 if (!(mscan[x>>3] & qt_pixmap_bit_mask[x&7]))
673 tscan[x] = 0;
674 }
675 }
676 release();
677 fromImage(newImage, Qt::AutoColor | Qt::OrderedAlphaDither);
678 }
679}
680
681void QS60PixmapData::setAlphaChannel(const QPixmap &alphaChannel)
682{
683 QImage img(toImage());
684 img.setAlphaChannel(alphaChannel.toImage());
685 release();
686 fromImage(img, Qt::OrderedDither | Qt::OrderedAlphaDither);
687}
688
689QImage QS60PixmapData::toImage() const
690{
691 return toImage(QRect());
692}
693
694QPaintEngine* QS60PixmapData::paintEngine() const
695{
696 if (!pengine) {
697 QS60PixmapData *that = const_cast<QS60PixmapData*>(this);
698 that->pengine = new QS60PaintEngine(&that->image, that);
699 }
700 return pengine;
701}
702
703void QS60PixmapData::beginDataAccess()
704{
705 if(!cfbsBitmap)
706 return;
707
708 symbianBitmapDataAccess->beginDataAccess(cfbsBitmap);
709
710 uchar* newBytes = (uchar*)cfbsBitmap->DataAddress();
711
712 TSize size = cfbsBitmap->SizeInPixels();
713
714 if (newBytes == bytes && image.width() == size.iWidth && image.height() == size.iHeight)
715 return;
716
717 bytes = newBytes;
718 TDisplayMode mode = cfbsBitmap->DisplayMode();
719 QImage::Format format = qt_TDisplayMode2Format(mode);
720 // On S60 3.1, premultiplied alpha pixels are stored in a bitmap with 16MA type.
721 // S60 window surface needs backing store pixmap for transparent window in ARGB32 format.
722 // In that case formatLocked is true.
723 if (!formatLocked && format == QImage::Format_ARGB32)
724 format = QImage::Format_ARGB32_Premultiplied; // pixel data is actually in premultiplied format
725
726 QVector<QRgb> savedColorTable;
727 if (!image.isNull())
728 savedColorTable = image.colorTable();
729
730 image = QImage(bytes, size.iWidth, size.iHeight, format);
731
732 // Restore the palette or create a default
733 if (!savedColorTable.isEmpty()) {
734 image.setColorTable(savedColorTable);
735 }
736
737 w = size.iWidth;
738 h = size.iHeight;
739 d = image.depth();
740 is_null = (w <= 0 || h <= 0);
741
742 if (pengine) {
743 QS60PaintEngine *engine = static_cast<QS60PaintEngine *>(pengine);
744 engine->prepare(&image);
745 }
746}
747
748void QS60PixmapData::endDataAccess(bool readOnly) const
749{
750 Q_UNUSED(readOnly);
751
752 if(!cfbsBitmap)
753 return;
754
755 symbianBitmapDataAccess->endDataAccess(cfbsBitmap);
756}
757
758/*!
759 \since 4.6
760
761 Returns a QPixmap that wraps given \a sgImage graphics resource.
762 The data should be valid even when original RSgImage handle has been
763 closed.
764
765 \warning This function is only available on Symbian OS.
766
767 \sa toSymbianRSgImage(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
768*/
769
770QPixmap QPixmap::fromSymbianRSgImage(RSgImage *sgImage)
771{
772 // It is expected that RSgImage will
773 // CURRENTLY be used in conjuction with
774 // OpenVG graphics system
775 //
776 // Surely things might change in future
777
778 if (!sgImage)
779 return QPixmap();
780
781 QScopedPointer<QPixmapData> data(QPixmapData::create(0,0, QPixmapData::PixmapType));
782 data->fromNativeType(reinterpret_cast<void*>(sgImage), QPixmapData::SgImage);
783 QPixmap pixmap(data.take());
784 return pixmap;
785}
786
787/*!
788\since 4.6
789
790Returns a \c RSgImage that is equivalent to the QPixmap by copying the data.
791
792It is the caller's responsibility to close/delete the \c RSgImage after use.
793
794\warning This function is only available on Symbian OS.
795
796\sa fromSymbianRSgImage()
797*/
798
799RSgImage *QPixmap::toSymbianRSgImage() const
800{
801 // It is expected that RSgImage will
802 // CURRENTLY be used in conjuction with
803 // OpenVG graphics system
804 //
805 // Surely things might change in future
806
807 if (isNull())
808 return 0;
809
810 RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmapData()->toNativeType(QPixmapData::SgImage));
811
812 return sgImage;
813}
814
815void* QS60PixmapData::toNativeType(NativeType type)
816{
817 if (type == QPixmapData::SgImage) {
818 return 0;
819 } else if (type == QPixmapData::FbsBitmap) {
820
821 if (isNull() || !cfbsBitmap)
822 return 0;
823
824 bool convertToArgb32 = false;
825 bool needsCopy = false;
826
827 if (!(S60->supportsPremultipliedAlpha)) {
828 // Convert argb32_premultiplied to argb32 since Symbian 9.2 does
829 // not support premultipied format.
830
831 if (image.format() == QImage::Format_ARGB32_Premultiplied) {
832 needsCopy = true;
833 convertToArgb32 = true;
834 }
835 }
836
837 CFbsBitmap *bitmap = 0;
838
839 TDisplayMode displayMode = cfbsBitmap->DisplayMode();
840
841 if(displayMode == EGray2) {
842 //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
843 //So invert mono bitmaps so that masks work correctly.
844 beginDataAccess();
845 image.invertPixels();
846 endDataAccess();
847 needsCopy = true;
848 }
849
850 if (needsCopy) {
851 QImage source;
852
853 if (convertToArgb32) {
854 beginDataAccess();
855 source = image.convertToFormat(QImage::Format_ARGB32);
856 endDataAccess();
857 displayMode = EColor16MA;
858 } else {
859 source = image;
860 }
861
862 CFbsBitmap *newBitmap = createSymbianCFbsBitmap(TSize(source.width(), source.height()), displayMode);
863 const uchar *sptr = source.bits();
864 symbianBitmapDataAccess->beginDataAccess(newBitmap);
865
866 uchar *dptr = (uchar*)newBitmap->DataAddress();
867 Mem::Copy(dptr, sptr, source.byteCount());
868
869 symbianBitmapDataAccess->endDataAccess(newBitmap);
870
871 bitmap = newBitmap;
872 } else {
873
874 QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap);
875
876 TInt err = bitmap->Duplicate(cfbsBitmap->Handle());
877 if (err != KErrNone) {
878 qWarning("Could not duplicate CFbsBitmap");
879 delete bitmap;
880 bitmap = 0;
881 }
882 }
883
884 if(displayMode == EGray2) {
885 // restore pixels
886 beginDataAccess();
887 image.invertPixels();
888 endDataAccess();
889 }
890
891 return reinterpret_cast<void*>(bitmap);
892
893 }
894
895 return 0;
896}
897
898void QS60PixmapData::fromNativeType(void* pixmap, NativeType nativeType)
899{
900 if (nativeType == QPixmapData::SgImage) {
901 return;
902 } else if (nativeType == QPixmapData::FbsBitmap && pixmap) {
903
904 CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap*>(pixmap);
905
906 bool deleteSourceBitmap = false;
907 bool needsCopy = false;
908
909#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE
910
911 // Rasterize extended bitmaps
912
913 TUid extendedBitmapType = bitmap->ExtendedBitmapType();
914 if (extendedBitmapType != KNullUid) {
915 CFbsBitmap *rasterBitmap = createSymbianCFbsBitmap(bitmap->SizeInPixels(), EColor16MA);
916
917 CFbsBitmapDevice *rasterBitmapDev = 0;
918 QT_TRAP_THROWING(rasterBitmapDev = CFbsBitmapDevice::NewL(rasterBitmap));
919
920 CFbsBitGc *rasterBitmapGc = 0;
921 TInt err = rasterBitmapDev->CreateContext(rasterBitmapGc);
922 if (err != KErrNone) {
923 delete rasterBitmap;
924 delete rasterBitmapDev;
925 rasterBitmapDev = 0;
926 return;
927 }
928
929 rasterBitmapGc->BitBlt(TPoint( 0, 0), bitmap);
930
931 bitmap = rasterBitmap;
932
933 delete rasterBitmapDev;
934 delete rasterBitmapGc;
935
936 rasterBitmapDev = 0;
937 rasterBitmapGc = 0;
938
939 deleteSourceBitmap = true;
940 }
941#endif
942
943
944 deleteSourceBitmap = bitmap->IsCompressedInRAM();
945 CFbsBitmap *sourceBitmap = uncompress(bitmap);
946
947 TDisplayMode displayMode = sourceBitmap->DisplayMode();
948 QImage::Format format = qt_TDisplayMode2Format(displayMode);
949
950 QImage::Format opaqueFormat = QNativeImage::systemFormat();
951 QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied;
952
953 if (format != opaqueFormat && format != alphaFormat && format != QImage::Format_MonoLSB)
954 needsCopy = true;
955
956
957 type = (format != QImage::Format_MonoLSB)
958 ? QPixmapData::PixmapType
959 : QPixmapData::BitmapType;
960
961 if (needsCopy) {
962
963 TSize size = sourceBitmap->SizeInPixels();
964 int bytesPerLine = sourceBitmap->ScanLineLength(size.iWidth, displayMode);
965
966 QSymbianBitmapDataAccess da;
967 da.beginDataAccess(sourceBitmap);
968 uchar *bytes = (uchar*)sourceBitmap->DataAddress();
969 QImage img = QImage(bytes, size.iWidth, size.iHeight, bytesPerLine, format);
970 img = img.copy();
971 da.endDataAccess(sourceBitmap);
972
973 if(displayMode == EGray2) {
974 //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
975 //So invert mono bitmaps so that masks work correctly.
976 img.invertPixels();
977 } else if(displayMode == EColor16M) {
978 img = img.rgbSwapped(); // EColor16M is BGR
979 }
980
981 fromImage(img, Qt::AutoColor);
982
983 if(deleteSourceBitmap)
984 delete sourceBitmap;
985 } else {
986 CFbsBitmap* duplicate = 0;
987 QT_TRAP_THROWING(duplicate = new (ELeave) CFbsBitmap);
988
989 TInt err = duplicate->Duplicate(sourceBitmap->Handle());
990 if (err != KErrNone) {
991 qWarning("Could not duplicate CFbsBitmap");
992
993 if(deleteSourceBitmap)
994 delete sourceBitmap;
995
996 delete duplicate;
997 return;
998 }
999
1000 fromSymbianBitmap(duplicate);
1001
1002 if(deleteSourceBitmap)
1003 delete sourceBitmap;
1004 }
1005 }
1006}
1007
1008void QS60PixmapData::convertToDisplayMode(int mode)
1009{
1010 const TDisplayMode displayMode = static_cast<TDisplayMode>(mode);
1011 if (!cfbsBitmap || cfbsBitmap->DisplayMode() == displayMode)
1012 return;
1013 if (image.depth() != TDisplayModeUtils::NumDisplayModeBitsPerPixel(displayMode)) {
1014 qWarning("Cannot convert display mode due to depth mismatch");
1015 return;
1016 }
1017
1018 const TSize size = cfbsBitmap->SizeInPixels();
1019 QScopedPointer<CFbsBitmap> newBitmap(createSymbianCFbsBitmap(size, displayMode));
1020
1021 const uchar *sptr = const_cast<const QImage &>(image).bits();
1022 symbianBitmapDataAccess->beginDataAccess(newBitmap.data());
1023 uchar *dptr = (uchar*)newBitmap->DataAddress();
1024 Mem::Copy(dptr, sptr, image.byteCount());
1025 symbianBitmapDataAccess->endDataAccess(newBitmap.data());
1026
1027 QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
1028 delete cfbsBitmap;
1029 lock.relock();
1030 cfbsBitmap = newBitmap.take();
1031 setSerialNumber(cfbsBitmap->Handle());
1032 UPDATE_BUFFER();
1033}
1034
1035QPixmapData *QS60PixmapData::createCompatiblePixmapData() const
1036{
1037 return new QS60PixmapData(pixelType());
1038}
1039
1040QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.