util/src/gui/image/qpixmap_s60.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 #include <exception>
       
    42 #include <w32std.h>
       
    43 #include <fbs.h>
       
    44 
       
    45 #include <private/qapplication_p.h>
       
    46 #include <private/qgraphicssystem_p.h>
       
    47 #include <private/qt_s60_p.h>
       
    48 #include <private/qpaintengine_s60_p.h>
       
    49 
       
    50 #include "qpixmap.h"
       
    51 #include "qpixmap_raster_p.h"
       
    52 #include <qwidget.h>
       
    53 #include "qpixmap_s60_p.h"
       
    54 #include "qnativeimage_p.h"
       
    55 #include "qbitmap.h"
       
    56 #include "qimage.h"
       
    57 #include "qimage_p.h"
       
    58 
       
    59 #include <fbs.h>
       
    60 
       
    61 QT_BEGIN_NAMESPACE
       
    62 
       
    63 const uchar qt_pixmap_bit_mask[] = { 0x01, 0x02, 0x04, 0x08,
       
    64                                      0x10, 0x20, 0x40, 0x80 };
       
    65 
       
    66 
       
    67 /*
       
    68     \class QSymbianFbsClient
       
    69     \since 4.6
       
    70     \internal
       
    71 
       
    72     Symbian Font And Bitmap server client that is
       
    73     used to lock the global bitmap heap. Only used in
       
    74     S60 v3.1 and S60 v3.2.
       
    75 */
       
    76 _LIT(KFBSERVLargeBitmapAccessName,"FbsLargeBitmapAccess");
       
    77 class QSymbianFbsClient
       
    78 {
       
    79 public:
       
    80 
       
    81     QSymbianFbsClient() : heapLocked(false)
       
    82     {
       
    83         heapLock.OpenGlobal(KFBSERVLargeBitmapAccessName);
       
    84     }
       
    85 
       
    86     ~QSymbianFbsClient()
       
    87     {
       
    88         heapLock.Close();
       
    89     }
       
    90 
       
    91     bool lockHeap()
       
    92     {
       
    93         bool wasLocked = heapLocked;
       
    94 
       
    95         if (heapLock.Handle() && !heapLocked) {
       
    96             heapLock.Wait();
       
    97             heapLocked = true;
       
    98         }
       
    99 
       
   100         return wasLocked;
       
   101     }
       
   102 
       
   103     bool unlockHeap()
       
   104     {
       
   105         bool wasLocked = heapLocked;
       
   106 
       
   107         if (heapLock.Handle() && heapLocked) {
       
   108             heapLock.Signal();
       
   109             heapLocked = false;
       
   110         }
       
   111 
       
   112         return wasLocked;
       
   113     }
       
   114 
       
   115 
       
   116 private:
       
   117 
       
   118     RMutex heapLock;
       
   119     bool heapLocked;
       
   120 };
       
   121 
       
   122 Q_GLOBAL_STATIC(QSymbianFbsClient, qt_symbianFbsClient);
       
   123 
       
   124 
       
   125 
       
   126 // QSymbianFbsHeapLock
       
   127 
       
   128 QSymbianFbsHeapLock::QSymbianFbsHeapLock(LockAction a)
       
   129 : action(a), wasLocked(false)
       
   130 {
       
   131     QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion();
       
   132     if (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3)
       
   133         wasLocked = qt_symbianFbsClient()->unlockHeap();
       
   134 }
       
   135 
       
   136 QSymbianFbsHeapLock::~QSymbianFbsHeapLock()
       
   137 {
       
   138     // Do nothing
       
   139 }
       
   140 
       
   141 void QSymbianFbsHeapLock::relock()
       
   142 {
       
   143     QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion();
       
   144     if (wasLocked && (symbianVersion == QSysInfo::SV_9_2 || symbianVersion == QSysInfo::SV_9_3))
       
   145         qt_symbianFbsClient()->lockHeap();
       
   146 }
       
   147 
       
   148 /*
       
   149     \class QSymbianBitmapDataAccess
       
   150     \since 4.6
       
   151     \internal
       
   152 
       
   153     Data access class that is used to locks/unlocks pixel data
       
   154     when drawing or modifying CFbsBitmap pixel data.
       
   155 */
       
   156 class QSymbianBitmapDataAccess
       
   157 {
       
   158 public:
       
   159 
       
   160     bool heapWasLocked;
       
   161     QSysInfo::SymbianVersion symbianVersion;
       
   162 
       
   163     explicit QSymbianBitmapDataAccess() : heapWasLocked(false)
       
   164     {
       
   165         symbianVersion = QSysInfo::symbianVersion();
       
   166     };
       
   167 
       
   168     ~QSymbianBitmapDataAccess() {};
       
   169 
       
   170     inline void beginDataAccess(CFbsBitmap *bitmap)
       
   171     {
       
   172         if (symbianVersion == QSysInfo::SV_9_2)
       
   173             heapWasLocked = qt_symbianFbsClient()->lockHeap();
       
   174         else
       
   175             bitmap->LockHeap(ETrue);
       
   176     }
       
   177 
       
   178     inline void endDataAccess(CFbsBitmap *bitmap)
       
   179     {
       
   180         if (symbianVersion == QSysInfo::SV_9_2) {
       
   181             if (!heapWasLocked)
       
   182                 qt_symbianFbsClient()->unlockHeap();
       
   183         } else {
       
   184             bitmap->UnlockHeap(ETrue);
       
   185         }
       
   186     }
       
   187 };
       
   188 
       
   189 
       
   190 #define UPDATE_BUFFER()     \
       
   191     {                       \
       
   192     beginDataAccess();      \
       
   193     endDataAccess();        \
       
   194 }
       
   195 
       
   196 
       
   197 static CFbsBitmap* createSymbianCFbsBitmap(const TSize& size, TDisplayMode mode)
       
   198 {
       
   199     QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
       
   200 
       
   201     CFbsBitmap* bitmap = 0;
       
   202     QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap);
       
   203 
       
   204     if (bitmap->Create(size, mode) != KErrNone) {
       
   205         delete bitmap;
       
   206         bitmap = 0;
       
   207     }
       
   208 
       
   209     lock.relock();
       
   210 
       
   211     return bitmap;
       
   212 }
       
   213 
       
   214 static CFbsBitmap* uncompress(CFbsBitmap* bitmap)
       
   215 {
       
   216     if(bitmap->IsCompressedInRAM()) {
       
   217         QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
       
   218 
       
   219         CFbsBitmap *uncompressed = 0;
       
   220         QT_TRAP_THROWING(uncompressed = new (ELeave) CFbsBitmap);
       
   221 
       
   222         if (uncompressed->Create(bitmap->SizeInPixels(), bitmap->DisplayMode()) != KErrNone) {
       
   223             delete bitmap;
       
   224             bitmap = 0;
       
   225             lock.relock();
       
   226 
       
   227             return bitmap;
       
   228         }
       
   229 
       
   230         lock.relock();
       
   231 
       
   232         CFbsBitmapDevice* bitmapDevice = 0;
       
   233         CFbsBitGc *bitmapGc = 0;
       
   234         QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(uncompressed));
       
   235         QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL());
       
   236         bitmapGc->Activate(bitmapDevice);
       
   237 
       
   238         bitmapGc->BitBlt(TPoint(), bitmap);
       
   239 
       
   240         delete bitmapGc;
       
   241         delete bitmapDevice;
       
   242 
       
   243         return uncompressed;
       
   244     } else {
       
   245         return bitmap;
       
   246     }
       
   247 }
       
   248 
       
   249 QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h)
       
   250 {
       
   251     CWsScreenDevice* screenDevice = S60->screenDevice();
       
   252     TSize screenSize = screenDevice->SizeInPixels();
       
   253 
       
   254     TSize srcSize;
       
   255     // Find out if this is one of our windows.
       
   256     QSymbianControl *sControl;
       
   257     sControl = winId->MopGetObject(sControl);
       
   258     if (sControl && sControl->widget()->windowType() == Qt::Desktop) {
       
   259         // Grabbing desktop widget
       
   260         srcSize = screenSize;
       
   261     } else {
       
   262         TPoint relativePos = winId->PositionRelativeToScreen();
       
   263         x += relativePos.iX;
       
   264         y += relativePos.iY;
       
   265         srcSize = winId->Size();
       
   266     }
       
   267 
       
   268     TRect srcRect(TPoint(x, y), srcSize);
       
   269     // Clip to the screen
       
   270     srcRect.Intersection(TRect(screenSize));
       
   271 
       
   272     if (w > 0 && h > 0) {
       
   273         TRect subRect(TPoint(x, y), TSize(w, h));
       
   274         // Clip to the subRect
       
   275         srcRect.Intersection(subRect);
       
   276     }
       
   277 
       
   278     if (srcRect.IsEmpty())
       
   279         return QPixmap();
       
   280 
       
   281     CFbsBitmap* temporary = createSymbianCFbsBitmap(srcRect.Size(), screenDevice->DisplayMode());
       
   282 
       
   283     QPixmap pix;
       
   284 
       
   285     if (temporary && screenDevice->CopyScreenToBitmap(temporary, srcRect) == KErrNone) {
       
   286         pix = QPixmap::fromSymbianCFbsBitmap(temporary);
       
   287     }
       
   288 
       
   289     delete temporary;
       
   290     return pix;
       
   291 }
       
   292 
       
   293 /*!
       
   294     \fn CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const
       
   295     \since 4.6
       
   296 
       
   297     Creates a \c CFbsBitmap that is equivalent to the QPixmap. Internally this
       
   298     function will try to duplicate the handle instead of copying the data,
       
   299     however in scenarios where this is not possible the data will be copied.
       
   300     If the creation fails or the pixmap is null, then this function returns 0.
       
   301 
       
   302     It is the caller's responsibility to release the \c CFbsBitmap data
       
   303     after use either by deleting the bitmap or calling \c Reset().
       
   304 
       
   305     \warning On S60 3.1 and S60 3.2, semi-transparent pixmaps are always copied
       
   306              and not duplicated.
       
   307     \warning This function is only available on Symbian OS.
       
   308 
       
   309     \sa fromSymbianCFbsBitmap()
       
   310 */
       
   311 CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const
       
   312 {
       
   313     QPixmapData *data = pixmapData();
       
   314     if (!data || data->isNull())
       
   315         return 0;
       
   316 
       
   317     return reinterpret_cast<CFbsBitmap*>(data->toNativeType(QPixmapData::FbsBitmap));
       
   318 }
       
   319 
       
   320 /*!
       
   321     \fn QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap)
       
   322     \since 4.6
       
   323 
       
   324     Creates a QPixmap from a \c CFbsBitmap \a bitmap. Internally this function
       
   325     will try to duplicate the bitmap handle instead of copying the data, however
       
   326     in scenarios where this is not possible the data will be copied.
       
   327     To be sure that QPixmap does not modify your original instance, you should
       
   328     make a copy of your \c CFbsBitmap before calling this function.
       
   329     If the CFbsBitmap is not valid this function will return a null QPixmap.
       
   330 
       
   331     \warning This function is only available on Symbian OS.
       
   332 
       
   333     \sa toSymbianCFbsBitmap(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
       
   334 */
       
   335 QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap)
       
   336 {
       
   337     if (!bitmap)
       
   338         return QPixmap();
       
   339 
       
   340     QScopedPointer<QPixmapData> data(QPixmapData::create(0,0, QPixmapData::PixmapType));
       
   341     data->fromNativeType(reinterpret_cast<void*>(bitmap), QPixmapData::FbsBitmap);
       
   342     QPixmap pixmap(data.take());
       
   343     return pixmap;
       
   344 }
       
   345 
       
   346 QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type),
       
   347     symbianBitmapDataAccess(new QSymbianBitmapDataAccess),
       
   348     cfbsBitmap(0),
       
   349     pengine(0),
       
   350     bytes(0),
       
   351     formatLocked(false)
       
   352 {
       
   353 
       
   354 }
       
   355 
       
   356 QS60PixmapData::~QS60PixmapData()
       
   357 {
       
   358     release();
       
   359     delete symbianBitmapDataAccess;
       
   360 }
       
   361 
       
   362 void QS60PixmapData::resize(int width, int height)
       
   363 {
       
   364     if (width <= 0 || height <= 0) {
       
   365         w = width;
       
   366         h = height;
       
   367         is_null = true;
       
   368 
       
   369         release();
       
   370         return;
       
   371     } else if (!cfbsBitmap) {
       
   372         TDisplayMode mode;
       
   373         if (pixelType() == BitmapType)
       
   374             mode = EGray2;
       
   375         else
       
   376             mode = EColor16MU;
       
   377 
       
   378         CFbsBitmap* bitmap = createSymbianCFbsBitmap(TSize(width, height), mode);
       
   379         fromSymbianBitmap(bitmap);
       
   380     } else {
       
   381 
       
   382         TSize newSize(width, height);
       
   383 
       
   384         if(cfbsBitmap->SizeInPixels() != newSize) {
       
   385             cfbsBitmap->Resize(TSize(width, height));
       
   386             if(pengine) {
       
   387                 delete pengine;
       
   388                 pengine = 0;
       
   389             }
       
   390         }
       
   391 
       
   392         UPDATE_BUFFER();
       
   393     }
       
   394 }
       
   395 
       
   396 void QS60PixmapData::release()
       
   397 {
       
   398     if (cfbsBitmap) {
       
   399         QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
       
   400         delete cfbsBitmap;
       
   401         lock.relock();
       
   402     }
       
   403 
       
   404     delete pengine;
       
   405     image = QImage();
       
   406     cfbsBitmap = 0;
       
   407     pengine = 0;
       
   408     bytes = 0;
       
   409 }
       
   410 
       
   411 /*!
       
   412  * Takes ownership of bitmap. Used by window surface
       
   413  */
       
   414 void QS60PixmapData::fromSymbianBitmap(CFbsBitmap* bitmap, bool lockFormat)
       
   415 {
       
   416     Q_ASSERT(bitmap);
       
   417 
       
   418     release();
       
   419 
       
   420     cfbsBitmap = bitmap;
       
   421     formatLocked = lockFormat;
       
   422 
       
   423     setSerialNumber(cfbsBitmap->Handle());
       
   424 
       
   425     UPDATE_BUFFER();
       
   426 
       
   427     // Create default palette if needed
       
   428     if (cfbsBitmap->DisplayMode() == EGray2) {
       
   429         image.setColorCount(2);
       
   430         image.setColor(0, QColor(Qt::color0).rgba());
       
   431         image.setColor(1, QColor(Qt::color1).rgba());
       
   432 
       
   433         //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
       
   434         //So invert mono bitmaps so that masks work correctly.
       
   435         image.invertPixels();
       
   436     } else if (cfbsBitmap->DisplayMode() == EGray256) {
       
   437         for (int i=0; i < 256; ++i)
       
   438             image.setColor(i, qRgb(i, i, i));
       
   439     } else if (cfbsBitmap->DisplayMode() == EColor256) {
       
   440         const TColor256Util *palette = TColor256Util::Default();
       
   441         for (int i=0; i < 256; ++i)
       
   442             image.setColor(i, (QRgb)(palette->Color256(i).Value()));
       
   443     }
       
   444 }
       
   445 
       
   446 QImage QS60PixmapData::toImage(const QRect &r) const
       
   447 {
       
   448     QS60PixmapData *that = const_cast<QS60PixmapData*>(this);
       
   449     that->beginDataAccess();
       
   450     QImage copy = that->image.copy(r);
       
   451     that->endDataAccess();
       
   452 
       
   453     return copy;
       
   454 }
       
   455 
       
   456 void QS60PixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags)
       
   457 {
       
   458     release();
       
   459 
       
   460     QImage sourceImage;
       
   461 
       
   462     if (pixelType() == BitmapType) {
       
   463         sourceImage = img.convertToFormat(QImage::Format_MonoLSB);
       
   464     } else {
       
   465         if (img.depth() == 1) {
       
   466             sourceImage = img.hasAlphaChannel()
       
   467                         ? img.convertToFormat(QImage::Format_ARGB32_Premultiplied)
       
   468                         : img.convertToFormat(QImage::Format_RGB32);
       
   469         } else {
       
   470 
       
   471             QImage::Format opaqueFormat = QNativeImage::systemFormat();
       
   472             QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied;
       
   473 
       
   474             if (!img.hasAlphaChannel()
       
   475                 || ((flags & Qt::NoOpaqueDetection) == 0
       
   476                     && !const_cast<QImage &>(img).data_ptr()->checkForAlphaPixels())) {
       
   477                 sourceImage = img.convertToFormat(opaqueFormat);
       
   478             } else {
       
   479                 sourceImage = img.convertToFormat(alphaFormat);
       
   480             }
       
   481         }
       
   482     }
       
   483 
       
   484 
       
   485     QImage::Format destFormat = sourceImage.format();
       
   486     TDisplayMode mode;
       
   487     switch (destFormat) {
       
   488     case QImage::Format_MonoLSB:
       
   489         mode = EGray2;
       
   490         break;
       
   491     case QImage::Format_RGB32:
       
   492         mode = EColor16MU;
       
   493         break;
       
   494     case QImage::Format_ARGB32_Premultiplied:
       
   495         if (S60->supportsPremultipliedAlpha) {
       
   496             mode = Q_SYMBIAN_ECOLOR16MAP;
       
   497             break;
       
   498         } else {
       
   499             destFormat = QImage::Format_ARGB32;
       
   500         }
       
   501         // Fall through intended
       
   502     case QImage::Format_ARGB32:
       
   503         mode = EColor16MA;
       
   504         break;
       
   505     case QImage::Format_Invalid:
       
   506         return;
       
   507     default:
       
   508         qWarning("Image format not supported: %d", image.format());
       
   509         return;
       
   510     }
       
   511 
       
   512     cfbsBitmap = createSymbianCFbsBitmap(TSize(sourceImage.width(), sourceImage.height()), mode);
       
   513     if (!cfbsBitmap) {
       
   514         qWarning("Could not create CFbsBitmap");
       
   515         release();
       
   516         return;
       
   517     }
       
   518 
       
   519     setSerialNumber(cfbsBitmap->Handle());
       
   520 
       
   521     const uchar *sptr = const_cast<const QImage &>(sourceImage).bits();
       
   522     symbianBitmapDataAccess->beginDataAccess(cfbsBitmap);
       
   523     uchar *dptr = (uchar*)cfbsBitmap->DataAddress();
       
   524     Mem::Copy(dptr, sptr, sourceImage.byteCount());
       
   525     symbianBitmapDataAccess->endDataAccess(cfbsBitmap);
       
   526 
       
   527     UPDATE_BUFFER();
       
   528 
       
   529     if (destFormat == QImage::Format_MonoLSB) {
       
   530 		image.setColorCount(2);
       
   531 		image.setColor(0, QColor(Qt::color0).rgba());
       
   532 		image.setColor(1, QColor(Qt::color1).rgba());
       
   533 	} else {
       
   534 		image.setColorTable(sourceImage.colorTable());
       
   535 	}
       
   536 }
       
   537 
       
   538 void QS60PixmapData::copy(const QPixmapData *data, const QRect &rect)
       
   539 {
       
   540     const QS60PixmapData *s60Data = static_cast<const QS60PixmapData*>(data);
       
   541     fromImage(s60Data->toImage(rect), Qt::AutoColor | Qt::OrderedAlphaDither);
       
   542 }
       
   543 
       
   544 bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect)
       
   545 {
       
   546     beginDataAccess();
       
   547     bool res = QRasterPixmapData::scroll(dx, dy, rect);
       
   548     endDataAccess();
       
   549     return res;
       
   550 }
       
   551 
       
   552 int QS60PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
       
   553 {
       
   554     if (!cfbsBitmap)
       
   555         return 0;
       
   556 
       
   557     switch (metric) {
       
   558     case QPaintDevice::PdmWidth:
       
   559         return cfbsBitmap->SizeInPixels().iWidth;
       
   560     case QPaintDevice::PdmHeight:
       
   561         return cfbsBitmap->SizeInPixels().iHeight;
       
   562     case QPaintDevice::PdmWidthMM: {
       
   563         TInt twips = cfbsBitmap->SizeInTwips().iWidth;
       
   564         return (int)(twips * (25.4/KTwipsPerInch));
       
   565     }
       
   566     case QPaintDevice::PdmHeightMM: {
       
   567         TInt twips = cfbsBitmap->SizeInTwips().iHeight;
       
   568         return (int)(twips * (25.4/KTwipsPerInch));
       
   569     }
       
   570     case QPaintDevice::PdmNumColors:
       
   571         return TDisplayModeUtils::NumDisplayModeColors(cfbsBitmap->DisplayMode());
       
   572     case QPaintDevice::PdmDpiX:
       
   573     case QPaintDevice::PdmPhysicalDpiX: {
       
   574         TReal inches = cfbsBitmap->SizeInTwips().iWidth / (TReal)KTwipsPerInch;
       
   575         TInt pixels = cfbsBitmap->SizeInPixels().iWidth;
       
   576         return pixels / inches;
       
   577     }
       
   578     case QPaintDevice::PdmDpiY:
       
   579     case QPaintDevice::PdmPhysicalDpiY: {
       
   580         TReal inches = cfbsBitmap->SizeInTwips().iHeight / (TReal)KTwipsPerInch;
       
   581         TInt pixels = cfbsBitmap->SizeInPixels().iHeight;
       
   582         return pixels / inches;
       
   583     }
       
   584     case QPaintDevice::PdmDepth:
       
   585         return TDisplayModeUtils::NumDisplayModeBitsPerPixel(cfbsBitmap->DisplayMode());
       
   586     default:
       
   587         qWarning("QPixmap::metric: Invalid metric command");
       
   588     }
       
   589     return 0;
       
   590 
       
   591 }
       
   592 
       
   593 void QS60PixmapData::fill(const QColor &color)
       
   594 {
       
   595     if (color.alpha() != 255) {
       
   596         QImage im(width(), height(), QImage::Format_ARGB32_Premultiplied);
       
   597         im.fill(PREMUL(color.rgba()));
       
   598         release();
       
   599         fromImage(im, Qt::AutoColor | Qt::OrderedAlphaDither);
       
   600     } else {
       
   601         beginDataAccess();
       
   602         QRasterPixmapData::fill(color);
       
   603         endDataAccess();
       
   604     }
       
   605 }
       
   606 
       
   607 void QS60PixmapData::setMask(const QBitmap &mask)
       
   608 {
       
   609     if (mask.size().isEmpty()) {
       
   610         if (image.depth() != 1) {
       
   611             QImage newImage = image.convertToFormat(QImage::Format_RGB32);
       
   612             release();
       
   613             fromImage(newImage,  Qt::AutoColor | Qt::OrderedAlphaDither);
       
   614         }
       
   615     } else if (image.depth() == 1) {
       
   616         beginDataAccess();
       
   617         QRasterPixmapData::setMask(mask);
       
   618         endDataAccess();
       
   619     } else {
       
   620         const int w = image.width();
       
   621         const int h = image.height();
       
   622 
       
   623         const QImage imageMask = mask.toImage().convertToFormat(QImage::Format_MonoLSB);
       
   624         QImage newImage = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
       
   625         for (int y = 0; y < h; ++y) {
       
   626             const uchar *mscan = imageMask.scanLine(y);
       
   627             QRgb *tscan = (QRgb *)newImage.scanLine(y);
       
   628             for (int x = 0; x < w; ++x) {
       
   629                 if (!(mscan[x>>3] & qt_pixmap_bit_mask[x&7]))
       
   630                     tscan[x] = 0;
       
   631             }
       
   632         }
       
   633         release();
       
   634         fromImage(newImage,  Qt::AutoColor | Qt::OrderedAlphaDither);
       
   635     }
       
   636 }
       
   637 
       
   638 void QS60PixmapData::setAlphaChannel(const QPixmap &alphaChannel)
       
   639 {
       
   640     QImage img(toImage());
       
   641     img.setAlphaChannel(alphaChannel.toImage());
       
   642     release();
       
   643     fromImage(img, Qt::OrderedDither | Qt::OrderedAlphaDither);
       
   644 }
       
   645 
       
   646 QImage QS60PixmapData::toImage() const
       
   647 {
       
   648     return toImage(QRect());
       
   649 }
       
   650 
       
   651 QPaintEngine* QS60PixmapData::paintEngine() const
       
   652 {
       
   653     if (!pengine) {
       
   654         QS60PixmapData *that = const_cast<QS60PixmapData*>(this);
       
   655         that->pengine = new QS60PaintEngine(&that->image, that);
       
   656     }
       
   657     return pengine;
       
   658 }
       
   659 
       
   660 void QS60PixmapData::beginDataAccess()
       
   661 {
       
   662     if(!cfbsBitmap)
       
   663         return;
       
   664 
       
   665     symbianBitmapDataAccess->beginDataAccess(cfbsBitmap);
       
   666 
       
   667     uchar* newBytes = (uchar*)cfbsBitmap->DataAddress();
       
   668 
       
   669     TSize size = cfbsBitmap->SizeInPixels();
       
   670 
       
   671     if (newBytes == bytes && image.width() == size.iWidth && image.height() == size.iHeight)
       
   672         return;
       
   673 
       
   674     bytes = newBytes;
       
   675     TDisplayMode mode = cfbsBitmap->DisplayMode();
       
   676     QImage::Format format = qt_TDisplayMode2Format(mode);
       
   677     // On S60 3.1, premultiplied alpha pixels are stored in a bitmap with 16MA type.
       
   678     // S60 window surface needs backing store pixmap for transparent window in ARGB32 format.
       
   679     // In that case formatLocked is true.
       
   680     if (!formatLocked && format == QImage::Format_ARGB32)
       
   681         format = QImage::Format_ARGB32_Premultiplied; // pixel data is actually in premultiplied format
       
   682 
       
   683     QVector<QRgb> savedColorTable;
       
   684     if (!image.isNull())
       
   685         savedColorTable = image.colorTable();
       
   686 
       
   687     image = QImage(bytes, size.iWidth, size.iHeight, format);
       
   688 
       
   689     // Restore the palette or create a default
       
   690     if (!savedColorTable.isEmpty()) {
       
   691         image.setColorTable(savedColorTable);
       
   692     }
       
   693 
       
   694     w = size.iWidth;
       
   695     h = size.iHeight;
       
   696     d = image.depth();
       
   697     is_null = (w <= 0 || h <= 0);
       
   698 
       
   699     if (pengine) {
       
   700         QS60PaintEngine *engine = static_cast<QS60PaintEngine *>(pengine);
       
   701         engine->prepare(&image);
       
   702     }
       
   703 }
       
   704 
       
   705 void QS60PixmapData::endDataAccess(bool readOnly) const
       
   706 {
       
   707     Q_UNUSED(readOnly);
       
   708 
       
   709     if(!cfbsBitmap)
       
   710         return;
       
   711 
       
   712     symbianBitmapDataAccess->endDataAccess(cfbsBitmap);
       
   713 }
       
   714 
       
   715 /*!
       
   716   \since 4.6
       
   717 
       
   718   Returns a QPixmap that wraps given \a sgImage graphics resource.
       
   719   The data should be valid even when original RSgImage handle has been
       
   720   closed.
       
   721 
       
   722   \warning This function is only available on Symbian OS.
       
   723 
       
   724   \sa toSymbianRSgImage(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
       
   725 */
       
   726 
       
   727 QPixmap QPixmap::fromSymbianRSgImage(RSgImage *sgImage)
       
   728 {
       
   729     // It is expected that RSgImage will
       
   730     // CURRENTLY be used in conjuction with
       
   731     // OpenVG graphics system
       
   732     //
       
   733     // Surely things might change in future
       
   734 
       
   735     if (!sgImage)
       
   736         return QPixmap();
       
   737 
       
   738     QScopedPointer<QPixmapData> data(QPixmapData::create(0,0, QPixmapData::PixmapType));
       
   739     data->fromNativeType(reinterpret_cast<void*>(sgImage), QPixmapData::SgImage);
       
   740     QPixmap pixmap(data.take());
       
   741     return pixmap;
       
   742 }
       
   743 
       
   744 /*!
       
   745 \since 4.6
       
   746 
       
   747 Returns a \c RSgImage that is equivalent to the QPixmap by copying the data.
       
   748 
       
   749 It is the caller's responsibility to close/delete the \c RSgImage after use.
       
   750 
       
   751 \warning This function is only available on Symbian OS.
       
   752 
       
   753 \sa fromSymbianRSgImage()
       
   754 */
       
   755 
       
   756 RSgImage *QPixmap::toSymbianRSgImage() const
       
   757 {
       
   758     // It is expected that RSgImage will
       
   759     // CURRENTLY be used in conjuction with
       
   760     // OpenVG graphics system
       
   761     //
       
   762     // Surely things might change in future
       
   763 
       
   764     if (isNull())
       
   765         return 0;
       
   766 
       
   767     RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmapData()->toNativeType(QPixmapData::SgImage));
       
   768 
       
   769     return sgImage;
       
   770 }
       
   771 
       
   772 void* QS60PixmapData::toNativeType(NativeType type)
       
   773 {
       
   774     if (type == QPixmapData::SgImage) {
       
   775         return 0;
       
   776     } else if (type == QPixmapData::FbsBitmap) {
       
   777 
       
   778         if (isNull() || !cfbsBitmap)
       
   779             return 0;
       
   780 
       
   781         bool convertToArgb32 = false;
       
   782         bool needsCopy = false;
       
   783 
       
   784         QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion();
       
   785         if (!(S60->supportsPremultipliedAlpha)) {
       
   786             // Convert argb32_premultiplied to argb32 since Symbian 9.2 does
       
   787             // not support premultipied format.
       
   788 
       
   789             if (image.format() == QImage::Format_ARGB32_Premultiplied) {
       
   790                 needsCopy = true;
       
   791                 convertToArgb32 = true;
       
   792             }
       
   793         }
       
   794 
       
   795         CFbsBitmap *bitmap = 0;
       
   796 
       
   797         TDisplayMode displayMode = cfbsBitmap->DisplayMode();
       
   798 
       
   799         if(displayMode == EGray2) {
       
   800             //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
       
   801             //So invert mono bitmaps so that masks work correctly.
       
   802             beginDataAccess();
       
   803             image.invertPixels();
       
   804             endDataAccess();
       
   805             needsCopy = true;
       
   806         }
       
   807 
       
   808         if (needsCopy) {
       
   809             QImage source;
       
   810 
       
   811             if (convertToArgb32) {
       
   812                 beginDataAccess();
       
   813                 source = image.convertToFormat(QImage::Format_ARGB32);
       
   814                 endDataAccess();
       
   815                 displayMode = EColor16MA;
       
   816             } else {
       
   817                 source = image;
       
   818             }
       
   819 
       
   820             CFbsBitmap *newBitmap = createSymbianCFbsBitmap(TSize(source.width(), source.height()), displayMode);
       
   821             const uchar *sptr = source.bits();
       
   822             symbianBitmapDataAccess->beginDataAccess(newBitmap);
       
   823 
       
   824             uchar *dptr = (uchar*)newBitmap->DataAddress();
       
   825             Mem::Copy(dptr, sptr, source.byteCount());
       
   826 
       
   827             symbianBitmapDataAccess->endDataAccess(newBitmap);
       
   828 
       
   829             bitmap = newBitmap;
       
   830         } else {
       
   831 
       
   832             QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap);
       
   833 
       
   834             TInt err = bitmap->Duplicate(cfbsBitmap->Handle());
       
   835             if (err != KErrNone) {
       
   836                 qWarning("Could not duplicate CFbsBitmap");
       
   837                 delete bitmap;
       
   838                 bitmap = 0;
       
   839             }
       
   840         }
       
   841 
       
   842         if(displayMode == EGray2) {
       
   843             // restore pixels
       
   844             beginDataAccess();
       
   845             image.invertPixels();
       
   846             endDataAccess();
       
   847         }
       
   848 
       
   849         return reinterpret_cast<void*>(bitmap);
       
   850 
       
   851     }
       
   852 
       
   853     return 0;
       
   854 }
       
   855 
       
   856 void QS60PixmapData::fromNativeType(void* pixmap, NativeType nativeType)
       
   857 {
       
   858     if (nativeType == QPixmapData::SgImage) {
       
   859         return;
       
   860     } else if (nativeType == QPixmapData::FbsBitmap && pixmap) {
       
   861 
       
   862         CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap*>(pixmap);
       
   863 
       
   864         bool deleteSourceBitmap = false;
       
   865         bool needsCopy = false;
       
   866 
       
   867 #ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE
       
   868 
       
   869         // Rasterize extended bitmaps
       
   870 
       
   871         TUid extendedBitmapType = bitmap->ExtendedBitmapType();
       
   872         if (extendedBitmapType != KNullUid) {
       
   873             CFbsBitmap *rasterBitmap = createSymbianCFbsBitmap(bitmap->SizeInPixels(), EColor16MA);
       
   874 
       
   875             CFbsBitmapDevice *rasterBitmapDev = 0;
       
   876             QT_TRAP_THROWING(rasterBitmapDev = CFbsBitmapDevice::NewL(rasterBitmap));
       
   877 
       
   878             CFbsBitGc *rasterBitmapGc = 0;
       
   879             TInt err = rasterBitmapDev->CreateContext(rasterBitmapGc);
       
   880             if (err != KErrNone) {
       
   881                 delete rasterBitmap;
       
   882                 delete rasterBitmapDev;
       
   883                 rasterBitmapDev = 0;
       
   884                 return;
       
   885             }
       
   886 
       
   887             rasterBitmapGc->BitBlt(TPoint( 0, 0), bitmap);
       
   888 
       
   889             bitmap = rasterBitmap;
       
   890 
       
   891             delete rasterBitmapDev;
       
   892             delete rasterBitmapGc;
       
   893 
       
   894             rasterBitmapDev = 0;
       
   895             rasterBitmapGc = 0;
       
   896 
       
   897             deleteSourceBitmap = true;
       
   898         }
       
   899 #endif
       
   900 
       
   901 
       
   902         deleteSourceBitmap = bitmap->IsCompressedInRAM();
       
   903         CFbsBitmap *sourceBitmap = uncompress(bitmap);
       
   904 
       
   905         TDisplayMode displayMode = sourceBitmap->DisplayMode();
       
   906         QImage::Format format = qt_TDisplayMode2Format(displayMode);
       
   907 
       
   908         QImage::Format opaqueFormat = QNativeImage::systemFormat();
       
   909         QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied;
       
   910 
       
   911         if (format != opaqueFormat && format != alphaFormat && format != QImage::Format_MonoLSB)
       
   912             needsCopy = true;
       
   913 
       
   914 
       
   915         type = (format != QImage::Format_MonoLSB)
       
   916                     ? QPixmapData::PixmapType
       
   917                     : QPixmapData::BitmapType;
       
   918 
       
   919         if (needsCopy) {
       
   920 
       
   921             TSize size = sourceBitmap->SizeInPixels();
       
   922 
       
   923             QSymbianBitmapDataAccess da;
       
   924             da.beginDataAccess(sourceBitmap);
       
   925             uchar *bytes = (uchar*)sourceBitmap->DataAddress();
       
   926             QImage img = QImage(bytes, size.iWidth, size.iHeight, format);
       
   927             img = img.copy();
       
   928             da.endDataAccess(sourceBitmap);
       
   929 
       
   930             if(displayMode == EGray2) {
       
   931                 //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
       
   932                 //So invert mono bitmaps so that masks work correctly.
       
   933                 img.invertPixels();
       
   934             } else if(displayMode == EColor16M) {
       
   935                 img = img.rgbSwapped(); // EColor16M is BGR
       
   936             }
       
   937 
       
   938             fromImage(img, Qt::AutoColor);
       
   939 
       
   940             if(deleteSourceBitmap)
       
   941                 delete sourceBitmap;
       
   942         } else {
       
   943             CFbsBitmap* duplicate = 0;
       
   944             QT_TRAP_THROWING(duplicate = new (ELeave) CFbsBitmap);
       
   945 
       
   946             TInt err = duplicate->Duplicate(sourceBitmap->Handle());
       
   947             if (err != KErrNone) {
       
   948                 qWarning("Could not duplicate CFbsBitmap");
       
   949 
       
   950                 if(deleteSourceBitmap)
       
   951                     delete sourceBitmap;
       
   952 
       
   953                 delete duplicate;
       
   954                 return;
       
   955             }
       
   956 
       
   957             fromSymbianBitmap(duplicate);
       
   958 
       
   959             if(deleteSourceBitmap)
       
   960                 delete sourceBitmap;
       
   961         }
       
   962     }
       
   963 }
       
   964 
       
   965 QPixmapData *QS60PixmapData::createCompatiblePixmapData() const
       
   966 {
       
   967     return new QS60PixmapData(pixelType());
       
   968 }
       
   969 
       
   970 QT_END_NAMESPACE