#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:
static int heapRefCount;
QSysInfo::SymbianVersion symbianVersion;
explicit QSymbianBitmapDataAccess()
{
symbianVersion = QSysInfo::symbianVersion();
};
~QSymbianBitmapDataAccess() {};
inline void beginDataAccess(CFbsBitmap *bitmap)
{
if (symbianVersion == QSysInfo::SV_9_2) {
if (heapRefCount == 0)
qt_symbianFbsClient()->lockHeap();
} else {
bitmap->LockHeap(ETrue);
}
heapRefCount++;
}
inline void endDataAccess(CFbsBitmap *bitmap)
{
heapRefCount--;
if (symbianVersion == QSysInfo::SV_9_2) {
if (heapRefCount == 0)
qt_symbianFbsClient()->unlockHeap();
} else {
bitmap->UnlockHeap(ETrue);
}
}
};
int QSymbianBitmapDataAccess::heapRefCount = 0;
#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<QPixmapData> data(QPixmapData::create(0,0, QPixmapData::PixmapType));
data->fromNativeType(reinterpret_cast<void*>(bitmap), QPixmapData::FbsBitmap);
QPixmap pixmap(data.take());
return pixmap;
}
QS60PixmapData::QS6