1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
44 #include "qapplication.h"
47 #include "qtransform.h"
49 #include "qvarlengtharray.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>
64 /*****************************************************************************
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
73 static int qt_pixmap_serial = 0;
75 Q_WIDGETS_EXPORT quint32 *qt_mac_pixmap_get_base(const QPixmap *pix)
77 if (QApplicationPrivate::graphics_system_name == QLatin1String("raster"))
78 return reinterpret_cast<quint32 *>(static_cast<QRasterPlatformPixmap*>(pix->data.data())->buffer()->bits());
80 return static_cast<QMacPlatformPixmap*>(pix->data.data())->pixels;
83 Q_WIDGETS_EXPORT int qt_mac_pixmap_get_bytes_per_line(const QPixmap *pix)
85 if (QApplicationPrivate::graphics_system_name == QLatin1String("raster"))
86 return static_cast<QRasterPlatformPixmap*>(pix->data.data())->buffer()->bytesPerLine();
88 return static_cast<QMacPlatformPixmap*>(pix->data.data())->bytesPerRow;
91 void qt_mac_cgimage_data_free(void *info, const void *memoryToFree, size_t)
93 QMacPlatformPixmap *pmdata = static_cast<QMacPlatformPixmap *>(info);
95 free(const_cast<void *>(memoryToFree));
97 if (QMacPlatformPixmap::validDataPointers.contains(pmdata) == false) {
98 free(const_cast<void *>(memoryToFree));
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));
106 free(pmdata->pixelsToFree);
107 pmdata->pixelsToFree = static_cast<quint32 *>(const_cast<void *>(memoryToFree));
109 pmdata->cg_dataBeingReleased = 0;
113 /*****************************************************************************
114 QPixmap member functions
115 *****************************************************************************/
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));
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;
135 return qRgb(tr,tg,tb);
138 QSet<QMacPlatformPixmap*> QMacPlatformPixmap::validDataPointers;
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),
148 QPlatformPixmap *QMacPlatformPixmap::createCompatiblePlatformPixmap() const
150 return new QMacPlatformPixmap(pixelType());
153 #define BEST_BYTE_ALIGNMENT 16
154 #define COMPTUE_BEST_BYTES_PER_ROW(bpr) \
155 (((bpr) + (BEST_BYTE_ALIGNMENT - 1)) & ~(BEST_BYTE_ALIGNMENT - 1))
157 void QMacPlatformPixmap::resize(int width, int height)
159 setSerialNumber(++qt_pixmap_serial);
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) {
172 qWarning("Qt: QPixmap: Invalid pixmap parameters");
180 bytesPerRow = w * sizeof(quint32); // Minimum bytes per row.
182 // Quartz2D likes things as a multple of 16 (for now).
183 bytesPerRow = COMPTUE_BEST_BYTES_PER_ROW(bytesPerRow);
187 #undef COMPUTE_BEST_BYTES_PER_ROW
189 void QMacPlatformPixmap::fromImage(const QImage &img,
190 Qt::ImageConversionFlags flags)
192 setSerialNumber(++qt_pixmap_serial);
194 // the conversion code only handles format >=
195 // Format_ARGB32_Premultiplied at the moment..
196 if (img.format() > QImage::Format_ARGB32_Premultiplied) {
198 if (img.hasAlphaChannel())
199 image = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
201 image = img.convertToFormat(QImage::Format_RGB32);
202 fromImage(image, flags);
208 is_null = (w <= 0 || h <= 0);
209 d = (pixelType() == BitmapType ? 1 : img.depth());
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
217 image = image.convertToFormat(QImage::Format_MonoLSB, flags); // dither
220 } else { // can be both
222 if(d > 8 && dd <= 8) { // convert to 8 bit
223 if ((flags & Qt::DitherMode_Mask) == Qt::AutoDither)
224 flags = (flags & ~Qt::DitherMode_Mask)
227 } else if ((flags & Qt::ColorMode_Mask) == Qt::ColorOnly) {
228 conv8 = d == 1; // native depth wanted
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);
235 // eg. 1-color monochrome images (they do exist).
240 image = image.convertToFormat(QImage::Format_Indexed8, flags);
245 if (image.depth()==1) {
246 image.setColor(0, QColor(Qt::color0).rgba());
247 image.setColor(1, QColor(Qt::color1).rgba());
250 if (d == 16 || d == 24) {
251 image = image.convertToFormat(QImage::Format_RGB32, flags);
252 fromImage(image, flags);
256 // different size or depth, make a new pixmap
259 quint32 *dptr = pixels, *drow;
260 const uint dbpr = bytesPerRow;
262 const QImage::Format sfmt = image.format();
263 const unsigned short sbpr = image.bytesPerLine();
265 // use const_cast to prevent a detach
266 const uchar *sptr = const_cast<const QImage &>(image).bits(), *srow;
268 for (int y = 0; y < h; ++y) {
269 drow = dptr + (y * (dbpr / 4));
270 srow = sptr + (y * sbpr);
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));
279 one_bit = one_bit >> (x % 8);
280 if ((one_bit & 0x01))
281 *(drow+x) = 0xFF000000;
283 *(drow+x) = 0xFFFFFFFF;
287 case QImage::Format_Indexed8: {
288 int numColors = image.numColors();
290 for (int x = 0; x < w; ++x) {
291 int index = *(srow + x);
292 *(drow+x) = PREMUL(image.color(qMin(index, numColors)));
296 case QImage::Format_RGB32:
297 for (int x = 0; x < w; ++x)
298 *(drow+x) = *(((quint32*)srow) + x) | 0xFF000000;
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);
308 *(drow+x) = PREMUL(*(((quint32*)srow) + x));
312 qWarning("Qt: internal: Oops: Forgot a format [%d] %s:%d", sfmt,
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]);
329 macSetHasAlpha(alphamap);
334 int get_index(QImage * qi,QRgb mycol)
337 for(loopc=0;loopc<qi->colorCount();loopc++) {
338 if(qi->color(loopc)==mycol)
341 qi->setColorCount(qi->colorCount()+1);
342 qi->setColor(qi->colorCount(),mycol);
343 return qi->colorCount();
346 QImage QMacPlatformPixmap::toImage() const
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);
353 QImage image(w, h, format);
354 quint32 *sptr = pixels, *srow;
355 const uint sbpr = bytesPerRow;
356 if (format == QImage::Format_MonoLSB) {
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));
370 for (int y = 0; y < h; ++y) {
371 srow = sptr + (y * (sbpr / 4));
372 memcpy(image.scanLine(y), srow, w * 4);
380 void QMacPlatformPixmap::fill(const QColor &fillColor)
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;
389 memset(dptr, 0, nbytes);
391 for (uint i = 0; i < nbytes / sizeof(quint32); ++i)
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);
402 QPixmap QMacPlatformPixmap::alphaChannel() const
407 QMacPlatformPixmap *alpha = new QMacPlatformPixmap(PixmapType);
409 macGetAlphaChannel(alpha, false);
410 return QPixmap(alpha);
413 void QMacPlatformPixmap::setAlphaChannel(const QPixmap &alpha)
416 QMacPlatformPixmap *alphaData = static_cast<QMacPlatformPixmap*>(alpha.data.data());
417 macSetAlphaChannel(alphaData, false);
420 QBitmap QMacPlatformPixmap::mask() const
422 if (!has_mask && !has_alpha)
425 QMacPlatformPixmap *mask = new QMacPlatformPixmap(BitmapType);
427 macGetAlphaChannel(mask, true);
428 return QPixmap(mask);
431 void QMacPlatformPixmap::setMask(const QBitmap &mask)
434 QMacPlatformPixmap opaque(PixmapType);
436 opaque.fill(QColor(255, 255, 255, 255));
437 macSetAlphaChannel(&opaque, true);
438 has_alpha = has_mask = false;
444 QMacPlatformPixmap *maskData = static_cast<QMacPlatformPixmap*>(mask.data.data());
445 macSetAlphaChannel(maskData, true);
448 int QMacPlatformPixmap::metric(QPaintDevice::PaintDeviceMetric theMetric) const
451 case QPaintDevice::PdmWidth:
453 case QPaintDevice::PdmHeight:
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:
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());
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());
471 case QPaintDevice::PdmDepth:
474 qWarning("QPixmap::metric: Invalid metric command");
479 QMacPlatformPixmap::~QMacPlatformPixmap()
481 validDataPointers.remove(this);
483 CGImageRelease(cg_mask);
487 delete pengine; // Make sure we aren't drawing on the context anymore.
489 CGImageRelease(cg_data);
490 } else if (!cg_dataBeingReleased && pixels != pixelsToFree) {
496 void QMacPlatformPixmap::macSetAlphaChannel(const QMacPlatformPixmap *pix, bool asMask)
498 if (!pixels || !h || !w || pix->w != w || pix->h != h)
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));
509 for (int x=0; x < w; ++x) {
510 if((*(srow+x) & RGB_MASK))
511 *(drow+x) = 0xFFFFFFFF;
514 for (int x=0; x < w; ++x)
515 *(drow+x) = (*(drow+x) & RGB_MASK) | (*(srow+x) << 24);
517 for (int x=0; x < w; ++x) {
518 if(*(srow+x) & RGB_MASK)
519 *(drow+x) = (*(drow+x) & RGB_MASK);
521 *(drow+x) = (*(drow+x) & RGB_MASK) | 0xFF000000;
522 *(drow+x) = PREMUL(*(drow+x));
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)));
529 *(drow+x) = (*(drow+x) & RGB_MASK) | (destAlpha << 24);
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);
535 *(drow+x) = PREMUL(*(drow+x));
539 macSetHasAlpha(true);
542 void QMacPlatformPixmap::macGetAlphaChannel(QMacPlatformPixmap *pix, bool asMask) const
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));
552 for (int x = 0; x < w; ++x) {
553 if (*(srow + x) & qRgba(0, 0, 0, 255))
554 *(drow + x) = 0x00000000;
556 *(drow + x) = 0xFFFFFFFF;
559 for (int x = 0; x < w; ++x) {
560 const int alpha = qAlpha(*(srow + x));
561 *(drow + x) = qRgb(alpha, alpha, alpha);
567 void QMacPlatformPixmap::macSetHasAlpha(bool b)
570 macReleaseCGImageRef();
573 void QMacPlatformPixmap::macCreateCGImageRef()
575 Q_ASSERT(cg_data == 0);
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;
586 cg_data = CGImageCreate(w, h, 8, 32, bytesPerRow, colorspace,
587 cgflags, provider, 0, 0, kCGRenderingIntentDefault);
590 void QMacPlatformPixmap::macReleaseCGImageRef()
593 return; // There's nothing we need to do
595 cg_dataBeingReleased = cg_data;
596 CGImageRelease(cg_data);
599 if (pixels != pixelsToFree) {
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()
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;
618 // We need a block of memory to do stuff with.
619 base_pixels = static_cast<quint32 *>(malloc(numBytes));
623 memcpy(base_pixels, pixels, pixelsSize);
624 pixels = base_pixels;
625 pixelsSize = numBytes;
629 QPixmap QMacPlatformPixmap::transformed(const QTransform &transform,
630 Qt::TransformationMode mode) const
632 int w, h; // size of target pixmap
633 const int ws = width();
634 const int hs = height();
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)
641 h = int(qAbs(mat.m22()) * hs + 0.9999);
642 w = int(qAbs(mat.m11()) * ws + 0.9999);
645 } else { // rotation or shearing
646 QPolygonF a(QRectF(0,0,ws+1,hs+1));
648 QRectF r = a.boundingRect().normalized();
649 w = int(r.width() + 0.9999);
650 h = int(r.height() + 0.9999);
652 mat = QPixmap::trueMatrix(mat, ws, hs);
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));
663 if (mode == Qt::SmoothTransformation) {
664 #warning QMacPlatformPixmap::transformed not properly implemented
665 qWarning("QMacPlatformPixmap::transformed not properly implemented");
668 p.setRenderHint(QPainter::Antialiasing);
669 p.setRenderHint(QPainter::SmoothPixmapTransform);
671 p.drawPixmap(0, 0, *this);
675 mat = mat.inverted(&invertible);
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");
690 pm->macSetHasAlpha(true);
695 QT_BEGIN_INCLUDE_NAMESPACE
696 #include <OpenGL/OpenGL.h>
697 #include <OpenGL/gl.h>
698 QT_END_INCLUDE_NAMESPACE
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 *);
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;
725 static bool resolveOpenGLSymbols()
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"));
741 return ptrCGLChoosePixelFormat && ptrCGLClearDrawable && ptrCGLCreateContext
742 && ptrCGLDestroyContext && ptrCGLDestroyPixelFormat && ptrCGLSetCurrentContext
743 && ptrCGLSetFullScreen && ptrglFinish && ptrglPixelStorei
744 && ptrglReadBuffer && ptrglReadPixels;
747 // Inverts the given pixmap in the y direction.
748 static void qt_mac_flipPixmap(void *data, int rowBytes, int height)
750 int bottom = height - 1;
752 void *buffer = malloc(rowBytes);
755 while ( top < bottom )
757 void *topP = (void *)((top * rowBytes) + (intptr_t)base);
758 void *bottomP = (void *)((bottom * rowBytes) + (intptr_t)base);
760 bcopy( topP, buffer, rowBytes );
761 bcopy( bottomP, topP, rowBytes );
762 bcopy( buffer, bottomP, rowBytes );
770 // Grabs displayRect from display and places it into buffer.
771 static void qt_mac_grabDisplayRect(CGDirectDisplayID display, const QRect &displayRect, void *buffer)
773 if (display == kCGNullDirectDisplay)
776 CGLPixelFormatAttribute attribs[] = {
779 (CGLPixelFormatAttribute)0, /* Display mask bit goes here */
780 (CGLPixelFormatAttribute)0
783 attribs[2] = (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(display);
785 // Build a full-screen GL context
786 CGLPixelFormatObj pixelFormatObj;
787 long numPixelFormats;
789 ptrCGLChoosePixelFormat( attribs, &pixelFormatObj, &numPixelFormats );
791 if (!pixelFormatObj) // No full screen context support
794 CGLContextObj glContextObj;
795 ptrCGLCreateContext(pixelFormatObj, 0, &glContextObj);
796 ptrCGLDestroyPixelFormat(pixelFormatObj) ;
800 ptrCGLSetCurrentContext(glContextObj);
801 ptrCGLSetFullScreen(glContextObj) ;
803 ptrglReadBuffer(GL_FRONT);
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);
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
817 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, buffer
821 ptrCGLSetCurrentContext(0);
822 ptrCGLClearDrawable(glContextObj); // disassociate from full screen
823 ptrCGLDestroyContext(glContextObj); // and destroy the context
826 // Returns a pixmap containing the screen contents at rect.
827 static QPixmap qt_mac_grabScreenRect(const QRect &rect)
829 if (!resolveOpenGLSymbols())
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);
838 if (err && displayCount == 0)
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);
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());
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);
864 QPixmap QPixmap::grabWindow(WId window, int x, int y, int w, int h)
866 QWidget *widget = QWidget::find(window);
871 w = widget->width() - x;
873 h = widget->height() - y;
875 QPoint globalCoord(0, 0);
876 globalCoord = widget->mapToGlobal(globalCoord);
877 QRect rect(globalCoord.x() + x, globalCoord.y() + y, w, h);
879 return qt_mac_grabScreenRect(rect);
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
888 \warning This function is only available on Mac OS X.
889 \warning As of Qt 4.6, this function \e{always} returns zero.
892 Qt::HANDLE QPixmap::macQDHandle() const
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.
903 \warning This function is only available on Mac OS X.
904 \warning As of Qt 4.6, this function \e{always} returns zero.
907 Qt::HANDLE QPixmap::macQDAlphaHandle() const
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.
918 \warning This function is only available on Mac OS X.
921 Qt::HANDLE QPixmap::macCGHandle() const
926 if (data->classId() == QPlatformPixmap::MacClass) {
927 QMacPlatformPixmap *d = static_cast<QMacPlatformPixmap *>(data.data());
929 d->macCreateCGImageRef();
930 CGImageRef ret = d->cg_data;
933 } else if (data->classId() == QPlatformPixmap::RasterClass) {
934 return qt_mac_image_to_cgimage(static_cast<QRasterPlatformPixmap *>(data.data())->image);
939 bool QMacPlatformPixmap::hasAlphaChannel() const
944 CGImageRef qt_mac_create_imagemask(const QPixmap &pixmap, const QRectF &sr)
946 QMacPlatformPixmap *px = static_cast<QMacPlatformPixmap*>(pixmap.data.data());
948 if (px->cg_mask_rect == sr) {
949 CGImageRetain(px->cg_mask); //reference for the caller
952 CGImageRelease(px->cg_mask);
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;
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
977 QPaintEngine* QMacPlatformPixmap::paintEngine() const
980 QMacPlatformPixmap *that = const_cast<QMacPlatformPixmap*>(this);
981 that->pengine = new QCoreGraphicsPaintEngine();
986 void QMacPlatformPixmap::copy(const QPlatformPixmap *data, const QRect &rect)
988 if (data->pixelType() == BitmapType) {
989 QBitmap::fromImage(toImage().copy(rect));
993 const QMacPlatformPixmap *macData = static_cast<const QMacPlatformPixmap*>(data);
995 resize(rect.width(), rect.height());
997 has_alpha = macData->has_alpha;
998 has_mask = macData->has_mask;
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;
1011 has_alpha = macData->has_alpha;
1012 has_mask = macData->has_mask;
1015 bool QMacPlatformPixmap::scroll(int dx, int dy, const QRect &rect)
1026 Creates a \c CGImageRef equivalent to the QPixmap. Returns the \c CGImageRef handle.
1028 It is the caller's responsibility to release the \c CGImageRef data
1031 \warning This function is only available on Mac OS X.
1033 \sa fromMacCGImageRef()
1035 CGImageRef QPixmap::toMacCGImageRef() const
1037 return (CGImageRef)macCGHandle();
1043 Returns a QPixmap that is equivalent to the given \a image.
1045 \warning This function is only available on Mac OS X.
1047 \sa toMacCGImageRef(), {QPixmap#Pixmap Conversion}{Pixmap Conversion}
1049 QPixmap QPixmap::fromMacCGImageRef(CGImageRef image)
1051 const size_t w = CGImageGetWidth(image),
1052 h = CGImageGetHeight(image);
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);