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
42
#include "qpixmap.h"
43
44
#include "qpixmap_raster_p.h"
45
#include "qnativeimage_p.h"
46
#include "qimage_p.h"
47
48
#include "qbitmap.h"
49
#include "qimage.h"
50
#include <private/qwidget_p.h>
51
#include <private/qdrawhelper_p.h>
52
53
QT_BEGIN_NAMESPACE
54
55
const uchar qt_pixmap_bit_mask[] = { 0x01, 0x02, 0x04, 0x08,
56
                                     0x10, 0x20, 0x40, 0x80 };
57
58
QPixmap qt_toRasterPixmap(const QImage &image)
59
{
60
    QPixmapData *data =
61
        new QRasterPixmapData(image.depth() == 1
62
                           ? QPixmapData::BitmapType
63
                           : QPixmapData::PixmapType);
64
65
    data->fromImage(image, Qt::AutoColor);
66
67
    return QPixmap(data);
68
}
69
70
QPixmap qt_toRasterPixmap(const QPixmap &pixmap)
71
{
72
    if (pixmap.isNull())
73
        return QPixmap();
74
75
    if (QPixmap(pixmap).data_ptr()->classId() == QPixmapData::RasterClass)
76
        return pixmap;
77
78
    return qt_toRasterPixmap(pixmap.toImage());
79
}
80
81
QRasterPixmapData::QRasterPixmapData(PixelType type)
82
    : QPixmapData(type, RasterClass)
83
{
84
}
85
86
QRasterPixmapData::~QRasterPixmapData()
87
{
88
}
89
90
QPixmapData *QRasterPixmapData::createCompatiblePixmapData() const
91
{
92
    return new QRasterPixmapData(pixelType());
93
}
94
95
void QRasterPixmapData::resize(int width, int height)
96
{
97
    QImage::Format format;
98
#ifdef Q_WS_QWS
99
    if (pixelType() == BitmapType) {
100
        format = QImage::Format_Mono;
101
    } else {
102
        format = QScreen::instance()->pixelFormat();
103
        if (format == QImage::Format_Invalid)
104
            format = QImage::Format_ARGB32_Premultiplied;
105
        else if (format == QImage::Format_Indexed8) // currently not supported
106
            format = QImage::Format_RGB444;
107
    }
108
#else
109
    if (pixelType() == BitmapType)
110
        format = QImage::Format_MonoLSB;
111
    else
112
        format = QNativeImage::systemFormat();
113
#endif
114
115
    image = QImage(width, height, format);
116
    w = width;
117
    h = height;
118
    d = image.depth();
119
    is_null = (w <= 0 || h <= 0);
120
121
    if (pixelType() == BitmapType && !image.isNull()) {
122
        image.setColorCount(2);
123
        image.setColor(0, QColor(Qt::color0).rgba());
124
        image.setColor(1, QColor(Qt::color1).rgba());
125
    }
126
127
    setSerialNumber(image.serialNumber());
128
}
129
130
void QRasterPixmapData::fromImage(const QImage &sourceImage,
131
                                  Qt::ImageConversionFlags flags)
132
{
133
    Q_UNUSED(flags);
134
135
#ifdef Q_WS_QWS
136
    QImage::Format format;
137
    if (pixelType() == BitmapType) {
138
        format = QImage::Format_Mono;
139
    } else {
140
        format = QScreen::instance()->pixelFormat();
141
        if (format == QImage::Format_Invalid)
142
            format = QImage::Format_ARGB32_Premultiplied;
143
        else if (format == QImage::Format_Indexed8) // currently not supported
144
            format = QImage::Format_RGB444;
145
    }
146
147
    if (sourceImage.hasAlphaChannel()
148
        && ((flags & Qt::NoOpaqueDetection)
149
            || const_cast<QImage &>(sourceImage).data_ptr()->checkForAlphaPixels())) {
150
        switch (format) {
151
            case QImage::Format_RGB16:
152
                format = QImage::Format_ARGB8565_Premultiplied;
153
                break;
154
            case QImage::Format_RGB666:
155
                format = QImage::Format_ARGB6666_Premultiplied;
156
                break;
157
            case QImage::Format_RGB555:
158
                format = QImage::Format_ARGB8555_Premultiplied;
159
                break;
160
            case QImage::Format_RGB444:
161
                format = QImage::Format_ARGB4444_Premultiplied;
162
                break;
163
            default:
164
                format = QImage::Format_ARGB32_Premultiplied;
165
                break;
166
        }
167
    } else if (format == QImage::Format_Invalid) {
168
        format = QImage::Format_ARGB32_Premultiplied;
169
    }
170
171
    image = sourceImage.convertToFormat(format);
172
#else
173
    if (pixelType() == BitmapType) {
174
        image = sourceImage.convertToFormat(QImage::Format_MonoLSB);
175
    } else {
176
        if (sourceImage.depth() == 1) {
177
            image = sourceImage.hasAlphaChannel()
178
                    ? sourceImage.convertToFormat(QImage::Format_ARGB32_Premultiplied)
179
                    : sourceImage.convertToFormat(QImage::Format_RGB32);
180
        } else {
181
182
            QImage::Format opaqueFormat = QNativeImage::systemFormat();
183
            QImage::Format alphaFormat = QImage::Format_ARGB32_Premultiplied;
184
185
            switch (opaqueFormat) {
186
            case QImage::Format_RGB16:
187
                alphaFormat = QImage::Format_ARGB8565_Premultiplied;
188
                break;
189
            default: // We don't care about the others...
190
                break;
191
            }
192
193
            if (!sourceImage.hasAlphaChannel()
194
                || ((flags & Qt::NoOpaqueDetection) == 0
195
                    && !const_cast<QImage &>(sourceImage).data_ptr()->checkForAlphaPixels())) {
196
                image = sourceImage.convertToFormat(opaqueFormat);
197
            } else {
198
                image = sourceImage.convertToFormat(alphaFormat);
199
            }
200
        }
201
    }
202
#endif
203
    if (image.d) {
204
        w = image.d->width;
205
        h = image.d->height;
206
        d = image.d->depth;
207
    } else {
208
        w = h = d = 0;
209
    }
210
    is_null = (w <= 0 || h <= 0);
211
212
    setSerialNumber(image.serialNumber());
213
}
214
215
// from qwindowsurface.cpp
216
extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
217
218
bool QRasterPixmapData::scroll(int dx, int dy, const QRect &rect)
219
{
220
    if (!image.isNull())
221
        qt_scrollRectInImage(image, rect, QPoint(dx, dy));
222
    return true;
223
}
224
225
void QRasterPixmapData::fill(const QColor &color)
226
{
227
    uint pixel;
228
229
    if (image.depth() == 1) {
230
        int gray = qGray(color.rgba());
231
        // Pick the best approximate color in the image's colortable.
232
        if (qAbs(qGray(image.color(0)) - gray) < qAbs(qGray(image.color(1)) - gray))
233
            pixel = 0;
234
        else
235
            pixel = 1;
236
    } else if (image.depth() >= 15) {
237
        int alpha = color.alpha();
238
        if (alpha != 255) {
239
            if (!image.hasAlphaChannel()) {
240
                QImage::Format toFormat;
241
                if (image.format() == QImage::Format_RGB16)
242
                    toFormat = QImage::Format_ARGB8565_Premultiplied;
243
                else if (image.format() == QImage::Format_RGB666)
244
                    toFormat = QImage::Format_ARGB6666_Premultiplied;
245
                else if (image.format() == QImage::Format_RGB555)
246
                    toFormat = QImage::Format_ARGB8555_Premultiplied;
247
                else if (image.format() == QImage::Format_RGB444)
248
                    toFormat = QImage::Format_ARGB4444_Premultiplied;
249
                else
250
                    toFormat = QImage::Format_ARGB32_Premultiplied;
251
                image = QImage(image.width(), image.height(), toFormat);
252
            }
253
254
            switch (image.format()) {
255
            case QImage::Format_ARGB8565_Premultiplied:
256
                pixel = qargb8565(color.rgba()).rawValue();
257
                break;
258
            case QImage::Format_ARGB8555_Premultiplied:
259
                pixel = qargb8555(color.rgba()).rawValue();
260
                break;
261
            case QImage::Format_ARGB6666_Premultiplied:
262
                pixel = qargb6666(color.rgba()).rawValue();
263
                break;
264
            case QImage::Format_ARGB4444_Premultiplied:
265
                pixel = qargb4444(color.rgba()).rawValue();
266
                break;
267
            default:
268
                pixel = PREMUL(color.rgba());
269
                break;
270
            }
271
        } else {
272
            switch (image.format()) {
273
            case QImage::Format_RGB16:
274
                pixel = qt_colorConvert<quint16, quint32>(color.rgba(), 0);
275
                break;
276
            case QImage::Format_RGB444:
277
                pixel = qrgb444(color.rgba()).rawValue();
278
                break;
279
            case QImage::Format_RGB555:
280
                pixel = qrgb555(color.rgba()).rawValue();
281
                break;
282
            case QImage::Format_RGB666:
283
                pixel = qrgb666(color.rgba()).rawValue();
284
                break;
285
            case QImage::Format_RGB888:
286
                pixel = qrgb888(color.rgba()).rawValue();
287
                break;
288
            default:
289
                pixel = color.rgba();
290
                break;
291
            }
292
        }
293
    } else {
294
        pixel = 0;
295
        // ### what about 8 bits
296
    }
297
298
    image.fill(pixel);
299
}
300
301
void QRasterPixmapData::setMask(const QBitmap &mask)
302
{
303
    if (mask.size().isEmpty()) {
304
        if (image.depth() != 1) { // hw: ????
305
            image = image.convertToFormat(QImage::Format_RGB32);
306
        }
307
    } else {
308
        const int w = image.width();
309
        const int h = image.height();
310
311
        switch (image.depth()) {
312
        case 1: {
313
            const QImage imageMask = mask.toImage().convertToFormat(image.format());
314
            for (int y = 0; y < h; ++y) {
315
                const uchar *mscan = imageMask.scanLine(y);
316
                uchar *tscan = image.scanLine(y);
317
                int bytesPerLine = image.bytesPerLine();
318
                for (int i = 0; i < bytesPerLine; ++i)
319
                    tscan[i] &= mscan[i];
320
            }
321
            break;
322
        }
323
        default: {
324
            const QImage imageMask = mask.toImage().convertToFormat(QImage::Format_MonoLSB);
325
            image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
326
            for (int y = 0; y < h; ++y) {
327
                const uchar *mscan = imageMask.scanLine(y);
328
                QRgb *tscan = (QRgb *)image.scanLine(y);
329
                for (int x = 0; x < w; ++x) {
330
                    if (!(mscan[x>>3] & qt_pixmap_bit_mask[x&7]))
331
                        tscan[x] = 0;
332
                }
333
            }
334
            break;
335
        }
336
        }
337
    }
338
}
339
340
bool QRasterPixmapData::hasAlphaChannel() const
341
{
342
    return image.hasAlphaChannel();
343
}
344
345
QImage QRasterPixmapData::toImage() const
346
{
347
    return image;
348
}
349
350
void QRasterPixmapData::setAlphaChannel(const QPixmap &alphaChannel)
351
{
352
    image.setAlphaChannel(alphaChannel.toImage());
353
}
354
355
QPaintEngine* QRasterPixmapData::paintEngine() const
356
{
357
    return image.paintEngine();
358
}
359
360
Q_GUI_EXPORT extern int qt_defaultDpiX();
361
Q_GUI_EXPORT extern int qt_defaultDpiY();
362
363
int QRasterPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const
364
{
365
    QImageData *d = image.d;
366
    if (!d)
367
        return 0;
368
369
    // override the image dpi with the screen dpi when rendering to a pixmap
370
    switch (metric) {
371
    case QPaintDevice::PdmWidth:
372
        return w;
373
    case QPaintDevice::PdmHeight:
374
        return h;
375
    case QPaintDevice::PdmWidthMM:
376
        return qRound(d->width * 25.4 / qt_defaultDpiX());
377
    case QPaintDevice::PdmHeightMM:
378
        return qRound(d->height * 25.4 / qt_defaultDpiY());
379
    case QPaintDevice::PdmNumColors:
380
        return d->colortable.size();
381
    case QPaintDevice::PdmDepth:
382
        return this->d;
383
    case QPaintDevice::PdmDpiX: // fall-through
384
    case QPaintDevice::PdmPhysicalDpiX:
385
        return qt_defaultDpiX();
386
    case QPaintDevice::PdmDpiY: // fall-through
387
    case QPaintDevice::PdmPhysicalDpiY:
388
        return qt_defaultDpiY();
389
    default:
390
        qWarning("QRasterPixmapData::metric(): Unhandled metric type %d", metric);
391
        break;
392
    }
393
394
    return 0;
395
}
396
397
QImage* QRasterPixmapData::buffer()
398
{
399
    return &image;
400
}
401
402
QT_END_NAMESPACE