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
#include "qimage.h"
44
#include "qapplication.h"
45
#include "qbitmap.h"
46
#include "qmatrix.h"
47
#include "qtransform.h"
48
#include "qlibrary.h"
49
#include "qvarlengtharray.h"
50
#include "qdebug.h"
51
#include <private/qdrawhelper_p.h>
52
#include <private/qpixmap_mac_p.h>
53
#include <private/qpixmap_raster_p.h>
54
#include <private/qpaintengine_mac_p.h>
55
#include <private/qt_mac_p.h>
56
#include <private/qt_cocoa_helpers_mac_p.h>
57
58
#include <limits.h>
59
#include <string.h>
60
61
QT_BEGIN_NAMESPACE
62
63
/*****************************************************************************
64
  Externals
65
 *****************************************************************************/
66
extern const uchar *qt_get_bitflip_array(); //qimage.cpp
67
extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); //qpaintdevice_mac.cpp
68
extern RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp
69
extern void qt_mac_dispose_rgn(RgnHandle r); //qregion_mac.cpp
70
extern QRegion qt_mac_convert_mac_region(RgnHandle rgn); //qregion_mac.cpp
71
72
static int qt_pixmap_serial = 0;
73
74
Q_GUI_EXPORT quint32 *qt_mac_pixmap_get_base(const QPixmap *pix)
75
{
76
    return static_cast<QMacPixmapData*>(pix->data.data())->pixels;
77
}
78
79
Q_GUI_EXPORT int qt_mac_pixmap_get_bytes_per_line(const QPixmap *pix)
80
{
81
    return static_cast<QMacPixmapData*>(pix->data.data())->bytesPerRow;
82
}
83
84
void qt_mac_cgimage_data_free(void *info, const void *memoryToFree, size_t)
85
{
86
    QMacPixmapData *pmdata = static_cast<QMacPixmapData *>(info);
87
    if (!pmdata) {
88
        free(const_cast<void *>(memoryToFree));
89
    } else {
90
        if (QMacPixmapData::validDataPointers.contains(pmdata) == false) {
91
            free(const_cast<void *>(memoryToFree));
92
            return;
93
        }
94
        if (pmdata->pixels == pmdata->pixelsToFree) {
95
            // something we aren't expecting, just free it.
96
            Q_ASSERT(memoryToFree != pmdata->pixelsToFree);
97
            free(const_cast<void *>(memoryToFree));
98
        } else {
99
            free(pmdata->pixelsToFree);
100
            pmdata->pixelsToFree = static_cast<quint32 *>(const_cast<void *>(memoryToFree));
101
        }
102
        pmdata->cg_dataBeingReleased = 0;
103
    }
104
}
105
106
CGImageRef qt_mac_image_to_cgimage(const QImage &image)
107
{
108
    int bitsPerColor = 8;
109
    int bitsPerPixel = 32;
110
    if (image.depth() == 1) {
111
        bitsPerColor = 1;
112
        bitsPerPixel = 1;
113
    }
114
    QCFType<CGDataProviderRef> provider =
115
        CGDataProviderCreateWithData(0, image.bits(), image.bytesPerLine() * image.height(),
116
                                     0);
117
118
    uint cgflags = kCGImageAlphaPremultipliedFirst;
119
#ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version
120
    cgflags |= kCGBitmapByteOrder32Host;
121
#endif
122
123
    CGImageRef cgImage = CGImageCreate(image.width(), image.height(), bitsPerColor, bitsPerPixel,
124
                                       image.bytesPerLine(),
125
                                       QCoreGraphicsPaintEngine::macGenericColorSpace(),
126
                                       cgflags, provider,
127
                                       0,
128
                                       0,
129
                                       kCGRenderingIntentDefault);
130
131
    return cgImage;
132
}
133
134
/*****************************************************************************
135
  QPixmap member functions
136
 *****************************************************************************/
137
138
static inline QRgb qt_conv16ToRgb(ushort c) {
139
    static const int qt_rbits = (565/100);
140
    static const int qt_gbits = (565/10%10);
141
    static const int qt_bbits = (565%10);
142
    static const int qt_red_shift = qt_bbits+qt_gbits-(8-qt_rbits);
143
    static const int qt_green_shift = qt_bbits-(8-qt_gbits);
144
    static const int qt_neg_blue_shift = 8-qt_bbits;
145
    static const int qt_blue_mask = (1<<qt_bbits)-1;
146
    static const int qt_green_mask = (1<<(qt_gbits+qt_bbits))-((1<<qt_bbits)-1);
147
    static const int qt_red_mask = (1<<(qt_rbits+qt_gbits+qt_bbits))-(1<<(qt_gbits+qt_bbits));
148
149
    const int r=(c & qt_red_mask);
150
    const int g=(c & qt_green_mask);
151
    const int b=(c & qt_blue_mask);
152
    const int tr = r >> qt_red_shift;
153
    const int tg = g >> qt_green_shift;
154
    const int tb = b << qt_neg_blue_shift;
155
156
    return qRgb(tr,tg,tb);
157
}
158
159
QSet<QMacPixmapData*> QMacPixmapData::validDataPointers;
160
161
QMacPixmapData::QMacPixmapData(PixelType type)
162
    : QPixmapData(type, MacClass), has_alpha(0), has_mask(0),
163
      uninit(true), pixels(0), pixelsSize(0), pixelsToFree(0),
164
      bytesPerRow(0), cg_data(0), cg_dataBeingReleased(0), cg_mask(0),
165
      pengine(0)
166
{
167
}
168
169
QPixmapData *QMacPixmapData::createCompatiblePixmapData() const
170
{
171
    return new QMacPixmapData(pixelType());
172
}
173
174
#define BEST_BYTE_ALIGNMENT 16
175
#define COMPTUE_BEST_BYTES_PER_ROW(bpr) \
176
    (((bpr) + (BEST_BYTE_ALIGNMENT - 1)) & ~(BEST_BYTE_ALIGNMENT - 1))
177
178
void QMacPixmapData::resize(int width, int height)
179
{
180
    setSerialNumber(++qt_pixmap_serial);
181
182
    w = width;
183
    h = height;
184
    is_null = (w <= 0 || h <= 0);
185
    d = (pixelType() == BitmapType ? 1 : 32);
186
    bool make_null = w <= 0 || h <= 0;                // create null pixmap
187
    if (make_null || d == 0) {
188
        w = 0;
189
        h = 0;
190
        is_null = true;
191
        d = 0;
192
        if (!make_null)
193
            qWarning("Qt: QPixmap: Invalid pixmap parameters");
194
        return;
195
    }
196
197
    if (w < 1 || h < 1)
198
        return;
199
200
    //create the pixels
201
    bytesPerRow = w * sizeof(quint32);  // Minimum bytes per row.
202
203
    // Quartz2D likes things as a multple of 16 (for now).
204
    bytesPerRow = COMPTUE_BEST_BYTES_PER_ROW(bytesPerRow);
205
    macCreatePixels();
206
}
207
208
#undef COMPUTE_BEST_BYTES_PER_ROW
209
210
void QMacPixmapData::fromImage(const QImage &img,
211
                               Qt::ImageConversionFlags flags)
212
{
213
    setSerialNumber(++qt_pixmap_serial);
214
215
    // the conversion code only handles format >=
216
    // Format_ARGB32_Premultiplied at the moment..
217
    if (img.format() > QImage::Format_ARGB32_Premultiplied) {
218
        QImage image;
219
        if (img.hasAlphaChannel())
220
            image = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
221
        else
222
            image = img.convertToFormat(QImage::Format_RGB32);
223
        fromImage(image, flags);
224
        return;
225
    }
226
227
    w = img.width();
228
    h = img.height();
229
    is_null = (w <= 0 || h <= 0);
230
    d = (pixelType() == BitmapType ? 1 : img.depth());
231
232
    QImage image = img;
233
    int dd = QPixmap::defaultDepth();
234
    bool force_mono = (dd == 1 ||
235
                       (flags & Qt::ColorMode_Mask)==Qt::MonoOnly);
236
    if (force_mono) {                         // must be monochrome
237
        if (d != 1) {
238
            image = image.convertToFormat(QImage::Format_MonoLSB, flags);  // dither
239
            d = 1;
240
        }
241
    } else {                                    // can be both
242
        bool conv8 = false;
243
        if(d > 8 && dd <= 8) {               // convert to 8 bit
244
            if ((flags & Qt::DitherMode_Mask) == Qt::AutoDither)
245
                flags = (flags & ~Qt::DitherMode_Mask)
246
                                   | Qt::PreferDither;
247
            conv8 = true;
248
        } else if ((flags & Qt::ColorMode_Mask) == Qt::ColorOnly) {
249
            conv8 = d == 1;                     // native depth wanted
250
        } else if (d == 1) {
251
            if (image.colorCount() == 2) {
252
                QRgb c0 = image.color(0);       // Auto: convert to best
253
                QRgb c1 = image.color(1);
254
                conv8 = qMin(c0,c1) != qRgb(0,0,0) || qMax(c0,c1) != qRgb(255,255,255);
255
            } else {
256
                // eg. 1-color monochrome images (they do exist).
257
                conv8 = true;
258
            }
259
        }
260
        if (conv8) {
261
            image = image.convertToFormat(QImage::Format_Indexed8, flags);
262
            d = 8;
263
        }
264
    }
265
266
    if (image.depth()==1) {
267
        image.setColor(0, QColor(Qt::color0).rgba());
268
        image.setColor(1, QColor(Qt::color1).rgba());
269
    }
270
271
    if (d == 16 || d == 24) {
272
        image = image.convertToFormat(QImage::Format_RGB32, flags);
273
        fromImage(image, flags);
274
        return;
275
    }
276
277
    // different size or depth, make a new pixmap
278
    resize(w, h);
279
280
    quint32 *dptr = pixels, *drow;
281
    const uint dbpr = bytesPerRow;
282
283
    const QImage::Format sfmt = image.format();
284
    const unsigned short sbpr = image.bytesPerLine();
285
286
    // use const_cast to prevent a detach
287
    const uchar *sptr = const_cast<const QImage &>(image).bits(), *srow;
288
289
    for (int y = 0; y < h; ++y) {
290
        drow = dptr + (y * (dbpr / 4));
291
        srow = sptr + (y * sbpr);
292
        switch(sfmt) {
293
        case QImage::Format_MonoLSB:
294
        case QImage::Format_Mono:{
295
            for (int x = 0; x < w; ++x) {
296
                char one_bit = *(srow + (x / 8));
297
                if (sfmt == QImage::Format_Mono)
298
                    one_bit = one_bit >> (7 - (x % 8));
299
                else
300
                    one_bit = one_bit >> (x % 8);
301
                if ((one_bit & 0x01))
302
                    *(drow+x) = 0xFF000000;
303
                else
304
                    *(drow+x) = 0xFFFFFFFF;
305
            }
306
            break;
307
        }
308
        case QImage::Format_Indexed8: {
309
            int numColors = image.numColors();
310
            if (numColors > 0) {
311
                for (int x = 0; x < w; ++x) {
312
                    int index = *(srow + x);
313
                    *(drow+x) = PREMUL(image.color(qMin(index, numColors)));
314
                }
315
            }
316
        } break;
317
        case QImage::Format_RGB32:
318
            for (int x = 0; x < w; ++x)
319
                *(drow+x) = *(((quint32*)srow) + x) | 0xFF000000;
320
            break;
321
        case QImage::Format_ARGB32:
322
        case QImage::Format_ARGB32_Premultiplied:
323
            for (int x = 0; x < w; ++x) {
324
                if(sfmt == QImage::Format_RGB32)
325
                    *(drow+x) = 0xFF000000 | (*(((quint32*)srow) + x) & 0x00FFFFFF);
326
                else if(sfmt == QImage::Format_ARGB32_Premultiplied)
327
                    *(drow+x) = *(((quint32*)srow) + x);
328
                else
329
                    *(drow+x) = PREMUL(*(((quint32*)srow) + x));
330
            }
331
            break;
332
        default:
333
            qWarning("Qt: internal: Oops: Forgot a format [%d] %s:%d", sfmt,
334
                     __FILE__, __LINE__);
335
            break;
336
        }
337
    }
338
    if (sfmt != QImage::Format_RGB32) { //setup the alpha
339
        bool alphamap = image.depth() == 32;
340
        if (sfmt == QImage::Format_Indexed8) {
341
            const QVector<QRgb> rgb = image.colorTable();
342
            for (int i = 0, count = image.colorCount(); i < count; ++i) {
343
                const int alpha = qAlpha(rgb[i]);
344
                if (alpha != 0xff) {
345
                    alphamap = true;
346
                    break;
347
                }
348
            }
349
        }
350
        macSetHasAlpha(alphamap);
351
    }
352
    uninit = false;
353
}
354
355
int get_index(QImage * qi,QRgb mycol)
356
{
357
    int loopc;
358
    for(loopc=0;loopc<qi->colorCount();loopc++) {
359
        if(qi->color(loopc)==mycol)
360
            return loopc;
361
    }
362
    qi->setColorCount(qi->colorCount()+1);
363
    qi->setColor(qi->colorCount(),mycol);
364
    return qi->colorCount();
365
}
366
367
QImage QMacPixmapData::toImage() const
368
{
369
    QImage::Format format = QImage::Format_MonoLSB;
370
    if (d != 1) //Doesn't support index color modes
371
        format = (has_alpha ? QImage::Format_ARGB32_Premultiplied :
372
                  QImage::Format_RGB32);
373
374
    QImage image(w, h, format);
375
    quint32 *sptr = pixels, *srow;
376
    const uint sbpr = bytesPerRow;
377
    if (format == QImage::Format_MonoLSB) {
378
        image.fill(0);
379
        image.setColorCount(2);
380
        image.setColor(0, QColor(Qt::color0).rgba());
381
        image.setColor(1, QColor(Qt::color1).rgba());
382
        for (int y = 0; y < h; ++y) {
383
            uchar *scanLine = image.scanLine(y);
384
            srow = sptr + (y * (sbpr/4));
385
            for (int x = 0; x < w; ++x) {
386
                if (!(*(srow + x) & RGB_MASK))
387
                    scanLine[x >> 3] |= (1 << (x & 7));
388
            }
389
        }
390
    } else {
391
        for (int y = 0; y < h; ++y) {
392
            srow = sptr + (y * (sbpr / 4));
393
            memcpy(image.scanLine(y), srow, w * 4);
394
        }
395
396
    }
397
398
    return image;
399
}
400
401
void QMacPixmapData::fill(const QColor &fillColor)
402
403
{
404
    { //we don't know what backend to use so we cannot paint here
405
        quint32 *dptr = pixels;
406
        Q_ASSERT_X(dptr, "QPixmap::fill", "No dptr");
407
        const quint32 colr = PREMUL(fillColor.rgba());
408
        const int nbytes = bytesPerRow * h;
409
        if (!colr) {
410
            memset(dptr, 0, nbytes);
411
        } else {
412
            for (uint i = 0; i < nbytes / sizeof(quint32); ++i)
413
                *(dptr + i) = colr;
414
        }
415
    }
416
    macSetHasAlpha(fillColor.alpha() != 255);
417
}
418
419
QPixmap QMacPixmapData::alphaChannel() const
420
{
421
    if (!has_alpha)
422
        return QPixmap();
423
424
    QMacPixmapData *alpha = new QMacPixmapData(PixmapType);
425
    alpha->resize(w, h);
426
    macGetAlphaChannel(alpha, false);
427
    return QPixmap(alpha);
428
}
429
430
void QMacPixmapData::setAlphaChannel(const QPixmap &alpha)
431
{
432
    has_mask = true;
433
    QMacPixmapData *alphaData = static_cast<QMacPixmapData*>(alpha.data.data());
434
    macSetAlphaChannel(alphaData, false);
435
}
436
437
QBitmap QMacPixmapData::mask() const
438
{
439
    if (!has_mask && !has_alpha)
440
        return QBitmap();
441
442
    QMacPixmapData *mask = new QMacPixmapData(BitmapType);
443
    mask->resize(w, h);
444
    macGetAlphaChannel(mask, true);
445
    return QPixmap(mask);
446
}
447
448
void QMacPixmapData::setMask(const QBitmap &mask)
449
{
450
    if (mask.isNull()) {
451
        QMacPixmapData opaque(PixmapType);
452
        opaque.resize(w, h);
453
        opaque.fill(QColor(255, 255, 255, 255));
454
        macSetAlphaChannel(&opaque, true);
455
        has_alpha = has_mask = false;
456
        return;
457
    }
458
459
    has_alpha = false;
460
    has_mask = true;
461
    QMacPixmapData *maskData = static_cast<QMacPixmapData*>(mask.data.data());
462
    macSetAlphaChannel(maskData, true);
463
}
464
465
int QMacPixmapData::metric(QPaintDevice::PaintDeviceMetric theMetric) const
466
{
467
    switch (theMetric) {
468
    case QPaintDevice::PdmWidth:
469
        return w;
470
    case QPaintDevice::PdmHeight:
471
        return h;
472
    case QPaintDevice::PdmWidthMM:
473
        return qRound(metric(QPaintDevice::PdmWidth) * 25.4 / qreal(metric(QPaintDevice::PdmDpiX)));
474
    case QPaintDevice::PdmHeightMM:
475
        return qRound(metric(QPaintDevice::PdmHeight) * 25.4 / qreal(metric(QPaintDevice::PdmDpiY)));
476
    case QPaintDevice::PdmNumColors:
477
        return 1 << d;
478
    case QPaintDevice::PdmDpiX:
479
    case QPaintDevice::PdmPhysicalDpiX: {
480
        extern float qt_mac_defaultDpi_x(); //qpaintdevice_mac.cpp
481
        return int(qt_mac_defaultDpi_x());
482
    }
483
    case QPaintDevice::PdmDpiY:
484
    case QPaintDevice::PdmPhysicalDpiY: {
485
        extern float qt_mac_defaultDpi_y(); //qpaintdevice_mac.cpp
486
        return int(qt_mac_defaultDpi_y());
487
    }
488
    case QPaintDevice::PdmDepth:
489
        return d;
490
    default:
491
        qWarning("QPixmap::metric: Invalid metric command");
492
    }
493
    return 0;
494
}
495
496
QMacPixmapData::~QMacPixmapData()
497
{
498
    validDataPointers.remove(this);
499
    if (cg_mask) {
500
        CGImageRelease(cg_mask);
501
        cg_mask = 0;
502
    }
503
504
    delete pengine;  // Make sure we aren't drawing on the context anymore.
505
    if (cg_data) {
506
        CGImageRelease(cg_data);
507
    } else if (!cg_dataBeingReleased && pixels != pixelsToFree) {
508
        free(pixels);
509
    }
510
    free(pixelsToFree);
511
}
512
513
void QMacPixmapData::macSetAlphaChannel(const QMacPixmapData *pix, bool asMask)
514
{
515
    if (!pixels || !h || !w || pix->w != w || pix->h != h)
516
        return;
517
518
    quint32 *dptr = pixels, *drow;
519
    const uint dbpr = bytesPerRow;
520
    const unsigned short sbpr = pix->bytesPerRow;
521
    quint32 *sptr = pix->pixels, *srow;
522
    for (int y=0; y < h; ++y) {
523
        drow = dptr + (y * (dbpr/4));
524
        srow = sptr + (y * (sbpr/4));
525
        if(d == 1) {
526
            for (int x=0; x < w; ++x) {
527
                if((*(srow+x) & RGB_MASK))
528
                    *(drow+x) = 0xFFFFFFFF;
529
            }
530
        } else if(d == 8) {
531
            for (int x=0; x < w; ++x)
532
                *(drow+x) = (*(drow+x) & RGB_MASK) | (*(srow+x) << 24);
533
        } else if(asMask) {
534
            for (int x=0; x < w; ++x) {
535
                if(*(srow+x) & RGB_MASK)
536
                    *(drow+x) = (*(drow+x) & RGB_MASK);
537
                else
538
                    *(drow+x) = (*(drow+x) & RGB_MASK) | 0xFF000000;
539
                *(drow+x) = PREMUL(*(drow+x));
540
            }
541
        } else {
542
            for (int x=0; x < w; ++x) {
543
                const uchar alpha = qGray(qRed(*(srow+x)), qGreen(*(srow+x)), qBlue(*(srow+x)));
544
                const uchar destAlpha = qt_div_255(alpha * qAlpha(*(drow+x)));
545
#if 1
546
                *(drow+x) = (*(drow+x) & RGB_MASK) | (destAlpha << 24);
547
#else
548
                *(drow+x) = qRgba(qt_div_255(qRed(*(drow+x) * alpha)),
549
                                  qt_div_255(qGreen(*(drow+x) * alpha)),
550
                                  qt_div_255(qBlue(*(drow+x) * alpha)), destAlpha);
551
#endif
552
                *(drow+x) = PREMUL(*(drow+x));
553
            }
554
        }
555
    }
556
    macSetHasAlpha(true);
557
}
558
559
void QMacPixmapData::macGetAlphaChannel(QMacPixmapData *pix, bool asMask) const
560
{
561
    quint32 *dptr = pix->pixels, *drow;
562
    const uint dbpr = pix->bytesPerRow;
563
    const unsigned short sbpr = bytesPerRow;
564
    quint32 *sptr = pixels, *srow;
565
    for(int y=0; y < h; ++y) {
566
        drow = dptr + (y * (dbpr/4));
567
        srow = sptr + (y * (sbpr/4));
568
        if(asMask) {
569
            for (int x = 0; x < w; ++x) {
570
                if (*(srow + x) & qRgba(0, 0, 0, 255))
571
                    *(drow + x) = 0x00000000;
572
                else
573
                    *(drow + x) = 0xFFFFFFFF;
574
            }
575
        } else {
576
            for (int x = 0; x < w; ++x) {
577
                const int alpha = qAlpha(*(srow + x));
578
                *(drow + x) = qRgb(alpha, alpha, alpha);
579
            }
580
        }
581
    }
582
}
583
584
void QMacPixmapData::macSetHasAlpha(bool b)
585
{
586
    has_alpha = b;
587
    macReleaseCGImageRef();
588
}
589
590
void QMacPixmapData::macCreateCGImageRef()
591
{
592
    Q_ASSERT(cg_data == 0);
593
    //create the cg data
594
    CGColorSpaceRef colorspace = QCoreGraphicsPaintEngine::macDisplayColorSpace();
595
    QCFType<CGDataProviderRef> provider = CGDataProviderCreateWithData(this,
596
                                                              pixels, bytesPerRow * h,
597
                                                              qt_mac_cgimage_data_free);
598
    validDataPointers.insert(this);
599
    uint cgflags = kCGImageAlphaPremultipliedFirst;
600
#ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version
601
    cgflags |= kCGBitmapByteOrder32Host;
602
#endif
603
    cg_data = CGImageCreate(w, h, 8, 32, bytesPerRow, colorspace,
604
                            cgflags, provider, 0, 0, kCGRenderingIntentDefault);
605
}
606
607
void QMacPixmapData::macReleaseCGImageRef()
608
{
609
    if (!cg_data)
610
        return;  // There's nothing we need to do
611
612
    cg_dataBeingReleased = cg_data;
613
    CGImageRelease(cg_data);
614
    cg_data = 0;
615
616
    if (pixels != pixelsToFree) {
617
        macCreatePixels();
618
    } else {
619
        pixelsToFree = 0;
620
    }
621
}
622
623
624
// We create our space in memory to paint on here. If we already have existing pixels
625
// copy them over. This is to preserve the fact that CGImageRef's are immutable.
626
void QMacPixmapData::macCreatePixels()
627
{
628
    const int numBytes = bytesPerRow * h;
629
    quint32 *base_pixels;
630
    if (pixelsToFree && pixelsToFree != pixels) {
631
        // Reuse unused block of memory lying around from a previous callback.
632
        base_pixels = pixelsToFree;
633
        pixelsToFree = 0;
634
    } else {
635
        // We need a block of memory to do stuff with.
636
        base_pixels = static_cast<quint32 *>(malloc(numBytes));
637
    }
638
639
    if (pixels)
640
        memcpy(base_pixels, pixels, pixelsSize);
641
    pixels = base_pixels;
642
    pixelsSize = numBytes;
643
}
644
645
#if 0
646
QPixmap QMacPixmapData::transformed(const QTransform &transform,
647
                                    Qt::TransformationMode mode) const
648
{
649
    int w, h;  // size of target pixmap
650
    const int ws = width();
651
    const int hs = height();
652
653
    QTransform mat(transform.m11(), transform.m12(),
654
                   transform.m21(), transform.m22(), 0., 0.);
655
    if (transform.m12() == 0.0F  && transform.m21() == 0.0F &&
656
        transform.m11() >= 0.0F  && transform.m22() >= 0.0F)
657
    {
658
        h = int(qAbs(mat.m22()) * hs + 0.9999);
659
        w = int(qAbs(mat.m11()) * ws + 0.9999);
660
        h = qAbs(h);
661
        w = qAbs(w);
662
    } else { // rotation or shearing
663
        QPolygonF a(QRectF(0,0,ws+1,hs+1));
664
        a = mat.map(a);
665
        QRectF r = a.boundingRect().normalized();
666
        w = int(r.width() + 0.9999);
667
        h = int(r.height() + 0.9999);
668
    }
669
    mat = QPixmap::trueMatrix(mat, ws, hs);
670
    if (!h || !w)
671
        return QPixmap();
672
673
    // create destination
674
    QMacPixmapData *pm = new QMacPixmapData(pixelType(), w, h);
675
    const quint32 *sptr = pixels;
676
    quint32 *dptr = pm->pixels;
677
    memset(dptr, 0, (pm->bytesPerRow * pm->h));
678
679
    // do the transform
680
    if (mode == Qt::SmoothTransformation) {
681
#warning QMacPixmapData::transformed not properly implemented
682
        qWarning("QMacPixmapData::transformed not properly implemented");
683
#if 0
684
        QPainter p(&pm);
685
        p.setRenderHint(QPainter::Antialiasing);
686
        p.setRenderHint(QPainter::SmoothPixmapTransform);
687
        p.setTransform(mat);
688
        p.drawPixmap(0, 0, *this);
689
#endif
690
    } else {
691
        bool invertible;
692
        mat = mat.inverted(&invertible);
693
        if (!invertible)
694
            return QPixmap();
695
696
        const int bpp = 32;
697
        const int xbpl = (w * bpp) / 8;
698
        if (!qt_xForm_helper(mat, 0, QT_XFORM_TYPE_MSBFIRST, bpp,
699
                             (uchar*)dptr, xbpl, (pm->bytesPerRow) - xbpl,
700
                             h, (uchar*)sptr, (bytesPerRow), ws, hs)) {
701
            qWarning("QMacPixmapData::transform(): failure");
702
            return QPixmap();
703
        }
704
    }
705
706
    // update the alpha
707
    pm->macSetHasAlpha(true);
708
    return QPixmap(pm);
709
}
710
#endif
711
712
QT_BEGIN_INCLUDE_NAMESPACE
713
#include <OpenGL/OpenGL.h>
714
#include <OpenGL/gl.h>
715
QT_END_INCLUDE_NAMESPACE
716
717
// Load and resolve the symbols we need from OpenGL manually so QtGui doesn't have to link against the OpenGL framework.
718
typedef CGLError (*PtrCGLChoosePixelFormat)(const CGLPixelFormatAttribute *, CGLPixelFormatObj *,  long *);
719
typedef CGLError (*PtrCGLClearDrawable)(CGLContextObj);
720
typedef CGLError (*PtrCGLCreateContext)(CGLPixelFormatObj, CGLContextObj, CGLContextObj *);
721
typedef CGLError (*PtrCGLDestroyContext)(CGLContextObj);
722
typedef CGLError (*PtrCGLDestroyPixelFormat)(CGLPixelFormatObj);
723
typedef CGLError (*PtrCGLSetCurrentContext)(CGLContextObj);
724
typedef CGLError (*PtrCGLSetFullScreen)(CGLContextObj);
725
typedef void (*PtrglFinish)();
726
typedef void (*PtrglPixelStorei)(GLenum, GLint);
727
typedef void (*PtrglReadBuffer)(GLenum);
728
typedef void (*PtrglReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid *);
729
730
static PtrCGLChoosePixelFormat ptrCGLChoosePixelFormat = 0;
731
static PtrCGLClearDrawable ptrCGLClearDrawable = 0;
732
static PtrCGLCreateContext ptrCGLCreateContext = 0;
733
static PtrCGLDestroyContext ptrCGLDestroyContext = 0;
734
static PtrCGLDestroyPixelFormat ptrCGLDestroyPixelFormat = 0;
735
static PtrCGLSetCurrentContext ptrCGLSetCurrentContext = 0;
736
static PtrCGLSetFullScreen ptrCGLSetFullScreen = 0;
737
static PtrglFinish ptrglFinish = 0;
738
static PtrglPixelStorei ptrglPixelStorei = 0;
739
static PtrglReadBuffer ptrglReadBuffer = 0;
740
static PtrglReadPixels ptrglReadPixels = 0;
741
742
static bool resolveOpenGLSymbols()
743
{
744
    if (ptrCGLChoosePixelFormat == 0) {
745
        QLibrary library(QLatin1String("/System/Library/Frameworks/OpenGL.framework/OpenGL"));
746
        ptrCGLChoosePixelFormat = (PtrCGLChoosePixelFormat)(library.resolve("CGLChoosePixelFormat"));
747
        ptrCGLClearDrawable = (PtrCGLClearDrawable)(library.resolve("CGLClearDrawable"));
748
        ptrCGLCreateContext = (PtrCGLCreateContext)(library.resolve("CGLCreateContext"));
749
        ptrCGLDestroyContext = (PtrCGLDestroyContext)(library.resolve("CGLDestroyContext"));
750
        ptrCGLDestroyPixelFormat = (PtrCGLDestroyPixelFormat)(library.resolve("CGLDestroyPixelFormat"));
751
        ptrCGLSetCurrentContext = (PtrCGLSetCurrentContext)(library.resolve("CGLSetCurrentContext"));
752
        ptrCGLSetFullScreen = (PtrCGLSetFullScreen)(library.resolve("CGLSetFullScreen"));
753
        ptrglFinish = (PtrglFinish)(library.resolve("glFinish"));
754
        ptrglPixelStorei = (PtrglPixelStorei)(library.resolve("glPixelStorei"));
755
        ptrglReadBuffer = (PtrglReadBuffer)(library.resolve("glReadBuffer"));
756
        ptrglReadPixels = (PtrglReadPixels)(library.resolve("glReadPixels"));
757
    }
758
    return ptrCGLChoosePixelFormat && ptrCGLClearDrawable && ptrCGLCreateContext
759
        && ptrCGLDestroyContext && ptrCGLDestroyPixelFormat && ptrCGLSetCurrentContext
760
        && ptrCGLSetFullScreen && ptrglFinish && ptrglPixelStorei
761
        && ptrglReadBuffer && ptrglReadPixels;
762
}
763
764
// Inverts the given pixmap in the y direction.
765
static void qt_mac_flipPixmap(void *data, int rowBytes, int height)
766
{
767
    int bottom = height - 1;
768
    void *base = data;
769
    void *buffer = malloc(rowBytes);
770
771
    int top = 0;
772
    while ( top < bottom )
773
    {
774
        void *topP = (void *)((top * rowBytes) + (intptr_t)base);
775
        void *bottomP = (void *)((bottom * rowBytes) + (intptr_t)base);
776
777
        bcopy( topP, buffer, rowBytes );
778
        bcopy( bottomP, topP, rowBytes );
779
        bcopy( buffer, bottomP, rowBytes );
780
781
        ++top;
782
        --bottom;
783
    }
784
    free(buffer);
785
}
786
787
// Grabs displayRect from display and places it into buffer.
788
static void qt_mac_grabDisplayRect(CGDirectDisplayID display, const QRect &displayRect, void *buffer)
789
{
790
    if (display == kCGNullDirectDisplay)
791
        return;
792
793
    CGLPixelFormatAttribute attribs[] = {
794
        kCGLPFAFullScreen,
795
        kCGLPFADisplayMask,
796
        (CGLPixelFormatAttribute)0,    /* Display mask bit goes here */
797
        (CGLPixelFormatAttribute)0
798
    };
799
800
    attribs[2] = (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(display);
801
802
    // Build a full-screen GL context
803
    CGLPixelFormatObj pixelFormatObj;
804
    long numPixelFormats;
805
806
    ptrCGLChoosePixelFormat( attribs, &pixelFormatObj, &numPixelFormats );
807
808
    if (!pixelFormatObj)    // No full screen context support
809
        return;
810
811
    CGLContextObj glContextObj;
812
    ptrCGLCreateContext(pixelFormatObj, 0, &glContextObj);
813
    ptrCGLDestroyPixelFormat(pixelFormatObj) ;
814
    if (!glContextObj)
815
        return;
816
817
    ptrCGLSetCurrentContext(glContextObj);
818
    ptrCGLSetFullScreen(glContextObj) ;
819
820
    ptrglReadBuffer(GL_FRONT);
821
822
    ptrglFinish(); // Finish all OpenGL commands
823
    ptrglPixelStorei(GL_PACK_ALIGNMENT, 4);  // Force 4-byte alignment
824
    ptrglPixelStorei(GL_PACK_ROW_LENGTH, 0);
825
    ptrglPixelStorei(GL_PACK_SKIP_ROWS, 0);
826
    ptrglPixelStorei(GL_PACK_SKIP_PIXELS, 0);
827
828
    // Fetch the data in XRGB format, matching the bitmap context.
829
    ptrglReadPixels(GLint(displayRect.x()), GLint(displayRect.y()),
830
                    GLint(displayRect.width()), GLint(displayRect.height()),
831
#ifdef __BIG_ENDIAN__
832
                    GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer
833
#else
834
                    GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, buffer
835
#endif
836
        );
837
838
    ptrCGLSetCurrentContext(0);
839
    ptrCGLClearDrawable(glContextObj); // disassociate from full screen
840
    ptrCGLDestroyContext(glContextObj); // and destroy the context
841
}
842
843
// Returns a pixmap containing the screen contents at rect.
844
static QPixmap qt_mac_grabScreenRect(const QRect &rect)
845
{
846
    if (!resolveOpenGLSymbols())
847
        return QPixmap();
848
849
    const int maxDisplays = 128; // 128 displays should be enough for everyone.
850
    CGDirectDisplayID displays[maxDisplays];
851
    CGDisplayCount displayCount;
852
    const CGRect cgRect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
853
    const CGDisplayErr err = CGGetDisplaysWithRect(cgRect, maxDisplays, displays, &displayCount);
854
855
    if (err && displayCount == 0)
856
        return QPixmap();
857
858
    long bytewidth = rect.width() * 4; // Assume 4 bytes/pixel for now
859
    bytewidth = (bytewidth + 3) & ~3; // Align to 4 bytes
860
    QVarLengthArray<char> buffer(rect.height() * bytewidth);
861
862
    for (uint i = 0; i < displayCount; ++i) {
863
        const CGRect bounds = CGDisplayBounds(displays[i]);
864
        // Translate to display-local coordinates
865
        QRect displayRect = rect.translated(qRound(-bounds.origin.x), qRound(-bounds.origin.y));
866
        // Adjust for inverted y axis.
867
        displayRect.moveTop(qRound(bounds.size.height) - displayRect.y() - rect.height());
868
        qt_mac_grabDisplayRect(displays[i], displayRect, buffer.data());
869
    }
870
871
    qt_mac_flipPixmap(buffer.data(), bytewidth, rect.height());
872
    QCFType<CGContextRef> bitmap = CGBitmapContextCreate(buffer.data(), rect.width(),
873
                                                         rect.height(), 8, bytewidth,
874
                                        QCoreGraphicsPaintEngine::macGenericColorSpace(),
875
                                        kCGImageAlphaNoneSkipFirst);
876
    QCFType<CGImageRef> image = CGBitmapContextCreateImage(bitmap);
877
    return QPixmap::fromMacCGImageRef(image);
878
}
879
880
#ifndef QT_MAC_USE_COCOA // no QuickDraw in 64-bit mode
881
static QPixmap qt_mac_grabScreenRect_10_3(int x, int y, int w, int h, QWidget *widget)
882
{
883
    QPixmap pm = QPixmap(w, h);
884
    extern WindowPtr qt_mac_window_for(const QWidget *); // qwidget_mac.cpp
885
    const BitMap *windowPort = 0;
886
    if((widget->windowType() == Qt::Desktop)) {
887
        GDHandle gdh;
888
          if(!(gdh=GetMainDevice()))
889
              qDebug("Qt: internal: Unexpected condition reached: %s:%d", __FILE__, __LINE__);
890
          windowPort = (BitMap*)(*(*gdh)->gdPMap);
891
    } else {
892
        windowPort = GetPortBitMapForCopyBits(GetWindowPort(qt_mac_window_for(widget)));
893
    }
894
    const BitMap *pixmapPort = GetPortBitMapForCopyBits(static_cast<GWorldPtr>(pm.macQDHandle()));
895
    Rect macSrcRect, macDstRect;
896
    SetRect(&macSrcRect, x, y, x + w, y + h);
897
    SetRect(&macDstRect, 0, 0, w, h);
898
    CopyBits(windowPort, pixmapPort, &macSrcRect, &macDstRect, srcCopy, 0);
899
    return pm;
900
}
901
#endif
902
903
QPixmap QPixmap::grabWindow(WId window, int x, int y, int w, int h)
904
{
905
    QWidget *widget = QWidget::find(window);
906
    if (widget == 0)
907
        return QPixmap();
908
909
    if(w == -1)
910
        w = widget->width() - x;
911
    if(h == -1)
912
        h = widget->height() - y;
913
914
    QPoint globalCoord(0, 0);
915
    globalCoord = widget->mapToGlobal(globalCoord);
916
    QRect rect(globalCoord.x() + x, globalCoord.y() + y, w, h);
917
918
#ifdef QT_MAC_USE_COCOA
919
    return qt_mac_grabScreenRect(rect);
920
#else
921
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
922
    if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
923
        return qt_mac_grabScreenRect(rect);
924
    } else
925
#endif
926
   {
927
        return qt_mac_grabScreenRect_10_3(x, y, w, h, widget);
928
   }
929
#endif // ifdef Q_WS_MAC64
930
}
931
932
/*! \internal
933
934
    Returns the QuickDraw CGrafPtr of the pixmap. 0 is returned if it can't
935
    be obtained. Do not hold the pointer around for long as it can be
936
    relocated.
937
938
    \warning This function is only available on Mac OS X.
939
    \warning As of Qt 4.6, this function \e{always} returns zero.
940
*/
941
942
Qt::HANDLE QPixmap::macQDHandle() const
943
{
944
    return 0;
945
}
946
947
/*! \internal
948
949
    Returns the QuickDraw CGrafPtr of the pixmap's alpha channel. 0 is
950
    returned if it can't be obtained. Do not hold the pointer around for
951
    long as it can be relocated.
952
953
    \warning This function is only available on Mac OS X.
954
    \warning As of Qt 4.6, this function \e{always} returns zero.
955
*/
956
957
Qt::HANDLE QPixmap::macQDAlphaHandle() const
958
{
959
    return 0;
960
}
961
962
/*! \internal
963
964
    Returns the CoreGraphics CGContextRef of the pixmap. 0 is returned if
965
    it can't be obtained. It is the caller's responsiblity to
966
    CGContextRelease the context when finished using it.
967
968
    \warning This function is only available on Mac OS X.
969
*/
970
971
Qt::HANDLE QPixmap::macCGHandle() const
972
{
973
    if (isNull())
974
        return 0;
975
976
    if (data->classId() == QPixmapData::MacClass) {
977
        QMacPixmapData *d = static_cast<QMacPixmapData *>(data.data());
978
        if (!d->cg_data)
979
            d->macCreateCGImageRef();
980
        CGImageRef ret = d->cg_data;
981
        CGImageRetain(ret);
982
        return ret;
983
    } else if (data->classId() == QPixmapData::RasterClass) {
984
        return qt_mac_image_to_cgimage(static_cast<QRasterPixmapData *>(data.data())->image);
985
    }
986
    return 0;
987
}
988
989
bool QMacPixmapData::hasAlphaChannel() const
990
{
991
    return has_alpha;
992
}
993
994
CGImageRef qt_mac_create_imagemask(const QPixmap &pixmap, const QRectF &sr)
995
{
996
    QMacPixmapData *px = static_cast<QMacPixmapData*>(pixmap.data.data());
997
    if (px->cg_mask) {
998
        if (px->cg_mask_rect == sr) {
999
            CGImageRetain(px->cg_mask); //reference for the caller
1000
            return px->cg_mask;
1001
        }
1002
        CGImageRelease(px->cg_mask);
1003
        px->cg_mask = 0;
1004
    }
1005
1006
    const int sx = qRound(sr.x()), sy = qRound(sr.y()), sw = qRound(sr.width()), sh = qRound(sr.height());
1007
    const int sbpr = px->bytesPerRow;
1008
    const uint nbytes = sw * sh;
1009
    //  alpha is always 255 for bitmaps, ignore it in this case.
1010
    const quint32 mask = px->depth() == 1 ? 0x00ffffff : 0xffffffff;
1011
    quint8 *dptr = static_cast<quint8 *>(malloc(nbytes));
1012
    quint32 *sptr = px->pixels, *srow;
1013
    for(int y = sy, offset=0; y < sh; ++y) {
1014
        srow = sptr + (y * (sbpr / 4));
1015
        for(int x = sx; x < sw; ++x)
1016
            *(dptr+(offset++)) = (*(srow+x) & mask) ? 255 : 0;
1017
    }
1018
    QCFType<CGDataProviderRef> provider = CGDataProviderCreateWithData(0, dptr, nbytes, qt_mac_cgimage_data_free);
1019
    px->cg_mask = CGImageMaskCreate(sw, sh, 8, 8, nbytes / sh, provider, 0, 0);
1020
    px->cg_mask_rect = sr;
1021
    CGImageRetain(px->cg_mask); //reference for the caller
1022
    return px->cg_mask;
1023
}
1024
1025
#ifndef QT_MAC_USE_COCOA
1026
IconRef qt_mac_create_iconref(const QPixmap &px)
1027
{
1028
    if (px.isNull())
1029
        return 0;
1030
1031
    //create icon
1032
    IconFamilyHandle iconFamily = reinterpret_cast<IconFamilyHandle>(NewHandle(0));
1033
    //create data
1034
    {
1035
        struct {
1036
            OSType mac_type;
1037
            int width, height, depth;
1038
            bool mask;
1039
        } images[] = {
1040
            { kThumbnail32BitData, 128, 128, 32, false },
1041
            { kThumbnail8BitMask, 128, 128, 8, true },
1042
            { 0, 0, 0, 0, false } //end marker
1043
        };
1044
        for(int i = 0; images[i].mac_type; i++) {
1045
            //get QPixmap data
1046
            QImage scaled_px = px.toImage().scaled(images[i].width, images[i].height);
1047
1048
            quint32 *sptr = (quint32 *) scaled_px.bits();
1049
            quint32 *srow;
1050
            uint sbpr = scaled_px.bytesPerLine();
1051
1052
            //get Handle data
1053
            const int dbpr = images[i].width * (images[i].depth/8);
1054
            Handle hdl = NewHandle(dbpr*images[i].height);
1055
            if(!sptr) { //handle null pixmap
1056
                memset((*hdl), '\0', dbpr*images[i].height);
1057
            } else if(images[i].mask) {
1058
                if(images[i].mac_type == kThumbnail8BitMask) {
1059
                    for(int y = 0, hindex = 0; y < images[i].height; ++y) {
1060
                        srow = sptr + (y * (sbpr/4));
1061
                        for(int x = 0; x < images[i].width; ++x)
1062
                            *((*hdl)+(hindex++)) = qAlpha(*(srow+x));
1063
                    }
1064
                }
1065
            } else {
1066
                char *dest = (*hdl);
1067
#if defined(__i386__)
1068
                if(images[i].depth == 32) {
1069
                    for(int y = 0; y < images[i].height; ++y) {
1070
                        uint *source = (uint*)((const uchar*)sptr+(sbpr*y));
1071
                        for(int x = 0; x < images[i].width; ++x, dest += 4)
1072
                            *((uint*)dest) = CFSwapInt32(*(source + x));
1073
                    }
1074
                } else
1075
#endif
1076
                {
1077
                    for(int y = 0; y < images[i].height; ++y)
1078
                        memcpy(dest+(y*dbpr), ((const uchar*)sptr+(sbpr*y)), dbpr);
1079
                }
1080
            }
1081
1082
            //set the family data to the Handle
1083
            OSStatus set = SetIconFamilyData(iconFamily, images[i].mac_type, hdl);
1084
            if(set != noErr)
1085
                qWarning("%s: %d -- Unable to create icon data[%d]!! %ld",
1086
                         __FILE__, __LINE__, i, long(set));
1087
            DisposeHandle(hdl);
1088
        }
1089
    }
1090
1091
    //acquire and cleanup
1092
    IconRef ret;
1093
    static int counter = 0;
1094
    const OSType kQtCreator = 'CUTE';
1095
    RegisterIconRefFromIconFamily(kQtCreator, (OSType)counter, iconFamily, &ret);
1096
    AcquireIconRef(ret);
1097
    UnregisterIconRef(kQtCreator, (OSType)counter);
1098
    DisposeHandle(reinterpret_cast<Handle>(iconFamily));
1099
    counter++;
1100
    return ret;
1101
1102
}
1103
#endif
1104
1105
/*! \internal */
1106
QPaintEngine* QMacPixmapData::paintEngine() const
1107
{
1108
    if (!pengine) {
1109
        QMacPixmapData *that = const_cast<QMacPixmapData*>(this);
1110
        that->pengine = new QCoreGraphicsPaintEngine();
1111
    }
1112
    return pengine;
1113
}
1114
1115
void QMacPixmapData::copy(const QPixmapData *data, const QRect &rect)
1116
{
1117
    if (data->pixelType() == BitmapType) {
1118
        QBitmap::fromImage(toImage().copy(rect));
1119
        return;
1120
    }
1121
1122
    const QMacPixmapData *macData = static_cast<const QMacPixmapData*>(data);
1123
1124
    resize(rect.width(), rect.height());
1125
1126
    has_alpha = macData->has_alpha;
1127
    has_mask = macData->has_mask;
1128
    uninit = false;
1129
1130
    const int x = rect.x();
1131
    const int y = rect.y();
1132
    char *dest = reinterpret_cast<char*>(pixels);
1133
    const char *src = reinterpret_cast<const char*>(macData->pixels + x) + y * macData->bytesPerRow;
1134
    for (int i = 0; i < h; ++i) {
1135
        memcpy(dest, src, w * 4);
1136
        dest += bytesPerRow;
1137
        src += macData->bytesPerRow;
1138
    }
1139
1140
    has_alpha = macData->has_alpha;
1141
    has_mask = macData->has_mask;
1142
}
1143
1144
bool QMacPixmapData::scroll(int dx, int dy, const QRect &rect)
1145
{
1146
    Q_UNUSED(dx);
1147
    Q_UNUSED(dy);
1148
    Q_UNUSED(rect);
1149
    return false;
1150
}
1151
1152
/*!
1153
    \since 4.2
1154
1155
    Creates a \c CGImageRef equivalent to the QPixmap. Returns the \c CGImageRef handle.
1156
1157
    It is the caller's responsibility to release the \c CGImageRef data
1158
    after use.
1159
1160
    \warning This function is only available on Mac OS X.
1161
1162
    \sa fromMacCGImageRef()
1163
*/
1164
CGImageRef QPixmap::toMacCGImageRef() const
1165
{
1166
    return (CGImageRef)macCGHandle();
1167
}
1168
1169
/*!
1170
    \since 4.2
1171
1172
    Returns a QPixmap that is equivalent to the given \a image.
1173
1174
    \warning This function is only available on Mac OS X.
1175
1176
    \sa toMacCGImageRef(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
1177
*/
1178
QPixmap QPixmap::fromMacCGImageRef(CGImageRef image)
1179
{
1180
    const size_t w = CGImageGetWidth(image),
1181
                 h = CGImageGetHeight(image);
1182
    QPixmap ret(w, h);
1183
    ret.fill(Qt::transparent);
1184
    CGRect rect = CGRectMake(0, 0, w, h);
1185
    CGContextRef ctx = qt_mac_cg_context(&ret);
1186
    qt_mac_drawCGImage(ctx, &rect, image);
1187
    CGContextRelease(ctx);
1188
    return ret;
1189
}
1190
1191
QT_END_NAMESPACE