summaryrefslogtreecommitdiffstats
path: root/src/gui/image/qpixmap_s60.cpp
diff options
context:
space:
mode:
authorJani Hautakangas <ext-jani.hautakangas@nokia.com>2009-09-18 11:33:10 (GMT)
committerJani Hautakangas <ext-jani.hautakangas@nokia.com>2009-09-18 11:33:10 (GMT)
commitc78dabc55943b76479f7a84bae146f52cbc7bbbf (patch)
tree5ea4392cf14c1126c82603b9ee614c384f28bd9e /src/gui/image/qpixmap_s60.cpp
parent6454aca1b273daa2e54a77f83e1f6d4bae83427d (diff)
downloadQt-c78dabc55943b76479f7a84bae146f52cbc7bbbf.zip
Qt-c78dabc55943b76479f7a84bae146f52cbc7bbbf.tar.gz
Qt-c78dabc55943b76479f7a84bae146f52cbc7bbbf.tar.bz2
Introduce native Symbian bitmap support to QPixmap
This is done to reduce heap consumption and to give a possibility to share bitmaps across process. QPixmap maps to Symbian CFbsBitmap which is stored in Symbian font and bitmap server. Reviewed-by: Jason Barron
Diffstat (limited to 'src/gui/image/qpixmap_s60.cpp')
-rw-r--r--src/gui/image/qpixmap_s60.cpp891
1 files changed, 773 insertions, 118 deletions
diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp
index 666e557..8a6ecb0 100644
--- a/src/gui/image/qpixmap_s60.cpp
+++ b/src/gui/image/qpixmap_s60.cpp
@@ -43,17 +43,218 @@
#include <fbs.h>
#include <private/qt_s60_p.h>
+#include <private/qpaintengine_s60_p.h>
+
#include "qpixmap.h"
#include "qpixmap_raster_p.h"
#include <qwidget.h>
+#include "qpixmap_s60_p.h"
+#include "qnativeimage_p.h"
+#include "qbitmap.h"
+#include "qimage.h"
+#include "qimage_p.h"
+
+#include <fbs.h>
QT_BEGIN_NAMESPACE
-QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h )
+const uchar qt_pixmap_bit_mask[] = { 0x01, 0x02, 0x04, 0x08,
+ 0x10, 0x20, 0x40, 0x80 };
+
+
+
+/*!
+ \since 4.6
+
+ Symbian Font And Bitmap server client that is
+ used to lock the global bitmap heap. Only used in
+ S60 v3.1 and S60 v3.2.
+*/
+class QSymbianFbsClient
+{
+public:
+
+ QSymbianFbsClient() : heapLock(0), heapLocked(false)
+ {
+ QT_TRAP_THROWING(heapLock = new(ELeave) CFbsBitmap);
+ heapLock->Create(TSize(0,0), S60->screenDevice()->DisplayMode());
+ }
+
+ ~QSymbianFbsClient()
+ {
+ delete heapLock;
+ }
+
+ bool lockHeap()
+ {
+ bool wasLocked = heapLocked;
+
+ if (heapLock && !heapLocked) {
+ heapLock->LockHeap(ETrue);
+ heapLocked = true;
+ }
+
+ return wasLocked;
+ }
+
+ bool unlockHeap()
+ {
+ bool wasLocked = heapLocked;
+
+ if (heapLock && heapLocked) {
+ heapLock->UnlockHeap(ETrue);
+ heapLocked = false;
+ }
+
+ return wasLocked;
+ }
+
+
+private:
+
+ CFbsBitmap *heapLock;
+ bool heapLocked;
+};
+
+Q_GLOBAL_STATIC(QSymbianFbsClient, qt_symbianFbsClient);
+
+
+
+// QSymbianFbsHeapLock
+
+QSymbianFbsHeapLock::QSymbianFbsHeapLock(LockAction a)
+: action(a), wasLocked(false)
+{
+ QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion();
+ if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3)
+ wasLocked = qt_symbianFbsClient()->unlockHeap();
+}
+
+QSymbianFbsHeapLock::~QSymbianFbsHeapLock()
+{
+ // Do nothing
+}
+
+void QSymbianFbsHeapLock::relock()
+{
+ QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion();
+ if (wasLocked && (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3))
+ qt_symbianFbsClient()->lockHeap();
+}
+
+/*!
+ \since 4.6
+
+ Data access class that is used to locks/unlocks pixel data
+ when drawing or modifying CFbsBitmap pixel data.
+*/
+class QSymbianBitmapDataAccess
+{
+public:
+
+ bool heapWasLocked;
+ QSysInfo::SymbianVersion symbianVersion;
+
+ explicit QSymbianBitmapDataAccess() : heapWasLocked(false)
+ {
+ symbianVersion = QSysInfo::symbianVersion();
+ };
+
+ ~QSymbianBitmapDataAccess() {};
+
+ inline void beginDataAccess(CFbsBitmap *bitmap)
+ {
+ if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3)
+ heapWasLocked = qt_symbianFbsClient()->lockHeap();
+ else
+ bitmap->LockHeap(ETrue);
+ }
+
+ inline void endDataAccess(CFbsBitmap *bitmap)
+ {
+ if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3) {
+ if (!heapWasLocked)
+ qt_symbianFbsClient()->unlockHeap();
+ } else {
+ bitmap->UnlockHeap(ETrue);
+ }
+ }
+};
+
+
+#define UPDATE_BUFFER() \
+ { \
+ beginDataAccess(); \
+ endDataAccess(); \
+}
+
+
+static CFbsBitmap* createSymbianCFbsBitmap(const TSize& size, TDisplayMode mode)
+{
+ QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
+
+ CFbsBitmap* bitmap = 0;
+ QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap);
+
+ if (bitmap->Create(size, mode) != KErrNone) {
+ delete bitmap;
+ bitmap = 0;
+ }
+
+ lock.relock();
+
+ return bitmap;
+}
+
+static CFbsBitmap* uncompress(CFbsBitmap* bitmap)
+{
+ if(bitmap->IsCompressedInRAM()) {
+ QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
+
+ CFbsBitmap *uncompressed = 0;
+ QT_TRAP_THROWING(uncompressed = new (ELeave) CFbsBitmap);
+
+ if (uncompressed->Create(bitmap->SizeInPixels(), bitmap->DisplayMode()) != KErrNone) {
+ delete bitmap;
+ bitmap = 0;
+ lock.relock();
+
+ return bitmap;
+ }
+
+ lock.relock();
+
+ CBitmapContext *bitmapContext = 0;
+ CFbsBitmapDevice* bitmapDevice = 0;
+ QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(uncompressed));
+ TInt err = bitmapDevice->CreateBitmapContext(bitmapContext);
+ if (err != KErrNone) {
+ delete bitmap;
+ delete bitmapDevice;
+ bitmap = 0;
+ bitmapDevice = 0;
+
+ lock.relock();
+
+ return bitmap;
+ }
+
+ bitmapContext->DrawBitmap(TPoint(), bitmap);
+
+ delete bitmapContext;
+ delete bitmapDevice;
+
+ return uncompressed;
+ } else {
+ return bitmap;
+ }
+}
+
+QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h)
{
CWsScreenDevice* screenDevice = S60->screenDevice();
TSize screenSize = screenDevice->SizeInPixels();
-
+
TSize srcSize;
// Find out if this is one of our windows.
QSymbianControl *sControl;
@@ -67,178 +268,632 @@ QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h )
y += relativePos.iY;
srcSize = winId->Size();
}
-
+
TRect srcRect(TPoint(x, y), srcSize);
// Clip to the screen
srcRect.Intersection(TRect(screenSize));
-
+
if (w > 0 && h > 0) {
TRect subRect(TPoint(x, y), TSize(w, h));
// Clip to the subRect
srcRect.Intersection(subRect);
}
-
+
if (srcRect.IsEmpty())
return QPixmap();
-
- TDisplayMode displayMode = screenDevice->DisplayMode();
- CFbsBitmap* temporary = q_check_ptr(new CFbsBitmap()); // CBase derived object needs check on new
- TInt error = temporary->Create(srcRect.Size(), displayMode);
- if (error == KErrNone)
- error = screenDevice->CopyScreenToBitmap(temporary, srcRect);
-
- if (error != KErrNone) {
- CBase::Delete(temporary);
- return QPixmap();
+
+ CFbsBitmap* temporary = createSymbianCFbsBitmap(srcRect.Size(), screenDevice->DisplayMode());
+
+ QPixmap pix;
+
+ if (temporary && screenDevice->CopyScreenToBitmap(temporary, srcRect) == KErrNone) {
+ pix = QPixmap::fromSymbianCFbsBitmap(temporary);
}
-
- QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(temporary);
- CBase::Delete(temporary);
- return pixmap;
+
+ delete temporary;
+ return pix;
}
/*!
-\since 4.6
+ \enum QPixmap::ConversionMode
+
+ \bold{Symbian only:} This enum defines how the conversion between \c
+ CFbsBitmap and QPixmap is performed.
-Returns a \c CFbsBitmap that is equivalent to the QPixmap by copying the data.
+ \warning This enum is only available on Symbian.
-It is the caller's responsibility to delete the \c CFbsBitmap after use.
+ \value CopyData Copied CFbsBitmap data.
-\warning This function is only available on Symbian OS.
+ \value DuplicateHandle Duplicates CFbsBitmap handle. This also means
+ that pixmap data will be explicitly shared.
-\sa fromSymbianCFbsBitmap()
+ \sa fromSymbianCFbsBitmap(), toSymbianCFbsBitmap()
*/
-CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const
+
+/*!
+ \fn CFbsBitmap *QPixmap::toSymbianCFbsBitmap(ConversionMode mode)
+ \since 4.6
+
+ Creates \c CFbsBitmap that is equivalent to the QPixmap, based on
+ the given \a mode. If the creation then this function returns 0.
+
+ It is the caller's responsibility to release the \c CFbsBitmap data
+ after use either by deleting the bitmap or calling \c Reset().
+
+ \warning On S60 3.1 and S60 3.2 conversion mode will always be CopyData
+ if QPixmap pixels have alpha values.
+ \warning This function is only available on Symbian OS.
+
+ \sa fromSymbianCFbsBitmap()
+*/
+CFbsBitmap *QPixmap::toSymbianCFbsBitmap(ConversionMode mode) const
{
- if (isNull())
+ QS60PixmapData *s60data = static_cast<QS60PixmapData *>(data.data());
+
+ if (isNull() || !s60data->cfbsBitmap)
return 0;
+
+ bool convertToArgb32 = false;
+
+ QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion();
+ if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3) {
+ // Convert argb32_premultiplied to argb32 since Symbian 9.2 and Symbian 9.3 do
+ // not support premultipied format.
+
+ if (s60data->image.format() == QImage::Format_ARGB32_Premultiplied) {
+ mode = CopyData;
+ convertToArgb32 = true;
+ }
+ }
+
+ CFbsBitmap *bitmap = 0;
+
+ TDisplayMode displayMode = s60data->cfbsBitmap->DisplayMode();
+
+ if(displayMode == EGray2) {
+ //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
+ //So invert mono bitmaps so that masks work correctly.
+ s60data->image.invertPixels();
+ mode = CopyData;
+ }
+
+ if (mode == CopyData) {
+ QImage source;
+
+ if (convertToArgb32) {
+ source = s60data->image.convertToFormat(QImage::Format_ARGB32);
+ displayMode = EColor16MA;
+ } else {
+ source = s60data->image;
+ }
+
+ CFbsBitmap *newBitmap = createSymbianCFbsBitmap(TSize(source.width(), source.height()), displayMode);
+ const uchar *sptr = source.bits();
+ s60data->symbianBitmapDataAccess->beginDataAccess(newBitmap);
+
+ uchar *dptr = (uchar*)newBitmap->DataAddress();
+ Mem::Copy(dptr, sptr, source.numBytes());
+
+ s60data->symbianBitmapDataAccess->endDataAccess(newBitmap);
+
+ bitmap = newBitmap;
+ } else {
+
+ QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap);
+
+ TInt err = bitmap->Duplicate(s60data->cfbsBitmap->Handle());
+ if (err != KErrNone) {
+ qWarning("Could not duplicate CFbsBitmap");
+ delete bitmap;
+ bitmap = 0;
+ }
+ }
+
+ if(displayMode == EGray2) {
+ // restore pixels
+ s60data->image.invertPixels();
+ }
+
+ return bitmap;
+}
+
+/*!
+ \fn QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap, ConversionMode mode)
+ \since 4.6
+
+ Creates a QPixmap from native \c CFbsBitmap \a bitmap. The conversion
+ is based on the specified \a mode. Conversion mode is always QPixmap::CopyData
+ if given \a bitmap does not have display mode of TDisplayMode::EGray2,
+ \c TDisplayMode::EColor16MU or \c TDisplayMode::EColor16MAP.
+
+ If the CFbsBitmap is not valid this function will return a null QPixmap.
+
+ \warning This function is only available on Symbian OS.
+
+ \sa toSymbianCFbsBitmap(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
+*/
+QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap, ConversionMode mode)
+{
+ if (bitmap) {
+
+ bool deleteSourceBitmap = false;
+
+#if Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE
+
+ // Rasterize extended bitmaps
+
+ TUid extendedBitmapType = = bitmap->ExtendedBitmapType();
+ if (extendedBitmapType != KNullUid) {
+ CFbsBitmap *rasterBitmap = createSymbianCFbsBitmap(bitmap->SizeInPixels(), EColor16MA);
+
+ CFbsBitmapDevice *rasterBitmapDev = 0;
+ QT_TRAP_THROWING(rasterBitmapDev = CFbsBitmapDevice::NewL(rasterBitmap));
+
+ CFbsBitGc *rasterBitmapGc = 0;
+ TInt err = rasterBitmapDev->CreateContext(rasterBitmapGc);
+ if (err != KErrNone) {
+ delete rasterBitmap;
+ delete rasterBitmapDev;
+ rasterBitmapDev = 0;
+ return QPixmap();
+ }
+
+ rasterBitmapGc->BitBlt(TPoint( 0, 0), bitmap);
+
+ bitmap = rasterBitmap;
+
+ delete rasterBitmapDev;
+ delete rasterBitmapGc;
+
+ rasterBitmapDev = 0;
+ rasterBitmapGc = 0;
+
+ deleteSourceBitmap = true;
+ }
+#endif
+
+
+ deleteSourceBitmap = bitmap->IsCompressedInRAM();
+ CFbsBitmap *sourceBitmap = uncompress(bitmap);
+
+ TDisplayMode displayMode = sourceBitmap->DisplayMode();
+ QImage::Format format = qt_TDisplayMode2Format(displayMode);
+
+ QImage::Format opaqueFormat = QNativeImage::systemFormat();
+ QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied;
+
+ if (format != opaqueFormat && format != alphaFormat && format != QImage::Format_MonoLSB)
+ mode = CopyData;
+
+
+ QPixmapData::PixelType type = (format!=QImage::Format_MonoLSB)
+ ? QPixmapData::PixmapType
+ : QPixmapData::BitmapType;
+
+ QS60PixmapData *pixmapData = 0;
+
+ if (mode == CopyData) {
+
+ TSize size = sourceBitmap->SizeInPixels();
+
+ QSymbianBitmapDataAccess da;
+ da.beginDataAccess(sourceBitmap);
+ uchar *bytes = (uchar*)sourceBitmap->DataAddress();
+ QImage img = QImage(bytes, size.iWidth, size.iHeight, format);
+ da.endDataAccess(sourceBitmap);
+
+ pixmapData = new QS60PixmapData(type);
+ pixmapData->fromImage(img, Qt::AutoColor);
+
+ if(deleteSourceBitmap)
+ delete sourceBitmap;
+
+ if(displayMode == EGray2) {
+ //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
+ //So invert mono bitmaps so that masks work correctly.
+ pixmapData->image.invertPixels();
+ }
+ } else {
+ CFbsBitmap* duplicate = 0;
+ QT_TRAP_THROWING(duplicate = new (ELeave) CFbsBitmap);
+
+ TInt err = duplicate->Duplicate(sourceBitmap->Handle());
+ if (err != KErrNone) {
+ qWarning("Could not duplicate CFbsBitmap");
+
+ if(deleteSourceBitmap)
+ delete sourceBitmap;
+
+ delete duplicate;
+ return QPixmap();
+ }
+
+ pixmapData = new QS60PixmapData(type);
+ pixmapData->fromSymbianBitmap(duplicate);
+
+ if(deleteSourceBitmap)
+ delete sourceBitmap;
+ }
+
+ return QPixmap(pixmapData);
+ }
+
+ return QPixmap();
+}
+
+QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type),
+ symbianBitmapDataAccess(new QSymbianBitmapDataAccess),
+ cfbsBitmap(0),
+ bitmapDevice(0),
+ bitmapContext(0),
+ pengine(0),
+ bytes(0)
+{
+
+}
+QS60PixmapData::~QS60PixmapData()
+{
+ release();
+}
+
+void QS60PixmapData::resize(int width, int height)
+{
+ if (width <= 0 || height <= 0) {
+ w = width;
+ h = height;
+ is_null = true;
+
+ release();
+ return;
+ } else if (!cfbsBitmap) {
+ TDisplayMode mode;
+ if (pixelType() == BitmapType)
+ mode = EGray2;
+ else
+ mode = EColor16MU;
+
+ CFbsBitmap* bitmap = createSymbianCFbsBitmap(TSize(width, height), mode);
+ fromSymbianBitmap(bitmap);
+ } else {
+
+ TSize newSize(width, height);
+
+ if(cfbsBitmap->SizeInPixels() != newSize) {
+ cfbsBitmap->Resize(TSize(width, height));
+ if(pengine) {
+ delete pengine;
+ pengine = 0;
+ }
+ }
+
+ UPDATE_BUFFER();
+ }
+}
+
+bool QS60PixmapData::initSymbianBitmapContext()
+{
+ QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(cfbsBitmap));
+ TInt err = bitmapDevice->CreateBitmapContext(bitmapContext);
+ if (err != KErrNone) {
+ delete bitmapDevice;
+ bitmapDevice = 0;
+ return false;
+ }
+ return true;
+}
+
+void QS60PixmapData::release()
+{
+ if (cfbsBitmap) {
+ QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
+ delete bitmapContext;
+ delete bitmapDevice;
+ delete cfbsBitmap;
+ lock.relock();
+ }
+
+ delete pengine;
+ image = QImage();
+ cfbsBitmap = 0;
+ bitmapContext = 0;
+ bitmapDevice = 0;
+ pengine = 0;
+ bytes = 0;
+}
+
+/*!
+ * Takes ownership of bitmap
+ */
+void QS60PixmapData::fromSymbianBitmap(CFbsBitmap* bitmap)
+{
+ cfbsBitmap = bitmap;
+
+ if(!initSymbianBitmapContext()) {
+ qWarning("Could not create CBitmapContext");
+ release();
+ return;
+ }
+
+ setSerialNumber(cfbsBitmap->Handle());
+
+ UPDATE_BUFFER();
+
+ // Create default palette if needed
+ if (cfbsBitmap->DisplayMode() == EGray2) {
+ image.setNumColors(2);
+ image.setColor(0, QColor(Qt::color0).rgba());
+ image.setColor(1, QColor(Qt::color1).rgba());
+
+ //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
+ //So invert mono bitmaps so that masks work correctly.
+ image.invertPixels();
+ } else if (cfbsBitmap->DisplayMode() == EGray256) {
+ for (int i=0; i < 256; ++i)
+ image.setColor(i, qRgb(i, i, i));
+ }else if (cfbsBitmap->DisplayMode() == EColor256) {
+ const TColor256Util *palette = TColor256Util::Default();
+ for (int i=0; i < 256; ++i)
+ image.setColor(i, (QRgb)(palette->Color256(i).Value()));
+ }
+}
+
+void QS60PixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags)
+{
+ QImage sourceImage;
+
+ if (pixelType() == BitmapType) {
+ sourceImage = img.convertToFormat(QImage::Format_MonoLSB);
+ } else {
+ if (img.depth() == 1) {
+ image = img.hasAlphaChannel()
+ ? img.convertToFormat(QImage::Format_ARGB32_Premultiplied)
+ : img.convertToFormat(QImage::Format_RGB32);
+ } else {
+
+ QImage::Format opaqueFormat = QNativeImage::systemFormat();
+ QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied;
+
+ if (!img.hasAlphaChannel()
+ || ((flags & Qt::NoOpaqueDetection) == 0
+ && !const_cast<QImage &>(img).data_ptr()->checkForAlphaPixels())) {
+ sourceImage = img.convertToFormat(opaqueFormat);
+ } else {
+ sourceImage = img.convertToFormat(alphaFormat);
+ }
+ }
+ }
+
+
+ QImage::Format destFormat = sourceImage.format();
TDisplayMode mode;
- const QImage img = toImage();
- QImage::Format destFormat = img.format();
- switch (img.format()) {
- case QImage::Format_Mono:
- destFormat = QImage::Format_MonoLSB;
- // Fall through intended
+ switch (destFormat) {
case QImage::Format_MonoLSB:
mode = EGray2;
break;
- case QImage::Format_Indexed8:
- if (img.isGrayscale())
- mode = EGray256;
- else
- mode = EColor256;
- break;
case QImage::Format_RGB32:
mode = EColor16MU;
break;
- case QImage::Format_ARGB6666_Premultiplied:
- case QImage::Format_ARGB8565_Premultiplied:
- case QImage::Format_ARGB8555_Premultiplied:
- destFormat = QImage::Format_ARGB32_Premultiplied;
- // Fall through intended
case QImage::Format_ARGB32_Premultiplied:
#if !defined(__SERIES60_31__) && !defined(__S60_32__)
- // ### TODO: Add runtime detection as well?
mode = EColor16MAP;
- break;
+ break;
#endif
destFormat = QImage::Format_ARGB32;
// Fall through intended
case QImage::Format_ARGB32:
mode = EColor16MA;
break;
- case QImage::Format_RGB555:
- destFormat = QImage::Format_RGB16;
- // Fall through intended
- case QImage::Format_RGB16:
- mode = EColor64K;
- break;
- case QImage::Format_RGB666:
- destFormat = QImage::Format_RGB888;
- // Fall through intended
- case QImage::Format_RGB888:
- mode = EColor16M;
- break;
- case QImage::Format_RGB444:
- mode = EColor4K;
- break;
case QImage::Format_Invalid:
- return 0;
+ return;
default:
- qWarning("Image format not supported: %d", img.format());
- return 0;
+ qWarning("Image format not supported: %d", image.format());
+ return;
+ }
+
+ cfbsBitmap = createSymbianCFbsBitmap(TSize(sourceImage.width(), sourceImage.height()), mode);
+ if (!(cfbsBitmap && initSymbianBitmapContext())) {
+ qWarning("Could not create CFbsBitmap and/or CBitmapContext");
+ release();
+ return;
}
+
+ setSerialNumber(cfbsBitmap->Handle());
+
+ const uchar *sptr = const_cast<const QImage &>(sourceImage).bits();
+ symbianBitmapDataAccess->beginDataAccess(cfbsBitmap);
+ uchar *dptr = (uchar*)cfbsBitmap->DataAddress();
+ Mem::Copy(dptr, sptr, sourceImage.numBytes());
+ symbianBitmapDataAccess->endDataAccess(cfbsBitmap);
+
+ UPDATE_BUFFER();
+
+ if (destFormat == QImage::Format_MonoLSB) {
+ image.setNumColors(2);
+ image.setColor(0, QColor(Qt::color0).rgba());
+ image.setColor(1, QColor(Qt::color1).rgba());
+ } else {
+ image.setColorTable(sourceImage.colorTable());
+ }
+}
- CFbsBitmap* bitmap = q_check_ptr(new CFbsBitmap()); // CBase derived object needs check on new
- TSize size(width(), height());
- if (bitmap->Create(size, mode) != KErrNone) {
- CBase::Delete(bitmap);
- return 0;
+void QS60PixmapData::copy(const QPixmapData *data, const QRect &rect)
+{
+ if (data->pixelType() == BitmapType) {
+ QBitmap::fromImage(data->toImage().copy(rect));
+ return;
}
+
+ const QS60PixmapData *s60Data = static_cast<const QS60PixmapData*>(data);
+
+ resize(rect.width(), rect.height());
+ cfbsBitmap->SetDisplayMode(s60Data->cfbsBitmap->DisplayMode());
+
+ bitmapContext->BitBlt(TPoint(0, 0), s60Data->cfbsBitmap, qt_QRect2TRect(rect));
+}
- QImage converted = img.convertToFormat(destFormat);
+bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect)
+{
+ bitmapContext->CopyRect(TPoint(dx, dy), qt_QRect2TRect(rect));
+ return true;
+}
- //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
- //So invert mono bitmaps so that masks work correctly.
- if (mode == EGray2)
- converted.invertPixels();
+int QS60PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
+{
+ if (!cfbsBitmap)
+ return 0;
- bitmap->LockHeap();
- const uchar *sptr = converted.bits();
- uchar *dptr = (uchar*)bitmap->DataAddress();
- Mem::Copy(dptr, sptr, converted.numBytes());
- bitmap->UnlockHeap();
- return bitmap;
-}
+ switch (metric) {
+ case QPaintDevice::PdmWidth:
+ return cfbsBitmap->SizeInPixels().iWidth;
+ case QPaintDevice::PdmHeight:
+ return cfbsBitmap->SizeInPixels().iHeight;
+ case QPaintDevice::PdmWidthMM: {
+ TInt twips = cfbsBitmap->SizeInTwips().iWidth;
+ return (int)(twips * (25.4/KTwipsPerInch));
+ }
+ case QPaintDevice::PdmHeightMM: {
+ TInt twips = cfbsBitmap->SizeInTwips().iHeight;
+ return (int)(twips * (25.4/KTwipsPerInch));
+ }
+ case QPaintDevice::PdmNumColors:
+ return TDisplayModeUtils::NumDisplayModeColors(cfbsBitmap->DisplayMode());
+ case QPaintDevice::PdmDpiX:
+ case QPaintDevice::PdmPhysicalDpiX: {
+ TReal inches = cfbsBitmap->SizeInTwips().iWidth / (TReal)KTwipsPerInch;
+ TInt pixels = cfbsBitmap->SizeInPixels().iWidth;
+ return pixels / inches;
+ }
+ case QPaintDevice::PdmDpiY:
+ case QPaintDevice::PdmPhysicalDpiY: {
+ TReal inches = cfbsBitmap->SizeInTwips().iHeight / (TReal)KTwipsPerInch;
+ TInt pixels = cfbsBitmap->SizeInPixels().iHeight;
+ return pixels / inches;
+ }
+ case QPaintDevice::PdmDepth:
+ return TDisplayModeUtils::NumDisplayModeBitsPerPixel(cfbsBitmap->DisplayMode());
+ default:
+ qWarning("QPixmap::metric: Invalid metric command");
+ }
+ return 0;
-/*!
- \since 4.6
+}
- Returns a QPixmap that is equivalent to the \c CFbsBitmap \a bitmap
- by copying the data. If the CFbsBitmap is not valid or is compressed
- in memory, this function will return a null QPixmap.
+void QS60PixmapData::fill(const QColor &color)
+{
+ if (color.alpha() != 255) {
+ QImage im(width(), height(), QImage::Format_ARGB32_Premultiplied);
+ im.fill(PREMUL(color.rgba()));
+ release();
+ fromImage(im, Qt::AutoColor | Qt::OrderedAlphaDither);
+ } else {
+ beginDataAccess();
+ QRasterPixmapData::fill(color);
+ endDataAccess();
+ }
+}
- \warning This function is only available on Symbian OS.
+void QS60PixmapData::setMask(const QBitmap &mask)
+{
+ if (mask.size().isEmpty()) {
+ if (image.depth() != 1) {
+ QImage newImage = image.convertToFormat(QImage::Format_RGB32);
+ release();
+ fromImage(newImage, Qt::AutoColor | Qt::OrderedAlphaDither);
+ }
+ } else if (image.depth() == 1) {
+ beginDataAccess();
+ QRasterPixmapData::setMask(mask);
+ endDataAccess();
+ } else {
+ const int w = image.width();
+ const int h = image.height();
+
+ const QImage imageMask = mask.toImage().convertToFormat(QImage::Format_MonoLSB);
+ QImage newImage = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ for (int y = 0; y < h; ++y) {
+ const uchar *mscan = imageMask.scanLine(y);
+ QRgb *tscan = (QRgb *)newImage.scanLine(y);
+ for (int x = 0; x < w; ++x) {
+ if (!(mscan[x>>3] & qt_pixmap_bit_mask[x&7]))
+ tscan[x] = 0;
+ }
+ }
+ release();
+ fromImage(newImage, Qt::AutoColor | Qt::OrderedAlphaDither);
+ }
+}
- \sa toSymbianCFbsBitmap(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
-*/
+void QS60PixmapData::setAlphaChannel(const QPixmap &alphaChannel)
+{
+ QImage img(toImage());
+ img.setAlphaChannel(alphaChannel.toImage());
+ release();
+ fromImage(img, Qt::OrderedDither | Qt::OrderedAlphaDither);
+}
-QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap)
+QImage QS60PixmapData::toImage() const
{
- if (!bitmap)
- return QPixmap();
+ return image;
+}
- int width = bitmap->SizeInPixels().iWidth;
- int height = bitmap->SizeInPixels().iHeight;
+QPaintEngine* QS60PixmapData::paintEngine() const
+{
+ if (!pengine) {
+ QS60PixmapData *that = const_cast<QS60PixmapData*>(this);
+ that->pengine = new QS60PaintEngine(&that->image, that);
+ }
+ return pengine;
+}
- if (width <= 0 || height <= 0 || bitmap->IsCompressedInRAM())
- return QPixmap();
+void QS60PixmapData::beginDataAccess()
+{
+ if(!cfbsBitmap)
+ return;
+
+ symbianBitmapDataAccess->beginDataAccess(cfbsBitmap);
+
+ uchar* newBytes = (uchar*)cfbsBitmap->DataAddress();
+
+ if (newBytes == bytes)
+ return;
+
+
+ bytes = newBytes;
+ TDisplayMode mode = cfbsBitmap->DisplayMode();
+ QImage::Format format = qt_TDisplayMode2Format(mode);
+ TSize size = cfbsBitmap->SizeInPixels();
+
+ QVector<QRgb> savedColorTable;
+ if (!image.isNull())
+ savedColorTable = image.colorTable();
+
+ image = QImage(bytes, size.iWidth, size.iHeight, format);
+
+ // Restore the palette or create a default
+ if (!savedColorTable.isEmpty()) {
+ image.setColorTable(savedColorTable);
+ }
+
+ w = size.iWidth;
+ h = size.iHeight;
+ d = image.depth();
+ is_null = (w <= 0 || h <= 0);
+
+ if (pengine) {
+ QS60PaintEngine *engine = static_cast<QS60PaintEngine *>(pengine);
+ engine->prepare(&image);
+ }
+}
- TDisplayMode displayMode = bitmap->DisplayMode();
- QImage::Format format = qt_TDisplayMode2Format(displayMode);
- int bytesPerLine = CFbsBitmap::ScanLineLength(width, displayMode);
- bitmap->LockHeap();
- QImage image = QImage((const uchar*)bitmap->DataAddress(), width, height, bytesPerLine, format);
- if (displayMode == EGray2) {
- image.setNumColors(2);
- image.setColor(0, QColor(Qt::color0).rgba());
- image.setColor(1, QColor(Qt::color1).rgba());
- //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
- //So invert mono bitmaps so that masks work correctly.
- image.invertPixels();
- } else if (displayMode == EGray256) {
- for (int i=0; i < 256; ++i)
- image.setColor(i, qRgb(i, i, i));
- }else if (displayMode == EColor256) {
- const TColor256Util *palette = TColor256Util::Default();
- for (int i=0; i < 256; ++i)
- image.setColor(i, (QRgb)(palette->Color256(i).Value()));
- }
- QPixmap pixmap = QPixmap::fromImage(image.copy());
- bitmap->UnlockHeap();
- return pixmap;
+void QS60PixmapData::endDataAccess(bool readOnly) const
+{
+ if(!cfbsBitmap)
+ return;
+
+ symbianBitmapDataAccess->endDataAccess(cfbsBitmap);
}
+
QT_END_NAMESPACE