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