diff options
-rw-r--r-- | src/gui/image/qpixmap.h | 9 | ||||
-rw-r--r-- | src/gui/image/qpixmap_s60.cpp | 140 | ||||
-rw-r--r-- | tests/auto/qpixmap/qpixmap.pro | 19 | ||||
-rw-r--r-- | tests/auto/qpixmap/tst_qpixmap.cpp | 101 |
4 files changed, 251 insertions, 18 deletions
diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index 1863273..9ef5347 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -62,6 +62,10 @@ class QX11Info; class QPixmapData; +#if defined(Q_OS_SYMBIAN) +class CFbsBitmap; +#endif + class Q_GUI_EXPORT QPixmap : public QPaintDevice { public: @@ -152,6 +156,11 @@ public: static QPixmap fromMacCGImageRef(CGImageRef image); #endif +#if defined(Q_OS_SYMBIAN) + CFbsBitmap *toSymbianCFbsBitmap() const; + static QPixmap fromSymbianCFbsBitmap(CFbsBitmap *bitmap); +#endif + inline QPixmap copy(int x, int y, int width, int height) const; QPixmap copy(const QRect &rect = QRect()) const; diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp index 52e2fe7..879c980 100644 --- a/src/gui/image/qpixmap_s60.cpp +++ b/src/gui/image/qpixmap_s60.cpp @@ -91,14 +91,142 @@ QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h ) return QPixmap(); } - QImage::Format format = qt_TDisplayMode2Format( displayMode ); - int bytesPerLine = CFbsBitmap::ScanLineLength(temporary->SizeInPixels().iWidth,displayMode); - temporary->LockHeap(); - QImage image = QImage((uchar*)temporary->DataAddress(), srcRect.Width(), srcRect.Height(), bytesPerLine, format); - QPixmap pixmap = QPixmap::fromImage(image.copy()); - temporary->UnlockHeap(); + QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(temporary); CBase::Delete(temporary); return pixmap; +} + +/*! +\since 4.6 + +Returns a \c CFbsBitmap that is equivalent to the QPixmap by copying the data. + +It is the caller's responsibility to delete the \c CFbsBitmap after use. + +\warning This function is only available on Symbian OS. + +\sa fromSymbianCFbsBitmap() +*/ + +CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const +{ + if (isNull()) + return 0; + + 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 + 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; +#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; + default: + qWarning("Image format not supported: %d", img.format()); + return 0; + } + + CFbsBitmap* bitmap = new (ELeave) CFbsBitmap(); + TSize size(width(), height()); + if (bitmap->Create(size, mode) != KErrNone) { + CBase::Delete(bitmap); + return 0; + } + + const QImage converted = img.convertToFormat(destFormat); + bitmap->LockHeap(); + const uchar *sptr = converted.bits(); + uchar *dptr = (uchar*)bitmap->DataAddress(); + Mem::Copy(dptr, sptr, converted.numBytes()); + bitmap->UnlockHeap(); + return bitmap; } + +/*! +\since 4.6 + +Returns a QPixmap that is equivalent to the \c CFbsBitmap by copying the data. +If the CFbsBitmap is not valid or is compressed in memory, 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) +{ + int width = bitmap->SizeInPixels().iWidth; + int height = bitmap->SizeInPixels().iHeight; + + if (!bitmap || width <= 0 || height <= 0 || bitmap->IsCompressedInRAM()) + return QPixmap(); + + 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()); + } 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; +} + QT_END_NAMESPACE diff --git a/tests/auto/qpixmap/qpixmap.pro b/tests/auto/qpixmap/qpixmap.pro index aa767aa..c992f6e 100644 --- a/tests/auto/qpixmap/qpixmap.pro +++ b/tests/auto/qpixmap/qpixmap.pro @@ -1,26 +1,21 @@ load(qttest_p4) SOURCES += tst_qpixmap.cpp contains(QT_CONFIG, qt3support): QT += qt3support -wince*: { +wince*|symbian*: { task31722_0.sources = convertFromImage/task31722_0/* task31722_0.path = convertFromImage/task31722_0 task31722_1.sources = convertFromImage/task31722_1/* task31722_1.path = convertFromImage/task31722_1 DEPLOYMENT += task31722_0 task31722_1 - DEFINES += SRCDIR=\\\".\\\" } -symbian*:{ - task31722_0.sources = convertFromImage/task31722_0/* - task31722_0.path = convertFromImage/task31722_0 - task31722_1.sources = convertFromImage/task31722_1/* - task31722_1.path = convertFromImage/task31722_1 - DEPLOYMENT += task31722_0 task31722_1 + +wince*: { + DEFINES += SRCDIR=\\\".\\\" +} symbian*: { DEPLOYMENT_PLUGIN += qmng -} -else { + LIBS += -lfbscli.lib -lbitgdi.lib -lgdi.lib +} else { DEFINES += SRCDIR=\\\"$$PWD\\\" win32:LIBS += -lgdi32 -luser32 } - - diff --git a/tests/auto/qpixmap/tst_qpixmap.cpp b/tests/auto/qpixmap/tst_qpixmap.cpp index 493333b..9f73e34 100644 --- a/tests/auto/qpixmap/tst_qpixmap.cpp +++ b/tests/auto/qpixmap/tst_qpixmap.cpp @@ -58,6 +58,14 @@ #include <qscreen_qws.h> #endif +#ifdef Q_OS_SYMBIAN +#include <e32std.h> +#include <fbs.h> +#include <gdi.h> +#include <bitdev.h> +#endif + + //TESTED_CLASS= //TESTED_FILES= #if defined(Q_OS_SYMBIAN) @@ -120,6 +128,11 @@ private slots: void fromWinHBITMAP(); #endif +#if defined(Q_WS_S60) + void fromSymbianCFbsBitmap_data(); + void fromSymbianCFbsBitmap(); +#endif + void onlyNullPixmapsOutsideGuiThread(); void refUnref(); @@ -798,6 +811,94 @@ void tst_QPixmap::fromWinHBITMAP() #endif +#if defined(Q_WS_S60) +Q_DECLARE_METATYPE(TDisplayMode) + +void tst_QPixmap::fromSymbianCFbsBitmap_data() +{ + QTest::addColumn<TDisplayMode>("format"); + QTest::addColumn<int>("width"); + QTest::addColumn<int>("height"); + QTest::addColumn<QColor>("color"); + + const int smallWidth = 20; + const int smallHeight = 20; + const int largeWidth = 240; + const int largeHeight = 320; + + // Indexed Color Formats - Disabled since images seem to be blank -> no palette? +// QTest::newRow("EGray2 small") << EGray2 << smallWidth << smallHeight << QColor(Qt::black); +// QTest::newRow("EGray2 big") << EGray2 << largeWidth << largeHeight << QColor(Qt::black); +// QTest::newRow("EGray256 small") << EGray256 << smallWidth << smallHeight << QColor(Qt::blue); +// QTest::newRow("EGray256 big") << EGray256 << largeWidth << largeHeight << QColor(Qt::blue); +// QTest::newRow("EColor256 small") << EColor256 << smallWidth << smallHeight << QColor(Qt::red); +// QTest::newRow("EColor256 big") << EColor256 << largeWidth << largeHeight << QColor(Qt::red); + + // Direct Color Formats + QTest::newRow("EColor4K small") << EColor4K << smallWidth << smallHeight << QColor(Qt::red); + QTest::newRow("EColor4K big") << EColor4K << largeWidth << largeHeight << QColor(Qt::red); + QTest::newRow("EColor64K small") << EColor64K << smallWidth << smallHeight << QColor(Qt::green); + QTest::newRow("EColor64K big") << EColor64K << largeWidth << largeHeight << QColor(Qt::green); + QTest::newRow("EColor16MU small") << EColor16MU << smallWidth << smallHeight << QColor(Qt::red); + QTest::newRow("EColor16MU big") << EColor16MU << largeWidth << largeHeight << QColor(Qt::red); + QTest::newRow("EColor16MA small opaque") << EColor16MA << smallWidth << smallHeight << QColor(255, 255, 0); + QTest::newRow("EColor16MA big opaque") << EColor16MA << largeWidth << largeHeight << QColor(255, 255, 0); + + // Semi-transparent Colors - Disabled for now, since the QCOMPARE fails, but visually confirmed to work +// QTest::newRow("EColor16MA small semi") << EColor16MA << smallWidth << smallHeight << QColor(255, 255, 0, 127); +// QTest::newRow("EColor16MA big semi") << EColor16MA << largeWidth << largeHeight << QColor(255, 255, 0, 127); +// QTest::newRow("EColor16MA small trans") << EColor16MA << smallWidth << smallHeight << QColor(255, 255, 0, 0); +// QTest::newRow("EColor16MA big trans") << EColor16MA << largeWidth << largeHeight << QColor(255, 255, 0, 0); + +#if !defined(__SERIES60_31__) && !defined(__S60_32__) + QTest::newRow("EColor16MAP small") << EColor16MAP << smallWidth << smallHeight << QColor(Qt::red); + QTest::newRow("EColor16MAP big") << EColor16MAP << largeWidth << largeHeight << QColor(Qt::red); +#endif +} + +void tst_QPixmap::fromSymbianCFbsBitmap() +{ + QFETCH(TDisplayMode, format); + QFETCH(int, width); + QFETCH(int, height); + QFETCH(QColor, color); + int expectedDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(format); + + CFbsBitmap *nativeBitmap = 0; + CFbsBitmapDevice *bitmapDevice = 0; + CBitmapContext *bitmapContext = 0; + + nativeBitmap = new (ELeave) CFbsBitmap(); + TInt err = nativeBitmap->Create(TSize(width, height), format); + CleanupStack::PushL(nativeBitmap); + QVERIFY(err == KErrNone); + bitmapDevice = CFbsBitmapDevice::NewL(nativeBitmap); + CleanupStack::PushL(bitmapDevice); + + err = bitmapDevice->CreateBitmapContext(bitmapContext); + CleanupStack::PushL(bitmapContext); + QVERIFY(err == KErrNone); + TRgb symbianColor = TRgb(color.red(), color.green(), color.blue(), color.alpha()); + bitmapContext->SetBrushColor(symbianColor); + bitmapContext->Clear(); + + __UHEAP_MARK; + { // Test the normal case + QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(nativeBitmap); +// QCOMPARE(pixmap.depth(), expectedDepth); // Depth is not preserved now + QCOMPARE(pixmap.width(), width); + QCOMPARE(pixmap.height(), height); + QImage image = pixmap.toImage(); + + QColor actualColor(image.pixel(1, 1)); + QCOMPARE(actualColor, color); + } + __UHEAP_MARKEND; + + CleanupStack::PopAndDestroy(3); +} +#endif + void tst_QPixmap::onlyNullPixmapsOutsideGuiThread() { #if !defined(Q_WS_WIN) |