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