src/gui/image/qpixmap_s60.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /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