diff options
author | Jani Hautakangas <ext-jani.hautakangas@nokia.com> | 2009-09-18 11:33:10 (GMT) |
---|---|---|
committer | Jani Hautakangas <ext-jani.hautakangas@nokia.com> | 2009-09-18 11:33:10 (GMT) |
commit | c78dabc55943b76479f7a84bae146f52cbc7bbbf (patch) | |
tree | 5ea4392cf14c1126c82603b9ee614c384f28bd9e /src | |
parent | 6454aca1b273daa2e54a77f83e1f6d4bae83427d (diff) | |
download | Qt-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')
-rw-r--r-- | src/corelib/global/qglobal.h | 1 | ||||
-rw-r--r-- | src/gui/image/image.pri | 1 | ||||
-rw-r--r-- | src/gui/image/qpixmap.cpp | 13 | ||||
-rw-r--r-- | src/gui/image/qpixmap.h | 7 | ||||
-rw-r--r-- | src/gui/image/qpixmap_raster_p.h | 2 | ||||
-rw-r--r-- | src/gui/image/qpixmap_s60.cpp | 891 | ||||
-rw-r--r-- | src/gui/image/qpixmap_s60_p.h | 97 | ||||
-rw-r--r-- | src/gui/image/qpixmapdatafactory.cpp | 9 | ||||
-rw-r--r-- | src/gui/kernel/qt_s60_p.h | 4 | ||||
-rw-r--r-- | src/gui/painting/painting.pri | 6 | ||||
-rw-r--r-- | src/gui/painting/qgraphicssystem.cpp | 9 | ||||
-rw-r--r-- | src/gui/painting/qpaintengine_s60.cpp | 73 | ||||
-rw-r--r-- | src/gui/painting/qpaintengine_s60_p.h | 54 | ||||
-rw-r--r-- | src/gui/painting/qwindowsurface_s60.cpp | 158 | ||||
-rw-r--r-- | src/gui/painting/qwindowsurface_s60_p.h | 8 | ||||
-rw-r--r-- | src/gui/styles/qs60style_s60.cpp | 12 | ||||
-rw-r--r-- | src/gui/text/qfont_s60.cpp | 9 | ||||
-rw-r--r-- | src/gui/text/qfontdatabase_s60.cpp | 10 | ||||
-rw-r--r-- | src/gui/text/qfontengine_s60.cpp | 15 |
19 files changed, 1123 insertions, 256 deletions
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 6a781e8..79a253a 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -2389,6 +2389,7 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf(); #ifdef SYMBIAN_GRAPHICS_USE_GCE //RWsPointerCursor is fixed, so don't use low performance sprites #define Q_SYMBIAN_FIXED_POINTER_CURSORS +#define Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE #endif //Symbian does not support data imports from a DLL diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index 0970385..f365f66 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -70,6 +70,7 @@ mac { SOURCES += image/qpixmap_mac.cpp } symbian { + HEADERS += image/qpixmap_s60_p.h SOURCES += image/qpixmap_s60.cpp } diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index eb38b85..4f145af 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -1557,8 +1557,8 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) premultiplied alpha format. If the image has an alpha channel, and if the system allows, the preferred format is premultiplied alpha. Note also that QPixmap, unlike QImage, may be hardware dependent. - On X11 and Mac, a QPixmap is stored on the server side while a - QImage is stored on the client side (on Windows, these two classes + On X11, Mac and Symbian, a QPixmap is stored on the server side while + a QImage is stored on the client side (on Windows, these two classes have an equivalent internal representation, i.e. both QImage and QPixmap are stored on the client side and don't use any GDI resources). @@ -1577,7 +1577,8 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) screen. Alternatively, if no manipulation is desired, the image file can be loaded directly into a QPixmap. On Windows, the QPixmap class also supports conversion between \c HBITMAP and - QPixmap. + QPixmap. On Symbian, the QPixmap class also supports conversion + between CFbsBitmap and QPixmap. QPixmap provides a collection of functions that can be used to obtain a variety of information about the pixmap. In addition, @@ -1682,6 +1683,12 @@ QPixmap QPixmap::transformed(const QMatrix &matrix, Qt::TransformationMode mode) returns the HBITMAP handle. The fromWinHBITMAP() function returns a QPixmap that is equivalent to the given bitmap which has the specified format. + + In addition, on Symbian, the QPixmap class supports conversion to + and from CFbsBitmap: the toSymbianCFbsBitmap() function creates + CFbsBitmap equivalent to the QPixmap, based on given mode and returns + a CFbsBitmap object. The fromSymbianCFbsBitmap() function returns a + QPixmap that is equivalent to the given bitmap and given mode. \section1 Pixmap Transformations diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index 1eaafdc..4a8a876 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -157,8 +157,10 @@ public: #endif #if defined(Q_OS_SYMBIAN) - CFbsBitmap *toSymbianCFbsBitmap() const; - static QPixmap fromSymbianCFbsBitmap(CFbsBitmap *bitmap); + enum ConversionMode { CopyData, DuplicateHandle }; + + CFbsBitmap *toSymbianCFbsBitmap(ConversionMode mode = DuplicateHandle) const; + static QPixmap fromSymbianCFbsBitmap(CFbsBitmap *bitmap, ConversionMode mode = DuplicateHandle); #endif inline QPixmap copy(int x, int y, int width, int height) const; @@ -254,6 +256,7 @@ private: friend class QPixmapData; friend class QX11PixmapData; friend class QMacPixmapData; + friend class QS60PixmapData; friend class QBitmap; friend class QPaintDevice; friend class QPainter; diff --git a/src/gui/image/qpixmap_raster_p.h b/src/gui/image/qpixmap_raster_p.h index 5add5ed..2af2399 100644 --- a/src/gui/image/qpixmap_raster_p.h +++ b/src/gui/image/qpixmap_raster_p.h @@ -83,13 +83,13 @@ public: protected: int metric(QPaintDevice::PaintDeviceMetric metric) const; + QImage image; private: friend class QPixmap; friend class QBitmap; friend class QDetachedPixmap; friend class QRasterPaintEngine; - QImage image; }; QT_END_NAMESPACE 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 diff --git a/src/gui/image/qpixmap_s60_p.h b/src/gui/image/qpixmap_s60_p.h new file mode 100644 index 0000000..b56b270 --- /dev/null +++ b/src/gui/image/qpixmap_s60_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QPIXMAPDATA_S60_P_H +#define QPIXMAPDATA_S60_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGui/private/qpixmap_raster_p.h> + +QT_BEGIN_NAMESPACE + +class CFbsBitmap; +class CFbsBitmapDevice; +class CBitmapContext; + +class QSymbianBitmapDataAccess; + +class QSymbianFbsHeapLock +{ +public: + + enum LockAction { + Unlock + }; + + explicit QSymbianFbsHeapLock(LockAction a); + ~QSymbianFbsHeapLock(); + void relock(); + +private: + + LockAction action; + bool wasLocked; +}; + +class QS60PixmapData : public QRasterPixmapData +{ +public: + QS60PixmapData(PixelType type); + ~QS60PixmapData(); + + void resize(int width, int height); + void fromImage(const QImage &image, Qt::ImageConversionFlags flags); + void copy(const QPixmapData *data, const QRect &rect); + bool scroll(int dx, int dy, const QRect &rect); + + int metric(QPaintDevice::PaintDeviceMetric metric) const; + void fill(const QColor &color); + void setMask(const QBitmap &mask); + void setAlphaChannel(const QPixmap &alphaChannel); + QImage toImage() const; + QPaintEngine* paintEngine() const; + + void beginDataAccess(); + void endDataAccess(bool readOnly=false) const; + +private: + void release(); + void fromSymbianBitmap(CFbsBitmap* bitmap); + bool initSymbianBitmapContext(); + + QSymbianBitmapDataAccess *symbianBitmapDataAccess; + + CFbsBitmap *cfbsBitmap; + CFbsBitmapDevice *bitmapDevice; + CBitmapContext *bitmapContext; + QPaintEngine *pengine; + uchar* bytes; + + friend class QPixmap; + friend class QS60WindowSurface; + friend class QS60PaintEngine; + friend class QS60Data; +}; + +QT_END_NAMESPACE + +#endif // QPIXMAPDATA_S60_P_H + diff --git a/src/gui/image/qpixmapdatafactory.cpp b/src/gui/image/qpixmapdatafactory.cpp index e3d2e6c..806883d 100644 --- a/src/gui/image/qpixmapdatafactory.cpp +++ b/src/gui/image/qpixmapdatafactory.cpp @@ -47,12 +47,15 @@ #ifdef Q_WS_X11 # include <private/qpixmap_x11_p.h> #endif -#if defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) +#if defined(Q_WS_WIN) # include <private/qpixmap_raster_p.h> #endif #ifdef Q_WS_MAC # include <private/qpixmap_mac_p.h> #endif +#ifdef Q_WS_S60 +# include <private/qpixmap_s60_p.h> +#endif #include "private/qapplication_p.h" #include "private/qgraphicssystem_p.h" @@ -75,10 +78,12 @@ QPixmapData* QSimplePixmapDataFactory::create(QPixmapData::PixelType type) #if defined(Q_WS_X11) return new QX11PixmapData(type); -#elif defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) +#elif defined(Q_WS_WIN) return new QRasterPixmapData(type); #elif defined(Q_WS_MAC) return new QMacPixmapData(type); +#elif defined(Q_WS_S60) + return new QS60PixmapData(type); #else #error QSimplePixmapDataFactory::create() not implemented #endif diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index 67084c4..b43c950 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -108,7 +108,7 @@ public: bool virtualMouseRequired; int qtOwnsS60Environment : 1; static inline void updateScreenSize(); - static inline RWsSession& wsSession(); + static inline RWsSession& wsSession(); static inline RWindowGroup& windowGroup(); static inline CWsScreenDevice* screenDevice(); static inline CCoeAppUi* appUi(); @@ -284,7 +284,7 @@ static inline QImage::Format qt_TDisplayMode2Format(TDisplayMode mode) format = QImage::Format_RGB16; break; case EColor16M: - format = QImage::Format_RGB666; + format = QImage::Format_RGB888; break; case EColor16MU: format = QImage::Format_RGB32; diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 8343cb9..c35c33a 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -14,7 +14,7 @@ HEADERS += \ painting/qoutlinemapper_p.h \ painting/qpaintdevice.h \ painting/qpaintengine.h \ - painting/qpaintengine_p.h \ + painting/qpaintengine_p.h \ painting/qpaintengine_alpha_p.h \ painting/qpaintengine_preview_p.h \ painting/qpaintengineex_p.h \ @@ -179,8 +179,12 @@ embedded { symbian { SOURCES += \ + painting/qpaintengine_s60.cpp \ painting/qregion_s60.cpp \ painting/qcolormap_s60.cpp + + HEADERS += \ + painting/qpaintengine_s60_p.h } x11|embedded { diff --git a/src/gui/painting/qgraphicssystem.cpp b/src/gui/painting/qgraphicssystem.cpp index 20d6f22..2d9603d 100644 --- a/src/gui/painting/qgraphicssystem.cpp +++ b/src/gui/painting/qgraphicssystem.cpp @@ -44,12 +44,15 @@ #ifdef Q_WS_X11 # include <private/qpixmap_x11_p.h> #endif -#if defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) +#if defined(Q_WS_WIN) # include <private/qpixmap_raster_p.h> #endif #ifdef Q_WS_MAC # include <private/qpixmap_mac_p.h> #endif +#ifdef Q_WS_S60 +# include <private/qpixmap_s60_p.h> +#endif QT_BEGIN_NAMESPACE @@ -64,10 +67,12 @@ QPixmapData *QGraphicsSystem::createDefaultPixmapData(QPixmapData::PixelType typ #endif #if defined(Q_WS_X11) return new QX11PixmapData(type); -#elif defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) +#elif defined(Q_WS_WIN) return new QRasterPixmapData(type); #elif defined(Q_WS_MAC) return new QMacPixmapData(type); +#elif defined(Q_WS_S60) + return new QS60PixmapData(type); #elif !defined(Q_WS_QWS) #error QGraphicsSystem::createDefaultPixmapData() not implemented #endif diff --git a/src/gui/painting/qpaintengine_s60.cpp b/src/gui/painting/qpaintengine_s60.cpp new file mode 100644 index 0000000..2aa179a --- /dev/null +++ b/src/gui/painting/qpaintengine_s60.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include <private/qpaintengine_s60_p.h> +#include <private/qpixmap_s60_p.h> +#include <private/qt_s60_p.h> + +QT_BEGIN_NAMESPACE + +class QS60PaintEnginePrivate : public QRasterPaintEnginePrivate +{ +public: + QS60PaintEnginePrivate(QS60PaintEngine *engine) { } +}; + +QS60PaintEngine::QS60PaintEngine(QPaintDevice *device, QS60PixmapData *data) + : QRasterPaintEngine(*(new QS60PaintEnginePrivate(this)), device), pixmapData(data) +{ +} + +bool QS60PaintEngine::begin(QPaintDevice *device) +{ + pixmapData->beginDataAccess(); + return QRasterPaintEngine::begin(device); +} + +bool QS60PaintEngine::end() +{ + bool ret = QRasterPaintEngine::end(); + pixmapData->endDataAccess(); + return ret; +} + +void QS60PaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm) +{ + QS60PixmapData *srcData = static_cast<QS60PixmapData *>(pm.pixmapData()); + srcData->beginDataAccess(); + QRasterPaintEngine::drawPixmap(p, pm); + srcData->endDataAccess(); +} + +void QS60PaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) +{ + QS60PixmapData *srcData = static_cast<QS60PixmapData *>(pm.pixmapData()); + srcData->beginDataAccess(); + QRasterPaintEngine::drawPixmap(r, pm, sr); + srcData->endDataAccess(); +} + +void QS60PaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr) +{ + QS60PixmapData *srcData = static_cast<QS60PixmapData *>(pm.pixmapData()); + srcData->beginDataAccess(); + QRasterPaintEngine::drawTiledPixmap(r, pm, sr); + srcData->endDataAccess(); +} + +void QS60PaintEngine::prepare(QImage *image) +{ + QRasterBuffer *buffer = d_func()->rasterBuffer.data(); + if (buffer) + buffer->prepare(image); +} + +QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintengine_s60_p.h b/src/gui/painting/qpaintengine_s60_p.h new file mode 100644 index 0000000..b38ef93 --- /dev/null +++ b/src/gui/painting/qpaintengine_s60_p.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTENGINE_S60_P_H +#define QPAINTENGINE_S60_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qpaintengine_raster_p.h" + +QT_BEGIN_NAMESPACE + +class QS60PaintEnginePrivate; +class QS60PixmapData; + +class QS60PaintEngine : public QRasterPaintEngine +{ + Q_DECLARE_PRIVATE(QS60PaintEngine) + +public: + QS60PaintEngine(QPaintDevice *device, QS60PixmapData* data); + bool begin(QPaintDevice *device); + bool end(); + + void drawPixmap(const QPointF &p, const QPixmap &pm); + void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); + void drawTiledPixmap(const QRectF &r, const QPixmap &pm, const QPointF &sr); + + void prepare(QImage* image); + +private: + QS60PixmapData *pixmapData; +}; + +QT_END_NAMESPACE + +#endif // QPAINTENGINE_S60_P_H diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp index f56902a..664ad48 100644 --- a/src/gui/painting/qwindowsurface_s60.cpp +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -44,6 +44,7 @@ #include <QtGui/qpaintdevice.h> #include <private/qwidget_p.h> #include "qwindowsurface_s60_p.h" +#include "qpixmap_s60_p.h" #include "qt_s60_p.h" #include "private/qdrawhelper_p.h" @@ -51,20 +52,13 @@ QT_BEGIN_NAMESPACE struct QS60WindowSurfacePrivate { - QImage device; - CFbsBitmap *bitmap; - uchar* bytes; - - // Since only one CFbsBitmap is allowed to be locked at a time, this is static. - static QS60WindowSurface* lockedSurface; + QPixmap device; + QList<QImage*> bufferImages; }; -QS60WindowSurface* QS60WindowSurfacePrivate::lockedSurface = NULL; QS60WindowSurface::QS60WindowSurface(QWidget* widget) : QWindowSurface(widget), d_ptr(new QS60WindowSurfacePrivate) { - d_ptr->bytes = 0; - d_ptr->bitmap = 0; TDisplayMode mode = S60->screenDevice()->DisplayMode(); bool isOpaque = qt_widget_private(widget)->isOpaque; @@ -73,39 +67,27 @@ QS60WindowSurface::QS60WindowSurface(QWidget* widget) else if (mode == EColor16MU && !isOpaque) mode = EColor16MA; // Try for transparency anyway - // We create empty CFbsBitmap here -> it will be resized in setGeometry - d_ptr->bitmap = q_check_ptr(new CFbsBitmap); // CBase derived object needs check on new - qt_symbian_throwIfError( d_ptr->bitmap->Create(TSize(0, 0), mode ) ); - - updatePaintDeviceOnBitmap(); - + CFbsBitmap *bitmap = q_check_ptr(new CFbsBitmap); // CBase derived object needs check on new + qt_symbian_throwIfError( bitmap->Create( TSize(0, 0), mode ) ); + + QS60PixmapData *data = new QS60PixmapData(QPixmapData::PixmapType); + data->fromSymbianBitmap(bitmap); + d_ptr->device = QPixmap(data); + setStaticContentsSupport(true); } - QS60WindowSurface::~QS60WindowSurface() { - if (QS60WindowSurfacePrivate::lockedSurface == this) - unlockBitmapHeap(); - - delete d_ptr->bitmap; delete d_ptr; } void QS60WindowSurface::beginPaint(const QRegion &rgn) { - if(!d_ptr->bitmap) - return; - - if (QS60WindowSurfacePrivate::lockedSurface) - unlockBitmapHeap(); - - QS60WindowSurfacePrivate::lockedSurface = this; - lockBitmapHeap(); - if (!qt_widget_private(window())->isOpaque) { - QRgb *data = reinterpret_cast<QRgb *>(d_ptr->device.bits()); - const int row_stride = d_ptr->device.bytesPerLine() / 4; + QImage image = static_cast<QS60PixmapData *>(d_ptr->device.data_ptr().data())->image; + QRgb *data = reinterpret_cast<QRgb *>(image.bits()); + const int row_stride = image.bytesPerLine() / 4; const QVector<QRect> rects = rgn.rects(); for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) { @@ -124,6 +106,38 @@ void QS60WindowSurface::beginPaint(const QRegion &rgn) } } +void QS60WindowSurface::endPaint(const QRegion &) +{ + qDeleteAll(d_ptr->bufferImages); + d_ptr->bufferImages.clear(); +} + +QImage* QS60WindowSurface::buffer(const QWidget *widget) +{ + if (widget->window() != window()) + return 0; + + QPaintDevice *pdev = paintDevice(); + if (!pdev) + return 0; + + const QPoint off = offset(widget); + QImage *img = &(static_cast<QS60PixmapData *>(d_ptr->device.data_ptr().data())->image); + + QRect rect(off, widget->size()); + rect &= QRect(QPoint(), img->size()); + + if (rect.isEmpty()) + return 0; + + img = new QImage(img->scanLine(rect.y()) + rect.x() * img->depth() / 8, + rect.width(), rect.height(), + img->bytesPerLine(), img->format()); + d_ptr->bufferImages.append(img); + + return img; +} + void QS60WindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &) { const QVector<QRect> subRects = region.rects(); @@ -143,28 +157,10 @@ bool QS60WindowSurface::scroll(const QRegion &area, int dx, int dy) if (d_ptr->device.isNull()) return false; - CFbsBitmapDevice *bitmapDevice = 0; - QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(d_ptr->bitmap)); - CBitmapContext *bitmapContext; - TInt err = bitmapDevice->CreateBitmapContext(bitmapContext); - if (err != KErrNone) { - CBase::Delete(bitmapDevice); - return false; - } - bitmapContext->CopyRect(TPoint(dx, dy), qt_QRect2TRect(rect)); - CBase::Delete(bitmapContext); - CBase::Delete(bitmapDevice); - return true; -} - -void QS60WindowSurface::endPaint(const QRegion & /* rgn */) -{ - if(!d_ptr->bitmap) - return; + QS60PixmapData *data = static_cast<QS60PixmapData*>(d_ptr->device.data_ptr().data()); + data->scroll(dx, dy, rect); - Q_ASSERT(QS60WindowSurfacePrivate::lockedSurface); - unlockBitmapHeap(); - QS60WindowSurfacePrivate::lockedSurface = NULL; + return true; } QPaintDevice* QS60WindowSurface::paintDevice() @@ -177,61 +173,17 @@ void QS60WindowSurface::setGeometry(const QRect& rect) if (rect == geometry()) return; - QWindowSurface::setGeometry(rect); - - TRect nativeRect(qt_QRect2TRect(rect)); - qt_symbian_throwIfError(d_ptr->bitmap->Resize(nativeRect.Size())); - - if (!rect.isNull()) - updatePaintDeviceOnBitmap(); -} - -void QS60WindowSurface::lockBitmapHeap() -{ - if (!QS60WindowSurfacePrivate::lockedSurface) - return; - - // Get some local variables to make later code lines more clear to read - CFbsBitmap*& bitmap = QS60WindowSurfacePrivate::lockedSurface->d_ptr->bitmap; - QImage& device = QS60WindowSurfacePrivate::lockedSurface->d_ptr->device; - uchar*& bytes = QS60WindowSurfacePrivate::lockedSurface->d_ptr->bytes; - - bitmap->LockHeap(); - uchar *newBytes = (uchar*)bitmap->DataAddress(); - if (newBytes != bytes) { - bytes = newBytes; - - // Get some values for QImage creation - TDisplayMode mode = bitmap->DisplayMode(); - if (mode == EColor16MA - && qt_widget_private(QS60WindowSurfacePrivate::lockedSurface->window())->isOpaque) - mode = EColor16MU; - QImage::Format format = qt_TDisplayMode2Format( mode ); - TSize bitmapSize = bitmap->SizeInPixels(); - int bytesPerLine = CFbsBitmap::ScanLineLength( bitmapSize.iWidth, mode); - - device = QImage( bytes, bitmapSize.iWidth, bitmapSize.iHeight, bytesPerLine, format ); - } -} - -void QS60WindowSurface::unlockBitmapHeap() -{ - if (!QS60WindowSurfacePrivate::lockedSurface) - return; - - QS60WindowSurfacePrivate::lockedSurface->d_ptr->bitmap->UnlockHeap(); -} + QS60PixmapData *data = static_cast<QS60PixmapData*>(d_ptr->device.data_ptr().data()); + data->resize(rect.width(), rect.height()); -void QS60WindowSurface::updatePaintDeviceOnBitmap() -{ - // This forces the actual device to be updated based on CFbsBitmap - beginPaint(QRegion()); - endPaint(QRegion()); + QWindowSurface::setGeometry(rect); } -CFbsBitmap *QS60WindowSurface::symbianBitmap() const +CFbsBitmap* QS60WindowSurface::symbianBitmap() const { - return d_ptr->bitmap; + QS60PixmapData *data = static_cast<QS60PixmapData*>(d_ptr->device.data_ptr().data()); + return data->cfbsBitmap; } QT_END_NAMESPACE + diff --git a/src/gui/painting/qwindowsurface_s60_p.h b/src/gui/painting/qwindowsurface_s60_p.h index f9b6b60..3c4059f 100644 --- a/src/gui/painting/qwindowsurface_s60_p.h +++ b/src/gui/painting/qwindowsurface_s60_p.h @@ -75,17 +75,13 @@ public: void beginPaint(const QRegion &); void endPaint(const QRegion &); - void setGeometry(const QRect &rect); + QImage* buffer(const QWidget *widget); - static void lockBitmapHeap(); - static void unlockBitmapHeap(); + void setGeometry(const QRect &rect); CFbsBitmap *symbianBitmap() const; private: - void updatePaintDeviceOnBitmap(); - -private: QS60WindowSurfacePrivate* d_ptr; }; diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp index 4fdf48b..131d8bc 100644 --- a/src/gui/styles/qs60style_s60.cpp +++ b/src/gui/styles/qs60style_s60.cpp @@ -44,8 +44,8 @@ #include "qpainter.h" #include "qstyleoption.h" #include "qstyle.h" -#include "private/qwindowsurface_s60_p.h" #include "private/qt_s60_p.h" +#include "private/qpixmap_s60_p.h" #include "private/qcore_symbian_p.h" #include "qapplication.h" @@ -1136,11 +1136,13 @@ QPixmap QS60StyleModeSpecifics::generateMissingThemeGraphic(QS60StyleEnums::Skin QPixmap QS60StylePrivate::part(QS60StyleEnums::SkinParts part, const QSize &size, SkinElementFlags flags) { - QS60WindowSurface::unlockBitmapHeap(); + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + QPixmap result = (flags & SF_ColorSkinned)? QS60StyleModeSpecifics::colorSkinnedGraphics(part, size, flags) : QS60StyleModeSpecifics::skinnedGraphics(part, size, flags); - QS60WindowSurface::lockBitmapHeap(); + + lock.relock(); if (flags & SF_StateDisabled && !QS60StyleModeSpecifics::disabledPartGraphic(part)) { QStyleOption opt; @@ -1158,9 +1160,9 @@ QPixmap QS60StylePrivate::part(QS60StyleEnums::SkinParts part, QPixmap QS60StylePrivate::frame(SkinFrameElements frame, const QSize &size, SkinElementFlags flags) { - QS60WindowSurface::unlockBitmapHeap(); + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); QPixmap result = QS60StyleModeSpecifics::skinnedGraphics(frame, size, flags); - QS60WindowSurface::lockBitmapHeap(); + lock.relock(); if (flags & SF_StateDisabled && !QS60StyleModeSpecifics::disabledFrameGraphic(frame)) { QStyleOption opt; diff --git a/src/gui/text/qfont_s60.cpp b/src/gui/text/qfont_s60.cpp index 30e00ff..277d88f 100644 --- a/src/gui/text/qfont_s60.cpp +++ b/src/gui/text/qfont_s60.cpp @@ -41,7 +41,7 @@ #include "qfont.h" #include "qt_s60_p.h" -#include <private/qwindowsurface_s60_p.h> +#include "qpixmap_s60_p.h" #include "qmutex.h" QT_BEGIN_NAMESPACE @@ -57,14 +57,17 @@ QString QFont::lastResortFamily() const QMutexLocker locker(lastResortFamilyMutex()); static QString family; if (family.isEmpty()) { - QS60WindowSurface::unlockBitmapHeap(); + + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + CFont *font; const TInt err = S60->screenDevice()->GetNearestFontInTwips(font, TFontSpec()); Q_ASSERT(err == KErrNone); const TFontSpec spec = font->FontSpecInTwips(); family = QString((const QChar *)spec.iTypeface.iName.Ptr(), spec.iTypeface.iName.Length()); S60->screenDevice()->ReleaseFont(font); - QS60WindowSurface::lockBitmapHeap(); + + lock.relock(); } return family; #else diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp index e1a2c47..1a6bb11 100644 --- a/src/gui/text/qfontdatabase_s60.cpp +++ b/src/gui/text/qfontdatabase_s60.cpp @@ -45,9 +45,9 @@ #include "qfontengine_s60_p.h" #include "qabstractfileengine.h" #include "qdesktopservices.h" +#include "qpixmap_s60_p.h" #include "qt_s60_p.h" #include "qendian.h" -#include <private/qwindowsurface_s60_p.h> #include <private/qcore_symbian_p.h> #if defined(QT_NO_FREETYPE) #include <OPENFONT.H> @@ -217,7 +217,8 @@ static void initializeDb() if (!db->s60Store) db->s60Store = new QFontDatabaseS60StoreImplementation; - QS60WindowSurface::unlockBitmapHeap(); + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + const int numTypeFaces = QS60Data::screenDevice()->NumTypefaces(); const QFontDatabaseS60StoreImplementation *store = dynamic_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store); Q_ASSERT(store); @@ -271,8 +272,11 @@ static void initializeDb() } QS60Data::screenDevice()->ReleaseFont(font); } + Q_ASSERT(fontAdded); - QS60WindowSurface::lockBitmapHeap(); + + lock.relock(); + #else // defined(QT_NO_FREETYPE) QDir dir(QDesktopServices::storageLocation(QDesktopServices::FontsLocation)); dir.setNameFilters(QStringList() << QLatin1String("*.ttf") diff --git a/src/gui/text/qfontengine_s60.cpp b/src/gui/text/qfontengine_s60.cpp index ab2506c..88ae8f6 100644 --- a/src/gui/text/qfontengine_s60.cpp +++ b/src/gui/text/qfontengine_s60.cpp @@ -43,9 +43,9 @@ #include "qtextengine_p.h" #include "qglobal.h" #include <private/qapplication_p.h> -#include <private/qwindowsurface_s60_p.h> #include "qimage.h" #include "qt_s60_p.h" +#include "qpixmap_s60_p.h" #include <e32base.h> #include <e32std.h> @@ -136,7 +136,9 @@ QFontEngineS60::QFontEngineS60(const QFontDef &request, const QFontEngineS60Exte QFontEngine::fontDef = request; m_fontSizeInPixels = (request.pixelSize >= 0)? request.pixelSize:pointsToPixels(request.pointSize); - QS60WindowSurface::unlockBitmapHeap(); + + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + m_textRenderBitmap = q_check_ptr(new CFbsBitmap()); // CBase derived object needs check on new const TSize bitmapSize(1, 1); // It is just a dummy bitmap that I need to keep the font alive (or maybe not) qt_symbian_throwIfError(m_textRenderBitmap->Create(bitmapSize, EGray256)); @@ -151,12 +153,14 @@ QFontEngineS60::QFontEngineS60(const QFontDef &request, const QFontEngineS60Exte const TInt errorCode = m_textRenderBitmapDevice->GetNearestFontInPixels(m_font, fontSpec); Q_ASSERT(errorCode == 0); m_textRenderBitmapGc->UseFont(m_font); - QS60WindowSurface::lockBitmapHeap(); + + lock.relock(); } QFontEngineS60::~QFontEngineS60() { - QS60WindowSurface::unlockBitmapHeap(); + QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock); + m_textRenderBitmapGc->DiscardFont(); delete m_textRenderBitmapGc; m_textRenderBitmapGc = NULL; @@ -165,7 +169,8 @@ QFontEngineS60::~QFontEngineS60() m_textRenderBitmapDevice = NULL; delete m_textRenderBitmap; m_textRenderBitmap = NULL; - QS60WindowSurface::lockBitmapHeap(); + + lock.relock(); } bool QFontEngineS60::stringToCMap(const QChar *characters, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const |