--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/image/qpixmap_s60.cpp Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,973 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <exception>
+#include <w32std.h>
+#include <fbs.h>
+
+#include <private/qapplication_p.h>
+#include <private/qgraphicssystem_p.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
+
+const uchar qt_pixmap_bit_mask[] = { 0x01, 0x02, 0x04, 0x08,
+ 0x10, 0x20, 0x40, 0x80 };
+
+
+/*
+ \class QSymbianFbsClient
+ \since 4.6
+ \internal
+
+ 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();
+}
+
+/*
+ \class QSymbianBitmapDataAccess
+ \since 4.6
+ \internal
+
+ 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();
+
+ CFbsBitmapDevice* bitmapDevice = 0;
+ CFbsBitGc *bitmapGc = 0;
+ QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(uncompressed));
+ QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL());
+ bitmapGc->Activate(bitmapDevice);
+
+ bitmapGc->DrawBitmap(TPoint(), bitmap);
+
+ delete bitmapGc;
+ 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;
+ sControl = winId->MopGetObject(sControl);
+ if (sControl && sControl->widget()->windowType() == Qt::Desktop) {
+ // Grabbing desktop widget
+ srcSize = screenSize;
+ } else {
+ TPoint relativePos = winId->PositionRelativeToScreen();
+ x += relativePos.iX;
+ 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();
+
+ CFbsBitmap* temporary = createSymbianCFbsBitmap(srcRect.Size(), screenDevice->DisplayMode());
+
+ QPixmap pix;
+
+ if (temporary && screenDevice->CopyScreenToBitmap(temporary, srcRect) == KErrNone) {
+ pix = QPixmap::fromSymbianCFbsBitmap(temporary);
+ }
+
+ delete temporary;
+ return pix;
+}
+
+/*!
+ \fn CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const
+ \since 4.6
+
+ Creates a \c CFbsBitmap that is equivalent to the QPixmap. Internally this
+ function will try to duplicate the handle instead of copying the data,
+ however in scenarios where this is not possible the data will be copied.
+ If the creation fails or the pixmap is null, 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, semi-transparent pixmaps are always copied
+ and not duplicated.
+ \warning This function is only available on Symbian OS.
+
+ \sa fromSymbianCFbsBitmap()
+*/
+CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const
+{
+ QPixmapData *data = pixmapData();
+ if (data->isNull())
+ return 0;
+
+ return reinterpret_cast<CFbsBitmap*>(data->toNativeType(QPixmapData::FbsBitmap));
+}
+
+/*!
+ \fn QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap)
+ \since 4.6
+
+ Creates a QPixmap from a \c CFbsBitmap \a bitmap. Internally this function
+ will try to duplicate the bitmap handle instead of copying the data, however
+ in scenarios where this is not possible the data will be copied.
+ To be sure that QPixmap does not modify your original instance, you should
+ make a copy of your \c CFbsBitmap before calling this function.
+ 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)
+{
+ if (!bitmap)
+ return QPixmap();
+
+ QPixmap pixmap;
+ pixmap.pixmapData()->fromNativeType(reinterpret_cast<void*>(bitmap), QPixmapData::FbsBitmap);
+ return pixmap;
+}
+
+QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type),
+ symbianBitmapDataAccess(new QSymbianBitmapDataAccess),
+ cfbsBitmap(0),
+ bitmapDevice(0),
+ bitmapGc(0),
+ pengine(0),
+ bytes(0)
+{
+
+}
+
+QS60PixmapData::~QS60PixmapData()
+{
+ release();
+ delete symbianBitmapDataAccess;
+}
+
+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));
+ bitmapDevice->Resize(TSize(width, height));
+ bitmapGc->Resized();
+ if(pengine) {
+ delete pengine;
+ pengine = 0;
+ }
+ }
+
+ UPDATE_BUFFER();
+ }
+}
+
+bool QS60PixmapData::initSymbianBitmapContext()
+{
+ QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(cfbsBitmap));
+ QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL());
+ bitmapGc->Activate(bitmapDevice);
+
+ return true;
+}
+
+void QS60PixmapData::release()
+{
+ if (cfbsBitmap) {
+ QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
+ delete bitmapGc;
+ delete bitmapDevice;
+ delete cfbsBitmap;
+ lock.relock();
+ }
+
+ delete pengine;
+ image = QImage();
+ cfbsBitmap = 0;
+ bitmapGc = 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) {
+ sourceImage = 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;
+ switch (destFormat) {
+ case QImage::Format_MonoLSB:
+ mode = EGray2;
+ break;
+ case QImage::Format_RGB32:
+ mode = EColor16MU;
+ break;
+ case QImage::Format_ARGB32_Premultiplied:
+ if (S60->supportsPremultipliedAlpha) {
+ mode = Q_SYMBIAN_ECOLOR16MAP;
+ break;
+ } else {
+ destFormat = QImage::Format_ARGB32;
+ }
+ // Fall through intended
+ case QImage::Format_ARGB32:
+ mode = EColor16MA;
+ break;
+ case QImage::Format_Invalid:
+ return;
+ default:
+ 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());
+ }
+}
+
+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());
+
+ bitmapGc->BitBlt(TPoint(0, 0), s60Data->cfbsBitmap, qt_QRect2TRect(rect));
+}
+
+bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect)
+{
+ beginDataAccess();
+ bool res = QRasterPixmapData::scroll(dx, dy, rect);
+ endDataAccess();
+ return res;
+}
+
+int QS60PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
+{
+ if (!cfbsBitmap)
+ return 0;
+
+ 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;
+
+}
+
+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();
+ }
+}
+
+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);
+ }
+}
+
+void QS60PixmapData::setAlphaChannel(const QPixmap &alphaChannel)
+{
+ QImage img(toImage());
+ img.setAlphaChannel(alphaChannel.toImage());
+ release();
+ fromImage(img, Qt::OrderedDither | Qt::OrderedAlphaDither);
+}
+
+QImage QS60PixmapData::toImage() const
+{
+ QS60PixmapData *that = const_cast<QS60PixmapData*>(this);
+ that->beginDataAccess();
+ QImage copy = that->image.copy();
+ that->endDataAccess();
+
+ return copy;
+}
+
+QPaintEngine* QS60PixmapData::paintEngine() const
+{
+ if (!pengine) {
+ QS60PixmapData *that = const_cast<QS60PixmapData*>(this);
+ that->pengine = new QS60PaintEngine(&that->image, that);
+ }
+ return pengine;
+}
+
+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);
+ //on S60 3.1, premultiplied alpha pixels are stored in a bitmap with 16MA type
+ if (format == QImage::Format_ARGB32)
+ format = QImage::Format_ARGB32_Premultiplied; // pixel data is actually in premultiplied format
+
+ 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);
+ }
+}
+
+void QS60PixmapData::endDataAccess(bool readOnly) const
+{
+ Q_UNUSED(readOnly);
+
+ if(!cfbsBitmap)
+ return;
+
+ symbianBitmapDataAccess->endDataAccess(cfbsBitmap);
+}
+
+/*!
+ \since 4.6
+
+ Returns a QPixmap that wraps given \a sgImage graphics resource.
+ The data should be valid even when original RSgImage handle has been
+ closed.
+
+ \warning This function is only available on Symbian OS.
+
+ \sa toSymbianRSgImage(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
+*/
+
+QPixmap QPixmap::fromSymbianRSgImage(RSgImage *sgImage)
+{
+ // It is expected that RSgImage will
+ // CURRENTLY be used in conjuction with
+ // OpenVG graphics system
+ //
+ // Surely things might change in future
+
+ if (!sgImage)
+ return QPixmap();
+
+ QPixmap pixmap;
+ pixmap.pixmapData()->fromNativeType(reinterpret_cast<void*>(sgImage), QPixmapData::SgImage);
+
+ return pixmap;
+}
+
+/*!
+\since 4.6
+
+Returns a \c RSgImage that is equivalent to the QPixmap by copying the data.
+
+It is the caller's responsibility to close/delete the \c RSgImage after use.
+
+\warning This function is only available on Symbian OS.
+
+\sa fromSymbianRSgImage()
+*/
+
+RSgImage *QPixmap::toSymbianRSgImage() const
+{
+ // It is expected that RSgImage will
+ // CURRENTLY be used in conjuction with
+ // OpenVG graphics system
+ //
+ // Surely things might change in future
+
+ if (isNull())
+ return 0;
+
+ RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmapData()->toNativeType(QPixmapData::SgImage));
+
+ return sgImage;
+}
+
+void* QS60PixmapData::toNativeType(NativeType type)
+{
+ if (type == QPixmapData::SgImage) {
+ return 0;
+ } else if (type == QPixmapData::FbsBitmap) {
+
+ if (isNull() || !cfbsBitmap)
+ return 0;
+
+ bool convertToArgb32 = false;
+ bool needsCopy = false;
+
+ QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion();
+ if (!(S60->supportsPremultipliedAlpha)) {
+ // Convert argb32_premultiplied to argb32 since Symbian 9.2 does
+ // not support premultipied format.
+
+ if (image.format() == QImage::Format_ARGB32_Premultiplied) {
+ needsCopy = true;
+ convertToArgb32 = true;
+ }
+ }
+
+ CFbsBitmap *bitmap = 0;
+
+ TDisplayMode displayMode = 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.
+ image.invertPixels();
+ needsCopy = true;
+ }
+
+ if (needsCopy) {
+ QImage source;
+
+ if (convertToArgb32) {
+ source = image.convertToFormat(QImage::Format_ARGB32);
+ displayMode = EColor16MA;
+ } else {
+ source = image;
+ }
+
+ CFbsBitmap *newBitmap = createSymbianCFbsBitmap(TSize(source.width(), source.height()), displayMode);
+ const uchar *sptr = source.bits();
+ symbianBitmapDataAccess->beginDataAccess(newBitmap);
+
+ uchar *dptr = (uchar*)newBitmap->DataAddress();
+ Mem::Copy(dptr, sptr, source.numBytes());
+
+ symbianBitmapDataAccess->endDataAccess(newBitmap);
+
+ bitmap = newBitmap;
+ } else {
+
+ QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap);
+
+ TInt err = bitmap->Duplicate(cfbsBitmap->Handle());
+ if (err != KErrNone) {
+ qWarning("Could not duplicate CFbsBitmap");
+ delete bitmap;
+ bitmap = 0;
+ }
+ }
+
+ if(displayMode == EGray2) {
+ // restore pixels
+ image.invertPixels();
+ }
+
+ return reinterpret_cast<void*>(bitmap);
+
+ }
+
+ return 0;
+}
+
+void QS60PixmapData::fromNativeType(void* pixmap, NativeType nativeType)
+{
+ if (nativeType == QPixmapData::SgImage) {
+ return;
+ } else if (nativeType == QPixmapData::FbsBitmap && pixmap) {
+
+ CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap*>(pixmap);
+
+ bool deleteSourceBitmap = false;
+ bool needsCopy = false;
+
+#ifdef 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;
+ }
+
+ 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)
+ needsCopy = true;
+
+
+ type = (format != QImage::Format_MonoLSB)
+ ? QPixmapData::PixmapType
+ : QPixmapData::BitmapType;
+
+ if (needsCopy) {
+
+ 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);
+
+ 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.
+ 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;
+ }
+
+ fromSymbianBitmap(duplicate);
+
+ if(deleteSourceBitmap)
+ delete sourceBitmap;
+ }
+ }
+}
+
+QT_END_NAMESPACE