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