/****************************************************************************+ −
**+ −
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).+ −
** All rights reserved.+ −
** Contact: Nokia Corporation (qt-info@nokia.com)+ −
**+ −
** This file is part of the QtGui module 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.+ −
*/+ −
_LIT(KFBSERVLargeBitmapAccessName,"FbsLargeBitmapAccess");+ −
class QSymbianFbsClient+ −
{+ −
public:+ −
+ −
QSymbianFbsClient() : heapLocked(false)+ −
{+ −
heapLock.OpenGlobal(KFBSERVLargeBitmapAccessName);+ −
}+ −
+ −
~QSymbianFbsClient()+ −
{+ −
heapLock.Close();+ −
}+ −
+ −
bool lockHeap()+ −
{+ −
bool wasLocked = heapLocked;+ −
+ −
if (heapLock.Handle() && !heapLocked) {+ −
heapLock.Wait();+ −
heapLocked = true;+ −
}+ −
+ −
return wasLocked;+ −
}+ −
+ −
bool unlockHeap()+ −
{+ −
bool wasLocked = heapLocked;+ −
+ −
if (heapLock.Handle() && heapLocked) {+ −
heapLock.Signal();+ −
heapLocked = false;+ −
}+ −
+ −
return wasLocked;+ −
}+ −
+ −
+ −
private:+ −
+ −
RMutex 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)+ −
heapWasLocked = qt_symbianFbsClient()->lockHeap();+ −
else+ −
bitmap->LockHeap(ETrue);+ −
}+ −
+ −
inline void endDataAccess(CFbsBitmap *bitmap)+ −
{+ −
if (symbianVersion == QSysInfo::SV_9_2) {+ −
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->BitBlt(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 || 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();+ −
+ −
QScopedPointer<QS60PixmapData> data(new QS60PixmapData(QPixmapData::PixmapType));+ −
data->fromNativeType(reinterpret_cast<void*>(bitmap), QPixmapData::FbsBitmap);+ −
QPixmap pixmap(data.take());+ −
return pixmap;+ −
}+ −
+ −
QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type),+ −
symbianBitmapDataAccess(new QSymbianBitmapDataAccess),+ −
cfbsBitmap(0),+ −
pengine(0),+ −
bytes(0),+ −
formatLocked(false)+ −
{+ −
+ −
}+ −
+ −
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));+ −
if(pengine) {+ −
delete pengine;+ −
pengine = 0;+ −
}+ −
}+ −
+ −
UPDATE_BUFFER();+ −
}+ −
}+ −
+ −
void QS60PixmapData::release()+ −
{+ −
if (cfbsBitmap) {+ −
QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);+ −
delete cfbsBitmap;+ −
lock.relock();+ −
}+ −
+ −
delete pengine;+ −
image = QImage();+ −
cfbsBitmap = 0;+ −
pengine = 0;+ −
bytes = 0;+ −
}+ −
+ −
/*!+ −
* Takes ownership of bitmap. Used by window surface+ −
*/+ −
void QS60PixmapData::fromSymbianBitmap(CFbsBitmap* bitmap, bool lockFormat)+ −
{+ −
Q_ASSERT(bitmap);+ −
+ −
release();+ −
+ −
cfbsBitmap = bitmap;+ −
formatLocked = lockFormat;+ −
+ −
setSerialNumber(cfbsBitmap->Handle());+ −
+ −
UPDATE_BUFFER();+ −
+ −
// Create default palette if needed+ −
if (cfbsBitmap->DisplayMode() == EGray2) {+ −
image.setColorCount(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()));+ −
}+ −
}+ −
+ −
QImage QS60PixmapData::toImage(const QRect &r) const+ −
{+ −
QS60PixmapData *that = const_cast<QS60PixmapData*>(this);+ −
that->beginDataAccess();+ −
QImage copy = that->image.copy(r);+ −
that->endDataAccess();+ −
+ −
return copy;+ −
}+ −
+ −
void QS60PixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags)+ −
{+ −
release();+ −
+ −
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) {+ −
qWarning("Could not create CFbsBitmap");+ −
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.byteCount());+ −
symbianBitmapDataAccess->endDataAccess(cfbsBitmap);+ −
+ −
UPDATE_BUFFER();+ −
+ −
if (destFormat == QImage::Format_MonoLSB) {+ −
image.setColorCount(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)+ −
{+ −
const QS60PixmapData *s60Data = static_cast<const QS60PixmapData*>(data);+ −
fromImage(s60Data->toImage(rect), Qt::AutoColor | Qt::OrderedAlphaDither);+ −
}+ −
+ −
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+ −
{+ −
return toImage(QRect());+ −
}+ −
+ −
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();+ −
+ −
TSize size = cfbsBitmap->SizeInPixels();+ −
+ −
if (newBytes == bytes && image.width() == size.iWidth && image.height() == size.iHeight)+ −
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.+ −
// S60 window surface needs backing store pixmap for transparent window in ARGB32 format.+ −
// In that case formatLocked is true.+ −
if (!formatLocked && format == QImage::Format_ARGB32)+ −
format = QImage::Format_ARGB32_Premultiplied; // pixel data is actually in premultiplied format+ −
+ −
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();+ −
+ −
QScopedPointer<QS60PixmapData> data(new QS60PixmapData(QPixmapData::PixmapType));+ −
data->fromNativeType(reinterpret_cast<void*>(sgImage), QPixmapData::SgImage);+ −
QPixmap pixmap(data.take());+ −
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.+ −
beginDataAccess();+ −
image.invertPixels();+ −
endDataAccess();+ −
needsCopy = true;+ −
}+ −
+ −
if (needsCopy) {+ −
QImage source;+ −
+ −
if (convertToArgb32) {+ −
beginDataAccess();+ −
source = image.convertToFormat(QImage::Format_ARGB32);+ −
endDataAccess();+ −
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.byteCount());+ −
+ −
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+ −
beginDataAccess();+ −
image.invertPixels();+ −
endDataAccess();+ −
}+ −
+ −
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);+ −
img = img.copy();+ −
da.endDataAccess(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.+ −
img.invertPixels();+ −
} else if(displayMode == EColor16M) {+ −
img = img.rgbSwapped(); // EColor16M is BGR+ −
}+ −
+ −
fromImage(img, Qt::AutoColor);+ −
+ −
if(deleteSourceBitmap)+ −
delete sourceBitmap;+ −
} 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;+ −
}+ −
}+ −
}+ −
+ −
QPixmapData *QS60PixmapData::createCompatiblePixmapData() const+ −
{+ −
return new QS60PixmapData(pixelType());+ −
}+ −
+ −
QT_END_NAMESPACE+ −