source: trunk/src/gui/image/qpixmap_mac.cpp@ 503

Last change on this file since 503 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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