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

Last change on this file since 605 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

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