2 ** |
2 ** |
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
4 ** All rights reserved. |
4 ** All rights reserved. |
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
6 ** |
6 ** |
7 ** This file is part of the QtGui of the Qt Toolkit. |
7 ** This file is part of the QtGui module of the Qt Toolkit. |
8 ** |
8 ** |
9 ** $QT_BEGIN_LICENSE:LGPL$ |
9 ** $QT_BEGIN_LICENSE:LGPL$ |
10 ** No Commercial Usage |
10 ** No Commercial Usage |
11 ** This file contains pre-release code and may not be distributed. |
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 |
12 ** You may use this file in accordance with the terms and conditions |
71 |
71 |
72 Symbian Font And Bitmap server client that is |
72 Symbian Font And Bitmap server client that is |
73 used to lock the global bitmap heap. Only used in |
73 used to lock the global bitmap heap. Only used in |
74 S60 v3.1 and S60 v3.2. |
74 S60 v3.1 and S60 v3.2. |
75 */ |
75 */ |
|
76 _LIT(KFBSERVLargeBitmapAccessName,"FbsLargeBitmapAccess"); |
76 class QSymbianFbsClient |
77 class QSymbianFbsClient |
77 { |
78 { |
78 public: |
79 public: |
79 |
80 |
80 QSymbianFbsClient() : heapLock(0), heapLocked(false) |
81 QSymbianFbsClient() : heapLocked(false) |
81 { |
82 { |
82 QT_TRAP_THROWING(heapLock = new(ELeave) CFbsBitmap); |
83 heapLock.OpenGlobal(KFBSERVLargeBitmapAccessName); |
83 heapLock->Create(TSize(0,0), S60->screenDevice()->DisplayMode()); |
|
84 } |
84 } |
85 |
85 |
86 ~QSymbianFbsClient() |
86 ~QSymbianFbsClient() |
87 { |
87 { |
88 delete heapLock; |
88 heapLock.Close(); |
89 } |
89 } |
90 |
90 |
91 bool lockHeap() |
91 bool lockHeap() |
92 { |
92 { |
93 bool wasLocked = heapLocked; |
93 bool wasLocked = heapLocked; |
94 |
94 |
95 if (heapLock && !heapLocked) { |
95 if (heapLock.Handle() && !heapLocked) { |
96 heapLock->LockHeap(ETrue); |
96 heapLock.Wait(); |
97 heapLocked = true; |
97 heapLocked = true; |
98 } |
98 } |
99 |
99 |
100 return wasLocked; |
100 return wasLocked; |
101 } |
101 } |
102 |
102 |
103 bool unlockHeap() |
103 bool unlockHeap() |
104 { |
104 { |
105 bool wasLocked = heapLocked; |
105 bool wasLocked = heapLocked; |
106 |
106 |
107 if (heapLock && heapLocked) { |
107 if (heapLock.Handle() && heapLocked) { |
108 heapLock->UnlockHeap(ETrue); |
108 heapLock.Signal(); |
109 heapLocked = false; |
109 heapLocked = false; |
110 } |
110 } |
111 |
111 |
112 return wasLocked; |
112 return wasLocked; |
113 } |
113 } |
114 |
114 |
115 |
115 |
116 private: |
116 private: |
117 |
117 |
118 CFbsBitmap *heapLock; |
118 RMutex heapLock; |
119 bool heapLocked; |
119 bool heapLocked; |
120 }; |
120 }; |
121 |
121 |
122 Q_GLOBAL_STATIC(QSymbianFbsClient, qt_symbianFbsClient); |
122 Q_GLOBAL_STATIC(QSymbianFbsClient, qt_symbianFbsClient); |
123 |
123 |
167 |
167 |
168 ~QSymbianBitmapDataAccess() {}; |
168 ~QSymbianBitmapDataAccess() {}; |
169 |
169 |
170 inline void beginDataAccess(CFbsBitmap *bitmap) |
170 inline void beginDataAccess(CFbsBitmap *bitmap) |
171 { |
171 { |
172 if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3) |
172 if (symbianVersion == QSysInfo::SV_9_2) |
173 heapWasLocked = qt_symbianFbsClient()->lockHeap(); |
173 heapWasLocked = qt_symbianFbsClient()->lockHeap(); |
174 else |
174 else |
175 bitmap->LockHeap(ETrue); |
175 bitmap->LockHeap(ETrue); |
176 } |
176 } |
177 |
177 |
178 inline void endDataAccess(CFbsBitmap *bitmap) |
178 inline void endDataAccess(CFbsBitmap *bitmap) |
179 { |
179 { |
180 if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3) { |
180 if (symbianVersion == QSysInfo::SV_9_2) { |
181 if (!heapWasLocked) |
181 if (!heapWasLocked) |
182 qt_symbianFbsClient()->unlockHeap(); |
182 qt_symbianFbsClient()->unlockHeap(); |
183 } else { |
183 } else { |
184 bitmap->UnlockHeap(ETrue); |
184 bitmap->UnlockHeap(ETrue); |
185 } |
185 } |
335 QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap) |
335 QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap) |
336 { |
336 { |
337 if (!bitmap) |
337 if (!bitmap) |
338 return QPixmap(); |
338 return QPixmap(); |
339 |
339 |
340 QPixmap pixmap; |
340 QScopedPointer<QS60PixmapData> data(new QS60PixmapData(QPixmapData::PixmapType)); |
341 pixmap.pixmapData()->fromNativeType(reinterpret_cast<void*>(bitmap), QPixmapData::FbsBitmap); |
341 data->fromNativeType(reinterpret_cast<void*>(bitmap), QPixmapData::FbsBitmap); |
|
342 QPixmap pixmap(data.take()); |
342 return pixmap; |
343 return pixmap; |
343 } |
344 } |
344 |
345 |
345 QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type), |
346 QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type), |
346 symbianBitmapDataAccess(new QSymbianBitmapDataAccess), |
347 symbianBitmapDataAccess(new QSymbianBitmapDataAccess), |
347 cfbsBitmap(0), |
348 cfbsBitmap(0), |
348 bitmapDevice(0), |
|
349 bitmapGc(0), |
|
350 pengine(0), |
349 pengine(0), |
351 bytes(0) |
350 bytes(0), |
|
351 formatLocked(false) |
352 { |
352 { |
353 |
353 |
354 } |
354 } |
355 |
355 |
356 QS60PixmapData::~QS60PixmapData() |
356 QS60PixmapData::~QS60PixmapData() |
381 |
381 |
382 TSize newSize(width, height); |
382 TSize newSize(width, height); |
383 |
383 |
384 if(cfbsBitmap->SizeInPixels() != newSize) { |
384 if(cfbsBitmap->SizeInPixels() != newSize) { |
385 cfbsBitmap->Resize(TSize(width, height)); |
385 cfbsBitmap->Resize(TSize(width, height)); |
386 bitmapDevice->Resize(TSize(width, height)); |
|
387 bitmapGc->Resized(); |
|
388 if(pengine) { |
386 if(pengine) { |
389 delete pengine; |
387 delete pengine; |
390 pengine = 0; |
388 pengine = 0; |
391 } |
389 } |
392 } |
390 } |
393 |
391 |
394 UPDATE_BUFFER(); |
392 UPDATE_BUFFER(); |
395 } |
393 } |
396 } |
394 } |
397 |
395 |
398 bool QS60PixmapData::initSymbianBitmapContext() |
|
399 { |
|
400 QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(cfbsBitmap)); |
|
401 QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL()); |
|
402 bitmapGc->Activate(bitmapDevice); |
|
403 |
|
404 return true; |
|
405 } |
|
406 |
|
407 void QS60PixmapData::release() |
396 void QS60PixmapData::release() |
408 { |
397 { |
409 if (cfbsBitmap) { |
398 if (cfbsBitmap) { |
410 QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); |
399 QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); |
411 delete bitmapGc; |
|
412 delete bitmapDevice; |
|
413 delete cfbsBitmap; |
400 delete cfbsBitmap; |
414 lock.relock(); |
401 lock.relock(); |
415 } |
402 } |
416 |
403 |
417 delete pengine; |
404 delete pengine; |
418 image = QImage(); |
405 image = QImage(); |
419 cfbsBitmap = 0; |
406 cfbsBitmap = 0; |
420 bitmapGc = 0; |
|
421 bitmapDevice = 0; |
|
422 pengine = 0; |
407 pengine = 0; |
423 bytes = 0; |
408 bytes = 0; |
424 } |
409 } |
425 |
410 |
426 /*! |
411 /*! |
427 * Takes ownership of bitmap |
412 * Takes ownership of bitmap. Used by window surface |
428 */ |
413 */ |
429 void QS60PixmapData::fromSymbianBitmap(CFbsBitmap* bitmap) |
414 void QS60PixmapData::fromSymbianBitmap(CFbsBitmap* bitmap, bool lockFormat) |
430 { |
415 { |
431 cfbsBitmap = bitmap; |
416 Q_ASSERT(bitmap); |
432 |
417 |
433 if(!initSymbianBitmapContext()) { |
418 release(); |
434 qWarning("Could not create CBitmapContext"); |
419 |
435 release(); |
420 cfbsBitmap = bitmap; |
436 return; |
421 formatLocked = lockFormat; |
437 } |
422 |
438 |
423 setSerialNumber(cfbsBitmap->Handle()); |
439 setSerialNumber(cfbsBitmap->Handle()); |
424 |
440 |
425 UPDATE_BUFFER(); |
441 UPDATE_BUFFER(); |
426 |
442 |
427 // Create default palette if needed |
443 // Create default palette if needed |
428 if (cfbsBitmap->DisplayMode() == EGray2) { |
444 if (cfbsBitmap->DisplayMode() == EGray2) { |
429 image.setColorCount(2); |
445 image.setNumColors(2); |
430 image.setColor(0, QColor(Qt::color0).rgba()); |
446 image.setColor(0, QColor(Qt::color0).rgba()); |
431 image.setColor(1, QColor(Qt::color1).rgba()); |
447 image.setColor(1, QColor(Qt::color1).rgba()); |
|
448 |
432 |
449 //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid |
433 //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid |
450 //So invert mono bitmaps so that masks work correctly. |
434 //So invert mono bitmaps so that masks work correctly. |
451 image.invertPixels(); |
435 image.invertPixels(); |
452 } else if (cfbsBitmap->DisplayMode() == EGray256) { |
436 } else if (cfbsBitmap->DisplayMode() == EGray256) { |
453 for (int i=0; i < 256; ++i) |
437 for (int i=0; i < 256; ++i) |
454 image.setColor(i, qRgb(i, i, i)); |
438 image.setColor(i, qRgb(i, i, i)); |
455 }else if (cfbsBitmap->DisplayMode() == EColor256) { |
439 } else if (cfbsBitmap->DisplayMode() == EColor256) { |
456 const TColor256Util *palette = TColor256Util::Default(); |
440 const TColor256Util *palette = TColor256Util::Default(); |
457 for (int i=0; i < 256; ++i) |
441 for (int i=0; i < 256; ++i) |
458 image.setColor(i, (QRgb)(palette->Color256(i).Value())); |
442 image.setColor(i, (QRgb)(palette->Color256(i).Value())); |
459 } |
443 } |
|
444 } |
|
445 |
|
446 QImage 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; |
460 } |
454 } |
461 |
455 |
462 void QS60PixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags) |
456 void QS60PixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags) |
463 { |
457 { |
|
458 release(); |
|
459 |
464 QImage sourceImage; |
460 QImage sourceImage; |
465 |
461 |
466 if (pixelType() == BitmapType) { |
462 if (pixelType() == BitmapType) { |
467 sourceImage = img.convertToFormat(QImage::Format_MonoLSB); |
463 sourceImage = img.convertToFormat(QImage::Format_MonoLSB); |
468 } else { |
464 } else { |
512 qWarning("Image format not supported: %d", image.format()); |
508 qWarning("Image format not supported: %d", image.format()); |
513 return; |
509 return; |
514 } |
510 } |
515 |
511 |
516 cfbsBitmap = createSymbianCFbsBitmap(TSize(sourceImage.width(), sourceImage.height()), mode); |
512 cfbsBitmap = createSymbianCFbsBitmap(TSize(sourceImage.width(), sourceImage.height()), mode); |
517 if (!(cfbsBitmap && initSymbianBitmapContext())) { |
513 if (!cfbsBitmap) { |
518 qWarning("Could not create CFbsBitmap and/or CBitmapContext"); |
514 qWarning("Could not create CFbsBitmap"); |
519 release(); |
515 release(); |
520 return; |
516 return; |
521 } |
517 } |
522 |
518 |
523 setSerialNumber(cfbsBitmap->Handle()); |
519 setSerialNumber(cfbsBitmap->Handle()); |
524 |
520 |
525 const uchar *sptr = const_cast<const QImage &>(sourceImage).bits(); |
521 const uchar *sptr = const_cast<const QImage &>(sourceImage).bits(); |
526 symbianBitmapDataAccess->beginDataAccess(cfbsBitmap); |
522 symbianBitmapDataAccess->beginDataAccess(cfbsBitmap); |
527 uchar *dptr = (uchar*)cfbsBitmap->DataAddress(); |
523 uchar *dptr = (uchar*)cfbsBitmap->DataAddress(); |
528 Mem::Copy(dptr, sptr, sourceImage.numBytes()); |
524 Mem::Copy(dptr, sptr, sourceImage.byteCount()); |
529 symbianBitmapDataAccess->endDataAccess(cfbsBitmap); |
525 symbianBitmapDataAccess->endDataAccess(cfbsBitmap); |
530 |
526 |
531 UPDATE_BUFFER(); |
527 UPDATE_BUFFER(); |
532 |
528 |
533 if (destFormat == QImage::Format_MonoLSB) { |
529 if (destFormat == QImage::Format_MonoLSB) { |
534 image.setNumColors(2); |
530 image.setColorCount(2); |
535 image.setColor(0, QColor(Qt::color0).rgba()); |
531 image.setColor(0, QColor(Qt::color0).rgba()); |
536 image.setColor(1, QColor(Qt::color1).rgba()); |
532 image.setColor(1, QColor(Qt::color1).rgba()); |
537 } else { |
533 } else { |
538 image.setColorTable(sourceImage.colorTable()); |
534 image.setColorTable(sourceImage.colorTable()); |
539 } |
535 } |
540 } |
536 } |
541 |
537 |
542 void QS60PixmapData::copy(const QPixmapData *data, const QRect &rect) |
538 void QS60PixmapData::copy(const QPixmapData *data, const QRect &rect) |
543 { |
539 { |
544 if (data->pixelType() == BitmapType) { |
|
545 QBitmap::fromImage(data->toImage().copy(rect)); |
|
546 return; |
|
547 } |
|
548 |
|
549 const QS60PixmapData *s60Data = static_cast<const QS60PixmapData*>(data); |
540 const QS60PixmapData *s60Data = static_cast<const QS60PixmapData*>(data); |
550 |
541 fromImage(s60Data->toImage(rect), Qt::AutoColor | Qt::OrderedAlphaDither); |
551 resize(rect.width(), rect.height()); |
|
552 cfbsBitmap->SetDisplayMode(s60Data->cfbsBitmap->DisplayMode()); |
|
553 |
|
554 bitmapGc->BitBlt(TPoint(0, 0), s60Data->cfbsBitmap, qt_QRect2TRect(rect)); |
|
555 } |
542 } |
556 |
543 |
557 bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect) |
544 bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect) |
558 { |
545 { |
559 beginDataAccess(); |
546 beginDataAccess(); |
682 |
664 |
683 symbianBitmapDataAccess->beginDataAccess(cfbsBitmap); |
665 symbianBitmapDataAccess->beginDataAccess(cfbsBitmap); |
684 |
666 |
685 uchar* newBytes = (uchar*)cfbsBitmap->DataAddress(); |
667 uchar* newBytes = (uchar*)cfbsBitmap->DataAddress(); |
686 |
668 |
687 if (newBytes == bytes) |
669 TSize size = cfbsBitmap->SizeInPixels(); |
|
670 |
|
671 if (newBytes == bytes && image.width() == size.iWidth && image.height() == size.iHeight) |
688 return; |
672 return; |
689 |
|
690 |
673 |
691 bytes = newBytes; |
674 bytes = newBytes; |
692 TDisplayMode mode = cfbsBitmap->DisplayMode(); |
675 TDisplayMode mode = cfbsBitmap->DisplayMode(); |
693 QImage::Format format = qt_TDisplayMode2Format(mode); |
676 QImage::Format format = qt_TDisplayMode2Format(mode); |
694 //on S60 3.1, premultiplied alpha pixels are stored in a bitmap with 16MA type |
677 // On S60 3.1, premultiplied alpha pixels are stored in a bitmap with 16MA type. |
695 if (format == QImage::Format_ARGB32) |
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) |
696 format = QImage::Format_ARGB32_Premultiplied; // pixel data is actually in premultiplied format |
681 format = QImage::Format_ARGB32_Premultiplied; // pixel data is actually in premultiplied format |
697 |
|
698 TSize size = cfbsBitmap->SizeInPixels(); |
|
699 |
682 |
700 QVector<QRgb> savedColorTable; |
683 QVector<QRgb> savedColorTable; |
701 if (!image.isNull()) |
684 if (!image.isNull()) |
702 savedColorTable = image.colorTable(); |
685 savedColorTable = image.colorTable(); |
703 |
686 |
814 TDisplayMode displayMode = cfbsBitmap->DisplayMode(); |
797 TDisplayMode displayMode = cfbsBitmap->DisplayMode(); |
815 |
798 |
816 if(displayMode == EGray2) { |
799 if(displayMode == EGray2) { |
817 //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid |
800 //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid |
818 //So invert mono bitmaps so that masks work correctly. |
801 //So invert mono bitmaps so that masks work correctly. |
|
802 beginDataAccess(); |
819 image.invertPixels(); |
803 image.invertPixels(); |
|
804 endDataAccess(); |
820 needsCopy = true; |
805 needsCopy = true; |
821 } |
806 } |
822 |
807 |
823 if (needsCopy) { |
808 if (needsCopy) { |
824 QImage source; |
809 QImage source; |
825 |
810 |
826 if (convertToArgb32) { |
811 if (convertToArgb32) { |
|
812 beginDataAccess(); |
827 source = image.convertToFormat(QImage::Format_ARGB32); |
813 source = image.convertToFormat(QImage::Format_ARGB32); |
|
814 endDataAccess(); |
828 displayMode = EColor16MA; |
815 displayMode = EColor16MA; |
829 } else { |
816 } else { |
830 source = image; |
817 source = image; |
831 } |
818 } |
832 |
819 |
833 CFbsBitmap *newBitmap = createSymbianCFbsBitmap(TSize(source.width(), source.height()), displayMode); |
820 CFbsBitmap *newBitmap = createSymbianCFbsBitmap(TSize(source.width(), source.height()), displayMode); |
834 const uchar *sptr = source.bits(); |
821 const uchar *sptr = source.bits(); |
835 symbianBitmapDataAccess->beginDataAccess(newBitmap); |
822 symbianBitmapDataAccess->beginDataAccess(newBitmap); |
836 |
823 |
837 uchar *dptr = (uchar*)newBitmap->DataAddress(); |
824 uchar *dptr = (uchar*)newBitmap->DataAddress(); |
838 Mem::Copy(dptr, sptr, source.numBytes()); |
825 Mem::Copy(dptr, sptr, source.byteCount()); |
839 |
826 |
840 symbianBitmapDataAccess->endDataAccess(newBitmap); |
827 symbianBitmapDataAccess->endDataAccess(newBitmap); |
841 |
828 |
842 bitmap = newBitmap; |
829 bitmap = newBitmap; |
843 } else { |
830 } else { |
933 |
922 |
934 QSymbianBitmapDataAccess da; |
923 QSymbianBitmapDataAccess da; |
935 da.beginDataAccess(sourceBitmap); |
924 da.beginDataAccess(sourceBitmap); |
936 uchar *bytes = (uchar*)sourceBitmap->DataAddress(); |
925 uchar *bytes = (uchar*)sourceBitmap->DataAddress(); |
937 QImage img = QImage(bytes, size.iWidth, size.iHeight, format); |
926 QImage img = QImage(bytes, size.iWidth, size.iHeight, format); |
|
927 img = img.copy(); |
938 da.endDataAccess(sourceBitmap); |
928 da.endDataAccess(sourceBitmap); |
939 |
|
940 fromImage(img, Qt::AutoColor); |
|
941 |
|
942 if(deleteSourceBitmap) |
|
943 delete sourceBitmap; |
|
944 |
929 |
945 if(displayMode == EGray2) { |
930 if(displayMode == EGray2) { |
946 //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid |
931 //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid |
947 //So invert mono bitmaps so that masks work correctly. |
932 //So invert mono bitmaps so that masks work correctly. |
948 image.invertPixels(); |
933 img.invertPixels(); |
|
934 } else if(displayMode == EColor16M) { |
|
935 img = img.rgbSwapped(); // EColor16M is BGR |
949 } |
936 } |
|
937 |
|
938 fromImage(img, Qt::AutoColor); |
|
939 |
|
940 if(deleteSourceBitmap) |
|
941 delete sourceBitmap; |
950 } else { |
942 } else { |
951 CFbsBitmap* duplicate = 0; |
943 CFbsBitmap* duplicate = 0; |
952 QT_TRAP_THROWING(duplicate = new (ELeave) CFbsBitmap); |
944 QT_TRAP_THROWING(duplicate = new (ELeave) CFbsBitmap); |
953 |
945 |
954 TInt err = duplicate->Duplicate(sourceBitmap->Handle()); |
946 TInt err = duplicate->Duplicate(sourceBitmap->Handle()); |