src/gui/image/qpixmap_s60.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 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 class QSymbianFbsClient
       
    77 {
       
    78 public:
       
    79 
       
    80     QSymbianFbsClient() : heapLock(0), heapLocked(false)
       
    81     {
       
    82         QT_TRAP_THROWING(heapLock = new(ELeave) CFbsBitmap);
       
    83         heapLock->Create(TSize(0,0), S60->screenDevice()->DisplayMode());
       
    84     }
       
    85 
       
    86     ~QSymbianFbsClient()
       
    87     {
       
    88         delete heapLock;
       
    89     }
       
    90 
       
    91     bool lockHeap()
       
    92     {
       
    93         bool wasLocked = heapLocked;
       
    94 
       
    95         if (heapLock && !heapLocked) {
       
    96             heapLock->LockHeap(ETrue);
       
    97             heapLocked = true;
       
    98         }
       
    99 
       
   100         return wasLocked;
       
   101     }
       
   102 
       
   103     bool unlockHeap()
       
   104     {
       
   105         bool wasLocked = heapLocked;
       
   106 
       
   107         if (heapLock && heapLocked) {
       
   108             heapLock->UnlockHeap(ETrue);
       
   109             heapLocked = false;
       
   110         }
       
   111 
       
   112         return wasLocked;
       
   113     }
       
   114 
       
   115 
       
   116 private:
       
   117 
       
   118     CFbsBitmap *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 || symbianVersion == QSysInfo::SV_9_3)
       
   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 || symbianVersion == QSysInfo::SV_9_3) {
       
   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->DrawBitmap(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->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     QPixmap pixmap;
       
   341     pixmap.pixmapData()->fromNativeType(reinterpret_cast<void*>(bitmap), QPixmapData::FbsBitmap);
       
   342     return pixmap;
       
   343 }
       
   344 
       
   345 QS60PixmapData::QS60PixmapData(PixelType type) : QRasterPixmapData(type),
       
   346     symbianBitmapDataAccess(new QSymbianBitmapDataAccess),
       
   347     cfbsBitmap(0),
       
   348     bitmapDevice(0),
       
   349     bitmapGc(0),
       
   350     pengine(0),
       
   351     bytes(0)
       
   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             bitmapDevice->Resize(TSize(width, height));
       
   387             bitmapGc->Resized();
       
   388             if(pengine) {
       
   389                 delete pengine;
       
   390                 pengine = 0;
       
   391             }
       
   392         }
       
   393 
       
   394         UPDATE_BUFFER();
       
   395     }
       
   396 }
       
   397 
       
   398 bool QS60PixmapData::initSymbianBitmapContext()
       
   399 {
       
   400     QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(cfbsBitmap));
       
   401     QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL());
       
   402     bitmapGc->Activate(bitmapDevice);
       
   403 
       
   404     return true;
       
   405 }
       
   406 
       
   407 void QS60PixmapData::release()
       
   408 {
       
   409     if (cfbsBitmap) {
       
   410         QSymbianFbsHeapLock lock(QSymbianFbsHeapLock::Unlock);
       
   411         delete bitmapGc;
       
   412         delete bitmapDevice;
       
   413         delete cfbsBitmap;
       
   414         lock.relock();
       
   415     }
       
   416 
       
   417     delete pengine;
       
   418     image = QImage();
       
   419     cfbsBitmap = 0;
       
   420     bitmapGc = 0;
       
   421     bitmapDevice = 0;
       
   422     pengine = 0;
       
   423     bytes = 0;
       
   424 }
       
   425 
       
   426 /*!
       
   427  * Takes ownership of bitmap
       
   428  */
       
   429 void QS60PixmapData::fromSymbianBitmap(CFbsBitmap* bitmap)
       
   430 {
       
   431 	cfbsBitmap = bitmap;
       
   432 
       
   433 	 if(!initSymbianBitmapContext()) {
       
   434 		qWarning("Could not create CBitmapContext");
       
   435 		release();
       
   436 		return;
       
   437 	}
       
   438 
       
   439 	setSerialNumber(cfbsBitmap->Handle());
       
   440 
       
   441 	UPDATE_BUFFER();
       
   442 
       
   443 	// Create default palette if needed
       
   444 	if (cfbsBitmap->DisplayMode() == EGray2) {
       
   445 		image.setNumColors(2);
       
   446 		image.setColor(0, QColor(Qt::color0).rgba());
       
   447 		image.setColor(1, QColor(Qt::color1).rgba());
       
   448 
       
   449         //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
       
   450         //So invert mono bitmaps so that masks work correctly.
       
   451         image.invertPixels();
       
   452 	} else if (cfbsBitmap->DisplayMode() == EGray256) {
       
   453 		for (int i=0; i < 256; ++i)
       
   454 			image.setColor(i, qRgb(i, i, i));
       
   455 	}else if (cfbsBitmap->DisplayMode() == EColor256) {
       
   456 		const TColor256Util *palette = TColor256Util::Default();
       
   457 		for (int i=0; i < 256; ++i)
       
   458 			image.setColor(i, (QRgb)(palette->Color256(i).Value()));
       
   459 	}
       
   460 }
       
   461 
       
   462 void QS60PixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags flags)
       
   463 {
       
   464     QImage sourceImage;
       
   465 
       
   466     if (pixelType() == BitmapType) {
       
   467         sourceImage = img.convertToFormat(QImage::Format_MonoLSB);
       
   468     } else {
       
   469         if (img.depth() == 1) {
       
   470             sourceImage = img.hasAlphaChannel()
       
   471                         ? img.convertToFormat(QImage::Format_ARGB32_Premultiplied)
       
   472                         : img.convertToFormat(QImage::Format_RGB32);
       
   473         } else {
       
   474 
       
   475             QImage::Format opaqueFormat = QNativeImage::systemFormat();
       
   476             QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied;
       
   477 
       
   478             if (!img.hasAlphaChannel()
       
   479                 || ((flags & Qt::NoOpaqueDetection) == 0
       
   480                     && !const_cast<QImage &>(img).data_ptr()->checkForAlphaPixels())) {
       
   481                 sourceImage = img.convertToFormat(opaqueFormat);
       
   482             } else {
       
   483                 sourceImage = img.convertToFormat(alphaFormat);
       
   484             }
       
   485         }
       
   486     }
       
   487 
       
   488 
       
   489     QImage::Format destFormat = sourceImage.format();
       
   490     TDisplayMode mode;
       
   491     switch (destFormat) {
       
   492     case QImage::Format_MonoLSB:
       
   493         mode = EGray2;
       
   494         break;
       
   495     case QImage::Format_RGB32:
       
   496         mode = EColor16MU;
       
   497         break;
       
   498     case QImage::Format_ARGB32_Premultiplied:
       
   499         if (S60->supportsPremultipliedAlpha) {
       
   500             mode = Q_SYMBIAN_ECOLOR16MAP;
       
   501             break;
       
   502         } else {
       
   503             destFormat = QImage::Format_ARGB32;
       
   504         }
       
   505         // Fall through intended
       
   506     case QImage::Format_ARGB32:
       
   507         mode = EColor16MA;
       
   508         break;
       
   509     case QImage::Format_Invalid:
       
   510         return;
       
   511     default:
       
   512         qWarning("Image format not supported: %d", image.format());
       
   513         return;
       
   514     }
       
   515 
       
   516     cfbsBitmap = createSymbianCFbsBitmap(TSize(sourceImage.width(), sourceImage.height()), mode);
       
   517     if (!(cfbsBitmap && initSymbianBitmapContext())) {
       
   518         qWarning("Could not create CFbsBitmap and/or CBitmapContext");
       
   519         release();
       
   520         return;
       
   521     }
       
   522 
       
   523     setSerialNumber(cfbsBitmap->Handle());
       
   524 
       
   525     const uchar *sptr = const_cast<const QImage &>(sourceImage).bits();
       
   526     symbianBitmapDataAccess->beginDataAccess(cfbsBitmap);
       
   527     uchar *dptr = (uchar*)cfbsBitmap->DataAddress();
       
   528     Mem::Copy(dptr, sptr, sourceImage.numBytes());
       
   529     symbianBitmapDataAccess->endDataAccess(cfbsBitmap);
       
   530 
       
   531     UPDATE_BUFFER();
       
   532 
       
   533     if (destFormat == QImage::Format_MonoLSB) {
       
   534 		image.setNumColors(2);
       
   535 		image.setColor(0, QColor(Qt::color0).rgba());
       
   536 		image.setColor(1, QColor(Qt::color1).rgba());
       
   537 	} else {
       
   538 		image.setColorTable(sourceImage.colorTable());
       
   539 	}
       
   540 }
       
   541 
       
   542 void QS60PixmapData::copy(const QPixmapData *data, const QRect &rect)
       
   543 {
       
   544     if (data->pixelType() == BitmapType) {
       
   545         QBitmap::fromImage(data->toImage().copy(rect));
       
   546         return;
       
   547     }
       
   548 
       
   549     const QS60PixmapData *s60Data = static_cast<const QS60PixmapData*>(data);
       
   550 
       
   551     resize(rect.width(), rect.height());
       
   552     cfbsBitmap->SetDisplayMode(s60Data->cfbsBitmap->DisplayMode());
       
   553 
       
   554     bitmapGc->BitBlt(TPoint(0, 0), s60Data->cfbsBitmap, qt_QRect2TRect(rect));
       
   555 }
       
   556 
       
   557 bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect)
       
   558 {
       
   559     beginDataAccess();
       
   560     bool res = QRasterPixmapData::scroll(dx, dy, rect);
       
   561     endDataAccess();
       
   562     return res;
       
   563 }
       
   564 
       
   565 int QS60PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
       
   566 {
       
   567     if (!cfbsBitmap)
       
   568         return 0;
       
   569 
       
   570     switch (metric) {
       
   571     case QPaintDevice::PdmWidth:
       
   572         return cfbsBitmap->SizeInPixels().iWidth;
       
   573     case QPaintDevice::PdmHeight:
       
   574         return cfbsBitmap->SizeInPixels().iHeight;
       
   575     case QPaintDevice::PdmWidthMM: {
       
   576         TInt twips = cfbsBitmap->SizeInTwips().iWidth;
       
   577         return (int)(twips * (25.4/KTwipsPerInch));
       
   578     }
       
   579     case QPaintDevice::PdmHeightMM: {
       
   580         TInt twips = cfbsBitmap->SizeInTwips().iHeight;
       
   581         return (int)(twips * (25.4/KTwipsPerInch));
       
   582     }
       
   583     case QPaintDevice::PdmNumColors:
       
   584         return TDisplayModeUtils::NumDisplayModeColors(cfbsBitmap->DisplayMode());
       
   585     case QPaintDevice::PdmDpiX:
       
   586     case QPaintDevice::PdmPhysicalDpiX: {
       
   587         TReal inches = cfbsBitmap->SizeInTwips().iWidth / (TReal)KTwipsPerInch;
       
   588         TInt pixels = cfbsBitmap->SizeInPixels().iWidth;
       
   589         return pixels / inches;
       
   590     }
       
   591     case QPaintDevice::PdmDpiY:
       
   592     case QPaintDevice::PdmPhysicalDpiY: {
       
   593         TReal inches = cfbsBitmap->SizeInTwips().iHeight / (TReal)KTwipsPerInch;
       
   594         TInt pixels = cfbsBitmap->SizeInPixels().iHeight;
       
   595         return pixels / inches;
       
   596     }
       
   597     case QPaintDevice::PdmDepth:
       
   598         return TDisplayModeUtils::NumDisplayModeBitsPerPixel(cfbsBitmap->DisplayMode());
       
   599     default:
       
   600         qWarning("QPixmap::metric: Invalid metric command");
       
   601     }
       
   602     return 0;
       
   603 
       
   604 }
       
   605 
       
   606 void QS60PixmapData::fill(const QColor &color)
       
   607 {
       
   608     if (color.alpha() != 255) {
       
   609         QImage im(width(), height(), QImage::Format_ARGB32_Premultiplied);
       
   610         im.fill(PREMUL(color.rgba()));
       
   611         release();
       
   612         fromImage(im, Qt::AutoColor | Qt::OrderedAlphaDither);
       
   613     } else {
       
   614         beginDataAccess();
       
   615         QRasterPixmapData::fill(color);
       
   616         endDataAccess();
       
   617     }
       
   618 }
       
   619 
       
   620 void QS60PixmapData::setMask(const QBitmap &mask)
       
   621 {
       
   622     if (mask.size().isEmpty()) {
       
   623         if (image.depth() != 1) {
       
   624             QImage newImage = image.convertToFormat(QImage::Format_RGB32);
       
   625             release();
       
   626             fromImage(newImage,  Qt::AutoColor | Qt::OrderedAlphaDither);
       
   627         }
       
   628     } else if (image.depth() == 1) {
       
   629         beginDataAccess();
       
   630         QRasterPixmapData::setMask(mask);
       
   631         endDataAccess();
       
   632     } else {
       
   633         const int w = image.width();
       
   634         const int h = image.height();
       
   635 
       
   636         const QImage imageMask = mask.toImage().convertToFormat(QImage::Format_MonoLSB);
       
   637         QImage newImage = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
       
   638         for (int y = 0; y < h; ++y) {
       
   639             const uchar *mscan = imageMask.scanLine(y);
       
   640             QRgb *tscan = (QRgb *)newImage.scanLine(y);
       
   641             for (int x = 0; x < w; ++x) {
       
   642                 if (!(mscan[x>>3] & qt_pixmap_bit_mask[x&7]))
       
   643                     tscan[x] = 0;
       
   644             }
       
   645         }
       
   646         release();
       
   647         fromImage(newImage,  Qt::AutoColor | Qt::OrderedAlphaDither);
       
   648     }
       
   649 }
       
   650 
       
   651 void QS60PixmapData::setAlphaChannel(const QPixmap &alphaChannel)
       
   652 {
       
   653     QImage img(toImage());
       
   654     img.setAlphaChannel(alphaChannel.toImage());
       
   655     release();
       
   656     fromImage(img, Qt::OrderedDither | Qt::OrderedAlphaDither);
       
   657 }
       
   658 
       
   659 QImage QS60PixmapData::toImage() const
       
   660 {
       
   661     QS60PixmapData *that = const_cast<QS60PixmapData*>(this);
       
   662     that->beginDataAccess();
       
   663     QImage copy = that->image.copy();
       
   664     that->endDataAccess();
       
   665 
       
   666     return copy;
       
   667 }
       
   668 
       
   669 QPaintEngine* QS60PixmapData::paintEngine() const
       
   670 {
       
   671     if (!pengine) {
       
   672         QS60PixmapData *that = const_cast<QS60PixmapData*>(this);
       
   673         that->pengine = new QS60PaintEngine(&that->image, that);
       
   674     }
       
   675     return pengine;
       
   676 }
       
   677 
       
   678 void QS60PixmapData::beginDataAccess()
       
   679 {
       
   680     if(!cfbsBitmap)
       
   681         return;
       
   682 
       
   683     symbianBitmapDataAccess->beginDataAccess(cfbsBitmap);
       
   684 
       
   685     uchar* newBytes = (uchar*)cfbsBitmap->DataAddress();
       
   686 
       
   687     if (newBytes == bytes)
       
   688         return;
       
   689 
       
   690 
       
   691     bytes = newBytes;
       
   692     TDisplayMode mode = cfbsBitmap->DisplayMode();
       
   693     QImage::Format format = qt_TDisplayMode2Format(mode);
       
   694     //on S60 3.1, premultiplied alpha pixels are stored in a bitmap with 16MA type
       
   695     if (format == QImage::Format_ARGB32)
       
   696         format = QImage::Format_ARGB32_Premultiplied; // pixel data is actually in premultiplied format
       
   697 
       
   698     TSize size = cfbsBitmap->SizeInPixels();
       
   699 
       
   700     QVector<QRgb> savedColorTable;
       
   701     if (!image.isNull())
       
   702         savedColorTable = image.colorTable();
       
   703 
       
   704     image = QImage(bytes, size.iWidth, size.iHeight, format);
       
   705 
       
   706     // Restore the palette or create a default
       
   707     if (!savedColorTable.isEmpty()) {
       
   708         image.setColorTable(savedColorTable);
       
   709     }
       
   710 
       
   711     w = size.iWidth;
       
   712     h = size.iHeight;
       
   713     d = image.depth();
       
   714     is_null = (w <= 0 || h <= 0);
       
   715 
       
   716     if (pengine) {
       
   717         QS60PaintEngine *engine = static_cast<QS60PaintEngine *>(pengine);
       
   718         engine->prepare(&image);
       
   719     }
       
   720 }
       
   721 
       
   722 void QS60PixmapData::endDataAccess(bool readOnly) const
       
   723 {
       
   724     Q_UNUSED(readOnly);
       
   725 
       
   726     if(!cfbsBitmap)
       
   727         return;
       
   728 
       
   729     symbianBitmapDataAccess->endDataAccess(cfbsBitmap);
       
   730 }
       
   731 
       
   732 /*!
       
   733   \since 4.6
       
   734 
       
   735   Returns a QPixmap that wraps given \a sgImage graphics resource.
       
   736   The data should be valid even when original RSgImage handle has been
       
   737   closed.
       
   738 
       
   739   \warning This function is only available on Symbian OS.
       
   740 
       
   741   \sa toSymbianRSgImage(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
       
   742 */
       
   743 
       
   744 QPixmap QPixmap::fromSymbianRSgImage(RSgImage *sgImage)
       
   745 {
       
   746     // It is expected that RSgImage will
       
   747     // CURRENTLY be used in conjuction with
       
   748     // OpenVG graphics system
       
   749     //
       
   750     // Surely things might change in future
       
   751 
       
   752     if (!sgImage)
       
   753         return QPixmap();
       
   754 
       
   755     QPixmap pixmap;
       
   756     pixmap.pixmapData()->fromNativeType(reinterpret_cast<void*>(sgImage), QPixmapData::SgImage);
       
   757 
       
   758     return pixmap;
       
   759 }
       
   760 
       
   761 /*!
       
   762 \since 4.6
       
   763 
       
   764 Returns a \c RSgImage that is equivalent to the QPixmap by copying the data.
       
   765 
       
   766 It is the caller's responsibility to close/delete the \c RSgImage after use.
       
   767 
       
   768 \warning This function is only available on Symbian OS.
       
   769 
       
   770 \sa fromSymbianRSgImage()
       
   771 */
       
   772 
       
   773 RSgImage *QPixmap::toSymbianRSgImage() const
       
   774 {
       
   775     // It is expected that RSgImage will
       
   776     // CURRENTLY be used in conjuction with
       
   777     // OpenVG graphics system
       
   778     //
       
   779     // Surely things might change in future
       
   780 
       
   781     if (isNull())
       
   782         return 0;
       
   783 
       
   784     RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmapData()->toNativeType(QPixmapData::SgImage));
       
   785 
       
   786     return sgImage;
       
   787 }
       
   788 
       
   789 void* QS60PixmapData::toNativeType(NativeType type)
       
   790 {
       
   791     if (type == QPixmapData::SgImage) {
       
   792         return 0;
       
   793     } else if (type == QPixmapData::FbsBitmap) {
       
   794 
       
   795         if (isNull() || !cfbsBitmap)
       
   796             return 0;
       
   797 
       
   798         bool convertToArgb32 = false;
       
   799         bool needsCopy = false;
       
   800 
       
   801         QSysInfo::SymbianVersion symbianVersion = QSysInfo::symbianVersion();
       
   802         if (!(S60->supportsPremultipliedAlpha)) {
       
   803             // Convert argb32_premultiplied to argb32 since Symbian 9.2 does
       
   804             // not support premultipied format.
       
   805 
       
   806             if (image.format() == QImage::Format_ARGB32_Premultiplied) {
       
   807                 needsCopy = true;
       
   808                 convertToArgb32 = true;
       
   809             }
       
   810         }
       
   811 
       
   812         CFbsBitmap *bitmap = 0;
       
   813 
       
   814         TDisplayMode displayMode = cfbsBitmap->DisplayMode();
       
   815 
       
   816         if(displayMode == EGray2) {
       
   817             //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
       
   818             //So invert mono bitmaps so that masks work correctly.
       
   819             image.invertPixels();
       
   820             needsCopy = true;
       
   821         }
       
   822 
       
   823         if (needsCopy) {
       
   824             QImage source;
       
   825 
       
   826             if (convertToArgb32) {
       
   827                 source = image.convertToFormat(QImage::Format_ARGB32);
       
   828                 displayMode = EColor16MA;
       
   829             } else {
       
   830                 source = image;
       
   831             }
       
   832 
       
   833             CFbsBitmap *newBitmap = createSymbianCFbsBitmap(TSize(source.width(), source.height()), displayMode);
       
   834             const uchar *sptr = source.bits();
       
   835             symbianBitmapDataAccess->beginDataAccess(newBitmap);
       
   836 
       
   837             uchar *dptr = (uchar*)newBitmap->DataAddress();
       
   838             Mem::Copy(dptr, sptr, source.numBytes());
       
   839 
       
   840             symbianBitmapDataAccess->endDataAccess(newBitmap);
       
   841 
       
   842             bitmap = newBitmap;
       
   843         } else {
       
   844 
       
   845             QT_TRAP_THROWING(bitmap = new (ELeave) CFbsBitmap);
       
   846 
       
   847             TInt err = bitmap->Duplicate(cfbsBitmap->Handle());
       
   848             if (err != KErrNone) {
       
   849                 qWarning("Could not duplicate CFbsBitmap");
       
   850                 delete bitmap;
       
   851                 bitmap = 0;
       
   852             }
       
   853         }
       
   854 
       
   855         if(displayMode == EGray2) {
       
   856             // restore pixels
       
   857             image.invertPixels();
       
   858         }
       
   859 
       
   860         return reinterpret_cast<void*>(bitmap);
       
   861 
       
   862     }
       
   863 
       
   864     return 0;
       
   865 }
       
   866 
       
   867 void QS60PixmapData::fromNativeType(void* pixmap, NativeType nativeType)
       
   868 {
       
   869     if (nativeType == QPixmapData::SgImage) {
       
   870         return;
       
   871     } else if (nativeType == QPixmapData::FbsBitmap && pixmap) {
       
   872 
       
   873         CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap*>(pixmap);
       
   874 
       
   875         bool deleteSourceBitmap = false;
       
   876         bool needsCopy = false;
       
   877 
       
   878 #ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE
       
   879 
       
   880         // Rasterize extended bitmaps
       
   881 
       
   882         TUid extendedBitmapType = bitmap->ExtendedBitmapType();
       
   883         if (extendedBitmapType != KNullUid) {
       
   884             CFbsBitmap *rasterBitmap = createSymbianCFbsBitmap(bitmap->SizeInPixels(), EColor16MA);
       
   885 
       
   886             CFbsBitmapDevice *rasterBitmapDev = 0;
       
   887             QT_TRAP_THROWING(rasterBitmapDev = CFbsBitmapDevice::NewL(rasterBitmap));
       
   888 
       
   889             CFbsBitGc *rasterBitmapGc = 0;
       
   890             TInt err = rasterBitmapDev->CreateContext(rasterBitmapGc);
       
   891             if (err != KErrNone) {
       
   892                 delete rasterBitmap;
       
   893                 delete rasterBitmapDev;
       
   894                 rasterBitmapDev = 0;
       
   895                 return;
       
   896             }
       
   897 
       
   898             rasterBitmapGc->BitBlt(TPoint( 0, 0), bitmap);
       
   899 
       
   900             bitmap = rasterBitmap;
       
   901 
       
   902             delete rasterBitmapDev;
       
   903             delete rasterBitmapGc;
       
   904 
       
   905             rasterBitmapDev = 0;
       
   906             rasterBitmapGc = 0;
       
   907 
       
   908             deleteSourceBitmap = true;
       
   909         }
       
   910 #endif
       
   911 
       
   912 
       
   913         deleteSourceBitmap = bitmap->IsCompressedInRAM();
       
   914         CFbsBitmap *sourceBitmap = uncompress(bitmap);
       
   915 
       
   916         TDisplayMode displayMode = sourceBitmap->DisplayMode();
       
   917         QImage::Format format = qt_TDisplayMode2Format(displayMode);
       
   918 
       
   919         QImage::Format opaqueFormat = QNativeImage::systemFormat();
       
   920         QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied;
       
   921 
       
   922         if (format != opaqueFormat && format != alphaFormat && format != QImage::Format_MonoLSB)
       
   923             needsCopy = true;
       
   924 
       
   925 
       
   926         type = (format != QImage::Format_MonoLSB)
       
   927                     ? QPixmapData::PixmapType
       
   928                     : QPixmapData::BitmapType;
       
   929 
       
   930         if (needsCopy) {
       
   931 
       
   932             TSize size = sourceBitmap->SizeInPixels();
       
   933 
       
   934             QSymbianBitmapDataAccess da;
       
   935             da.beginDataAccess(sourceBitmap);
       
   936             uchar *bytes = (uchar*)sourceBitmap->DataAddress();
       
   937             QImage img = QImage(bytes, size.iWidth, size.iHeight, format);
       
   938             da.endDataAccess(sourceBitmap);
       
   939 
       
   940             fromImage(img, Qt::AutoColor);
       
   941 
       
   942             if(deleteSourceBitmap)
       
   943                 delete sourceBitmap;
       
   944 
       
   945             if(displayMode == EGray2) {
       
   946                 //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid
       
   947                 //So invert mono bitmaps so that masks work correctly.
       
   948                 image.invertPixels();
       
   949             }
       
   950         } else {
       
   951             CFbsBitmap* duplicate = 0;
       
   952             QT_TRAP_THROWING(duplicate = new (ELeave) CFbsBitmap);
       
   953 
       
   954             TInt err = duplicate->Duplicate(sourceBitmap->Handle());
       
   955             if (err != KErrNone) {
       
   956                 qWarning("Could not duplicate CFbsBitmap");
       
   957 
       
   958                 if(deleteSourceBitmap)
       
   959                     delete sourceBitmap;
       
   960 
       
   961                 delete duplicate;
       
   962                 return;
       
   963             }
       
   964 
       
   965             fromSymbianBitmap(duplicate);
       
   966 
       
   967             if(deleteSourceBitmap)
       
   968                 delete sourceBitmap;
       
   969         }
       
   970     }
       
   971 }
       
   972 
       
   973 QT_END_NAMESPACE