1
/****************************************************************************
2
**
3
** Copyright (C) 2011 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