src/gui/painting/qpaintengine_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 <qbitmap.h>
       
    43 #include <qpaintdevice.h>
       
    44 #include <private/qpaintengine_mac_p.h>
       
    45 #include <qpainterpath.h>
       
    46 #include <qpixmapcache.h>
       
    47 #include <private/qpaintengine_raster_p.h>
       
    48 #include <private/qprintengine_mac_p.h>
       
    49 #include <qprinter.h>
       
    50 #include <qstack.h>
       
    51 #include <qtextcodec.h>
       
    52 #include <qwidget.h>
       
    53 #include <qvarlengtharray.h>
       
    54 #include <qdebug.h>
       
    55 #include <qcoreapplication.h>
       
    56 #include <qmath.h>
       
    57 
       
    58 #include <private/qfont_p.h>
       
    59 #include <private/qfontengine_p.h>
       
    60 #include <private/qnumeric_p.h>
       
    61 #include <private/qpainter_p.h>
       
    62 #include <private/qpainterpath_p.h>
       
    63 #include <private/qpixmap_mac_p.h>
       
    64 #include <private/qt_mac_p.h>
       
    65 #include <private/qtextengine_p.h>
       
    66 #include <private/qwidget_p.h>
       
    67 #include <private/qt_cocoa_helpers_mac_p.h>
       
    68 
       
    69 #include <string.h>
       
    70 
       
    71 QT_BEGIN_NAMESPACE
       
    72 
       
    73 extern int qt_antialiasing_threshold; // QApplication.cpp
       
    74 
       
    75 /*****************************************************************************
       
    76   External functions
       
    77  *****************************************************************************/
       
    78 extern CGImageRef qt_mac_create_imagemask(const QPixmap &px, const QRectF &sr); //qpixmap_mac.cpp
       
    79 extern QPoint qt_mac_posInWindow(const QWidget *w); //qwidget_mac.cpp
       
    80 extern OSWindowRef qt_mac_window_for(const QWidget *); //qwidget_mac.cpp
       
    81 extern CGContextRef qt_mac_cg_context(const QPaintDevice *); //qpaintdevice_mac.cpp
       
    82 extern void qt_mac_dispose_rgn(RgnHandle r); //qregion_mac.cpp
       
    83 extern QPixmap qt_pixmapForBrush(int, bool); //qbrush.cpp
       
    84 
       
    85 void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform);
       
    86 
       
    87 
       
    88 //Implemented for qt_mac_p.h
       
    89 QMacCGContext::QMacCGContext(QPainter *p)
       
    90 {
       
    91     QPaintEngine *pe = p->paintEngine();
       
    92     if (pe->type() == QPaintEngine::MacPrinter)
       
    93         pe = static_cast<QMacPrintEngine*>(pe)->paintEngine();
       
    94     pe->syncState();
       
    95     context = 0;
       
    96     if(pe->type() == QPaintEngine::CoreGraphics)
       
    97         context = static_cast<QCoreGraphicsPaintEngine*>(pe)->handle();
       
    98 
       
    99     int devType = p->device()->devType();
       
   100     if (pe->type() == QPaintEngine::Raster
       
   101             && (devType == QInternal::Widget || devType == QInternal::Pixmap)) {
       
   102 
       
   103         extern CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice);
       
   104         CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pe->paintDevice());
       
   105         uint flags = kCGImageAlphaPremultipliedFirst;
       
   106 #ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version
       
   107         flags |= kCGBitmapByteOrder32Host;
       
   108 #endif
       
   109         const QImage *image = (const QImage *) pe->paintDevice();
       
   110 
       
   111         context = CGBitmapContextCreate((void *) image->bits(), image->width(), image->height(),
       
   112                                         8, image->bytesPerLine(), colorspace, flags);
       
   113 
       
   114         CGContextTranslateCTM(context, 0, image->height());
       
   115         CGContextScaleCTM(context, 1, -1);
       
   116 
       
   117         if (devType == QInternal::Widget) {
       
   118             QRegion clip = p->paintEngine()->systemClip();
       
   119             QTransform native = p->deviceTransform();
       
   120             QTransform logical = p->combinedTransform();
       
   121             if (p->hasClipping()) {
       
   122                 QRegion r = p->clipRegion();
       
   123                 r.translate(native.dx() - logical.dx(), native.dy() - logical.dy());
       
   124                 if (clip.isEmpty())
       
   125                     clip = r;
       
   126                 else
       
   127                     clip &= r;
       
   128             }
       
   129             qt_mac_clip_cg(context, clip, 0);
       
   130 
       
   131             QPainterState *state = static_cast<QPainterState *>(pe->state);
       
   132             Q_ASSERT(state);
       
   133             if (!state->redirectionMatrix.isIdentity())
       
   134                 CGContextTranslateCTM(context, state->redirectionMatrix.dx(), state->redirectionMatrix.dy());
       
   135         }
       
   136     }
       
   137     CGContextRetain(context);
       
   138 }
       
   139 
       
   140 
       
   141 /*****************************************************************************
       
   142   QCoreGraphicsPaintEngine utility functions
       
   143  *****************************************************************************/
       
   144 
       
   145 //conversion
       
   146 inline static float qt_mac_convert_color_to_cg(int c) { return ((float)c * 1000 / 255) / 1000; }
       
   147 inline static int qt_mac_convert_color_from_cg(float c) { return qRound(c * 255); }
       
   148 CGAffineTransform qt_mac_convert_transform_to_cg(const QTransform &t) {
       
   149     return CGAffineTransformMake(t.m11(), t.m12(), t.m21(), t.m22(), t.dx(),  t.dy());
       
   150 }
       
   151 
       
   152 CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice)
       
   153 {
       
   154     bool isWidget = (paintDevice->devType() == QInternal::Widget);
       
   155     return QCoreGraphicsPaintEngine::macDisplayColorSpace(isWidget ? static_cast<const QWidget *>(paintDevice)
       
   156                                                                    : 0);
       
   157 }
       
   158 
       
   159 inline static QCFType<CGColorRef> cgColorForQColor(const QColor &col, QPaintDevice *pdev)
       
   160 {
       
   161     CGFloat components[] = {
       
   162         qt_mac_convert_color_to_cg(col.red()),
       
   163         qt_mac_convert_color_to_cg(col.green()),
       
   164         qt_mac_convert_color_to_cg(col.blue()),
       
   165         qt_mac_convert_color_to_cg(col.alpha())
       
   166     };
       
   167     return CGColorCreate(qt_mac_colorSpaceForDeviceType(pdev), components);
       
   168 }
       
   169 
       
   170 // There's architectural problems with using native gradients
       
   171 // on the Mac at the moment, so disable them.
       
   172 // #define QT_MAC_USE_NATIVE_GRADIENTS
       
   173 
       
   174 #ifdef QT_MAC_USE_NATIVE_GRADIENTS
       
   175 static bool drawGradientNatively(const QGradient *gradient)
       
   176 {
       
   177     return gradient->spread() == QGradient::PadSpread;
       
   178 }
       
   179 
       
   180 // gradiant callback
       
   181 static void qt_mac_color_gradient_function(void *info, const CGFloat *in, CGFloat *out)
       
   182 {
       
   183     QBrush *brush = static_cast<QBrush *>(info);
       
   184     Q_ASSERT(brush && brush->gradient());
       
   185 
       
   186     const QGradientStops stops = brush->gradient()->stops();
       
   187     const int n = stops.count();
       
   188     Q_ASSERT(n >= 1);
       
   189     const QGradientStop *begin = stops.constBegin();
       
   190     const QGradientStop *end = begin + n;
       
   191 
       
   192     qreal p = in[0];
       
   193     const QGradientStop *i = begin;
       
   194     while (i != end && i->first < p)
       
   195         ++i;
       
   196 
       
   197     QRgb c;
       
   198     if (i == begin) {
       
   199         c = begin->second.rgba();
       
   200     } else if (i == end) {
       
   201         c = (end - 1)->second.rgba();
       
   202     } else {
       
   203         const QGradientStop &s1 = *(i - 1);
       
   204         const QGradientStop &s2 = *i;
       
   205         qreal p1 = s1.first;
       
   206         qreal p2 = s2.first;
       
   207         QRgb c1 = s1.second.rgba();
       
   208         QRgb c2 = s2.second.rgba();
       
   209         int idist = 256 * (p - p1) / (p2 - p1);
       
   210         int dist = 256 - idist;
       
   211         c = qRgba(INTERPOLATE_PIXEL_256(qRed(c1), dist, qRed(c2), idist),
       
   212                   INTERPOLATE_PIXEL_256(qGreen(c1), dist, qGreen(c2), idist),
       
   213                   INTERPOLATE_PIXEL_256(qBlue(c1), dist, qBlue(c2), idist),
       
   214                   INTERPOLATE_PIXEL_256(qAlpha(c1), dist, qAlpha(c2), idist));
       
   215     }
       
   216 
       
   217     out[0] = qt_mac_convert_color_to_cg(qRed(c));
       
   218     out[1] = qt_mac_convert_color_to_cg(qGreen(c));
       
   219     out[2] = qt_mac_convert_color_to_cg(qBlue(c));
       
   220     out[3] = qt_mac_convert_color_to_cg(qAlpha(c));
       
   221 }
       
   222 #endif
       
   223 
       
   224 //clipping handling
       
   225 void QCoreGraphicsPaintEnginePrivate::resetClip()
       
   226 {
       
   227     static bool inReset = false;
       
   228     if (inReset)
       
   229         return;
       
   230     inReset = true;
       
   231 
       
   232     CGAffineTransform old_xform = CGContextGetCTM(hd);
       
   233 
       
   234     //setup xforms
       
   235     CGContextConcatCTM(hd, CGAffineTransformInvert(old_xform));
       
   236     while (stackCount > 0) {
       
   237         restoreGraphicsState();
       
   238     }
       
   239     saveGraphicsState();
       
   240     inReset = false;
       
   241     //reset xforms
       
   242     CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd)));
       
   243     CGContextConcatCTM(hd, old_xform);
       
   244 }
       
   245 
       
   246 static CGRect qt_mac_compose_rect(const QRectF &r, float off=0)
       
   247 {
       
   248     return CGRectMake(r.x()+off, r.y()+off, r.width(), r.height());
       
   249 }
       
   250 
       
   251 static CGMutablePathRef qt_mac_compose_path(const QPainterPath &p, float off=0)
       
   252 {
       
   253     CGMutablePathRef ret = CGPathCreateMutable();
       
   254     QPointF startPt;
       
   255     for (int i=0; i<p.elementCount(); ++i) {
       
   256         const QPainterPath::Element &elm = p.elementAt(i);
       
   257         switch (elm.type) {
       
   258             case QPainterPath::MoveToElement:
       
   259                 if(i > 0
       
   260                         && p.elementAt(i - 1).x == startPt.x()
       
   261                         && p.elementAt(i - 1).y == startPt.y())
       
   262                     CGPathCloseSubpath(ret);
       
   263                 startPt = QPointF(elm.x, elm.y);
       
   264                 CGPathMoveToPoint(ret, 0, elm.x+off, elm.y+off);
       
   265                 break;
       
   266             case QPainterPath::LineToElement:
       
   267                 CGPathAddLineToPoint(ret, 0, elm.x+off, elm.y+off);
       
   268                 break;
       
   269             case QPainterPath::CurveToElement:
       
   270                 Q_ASSERT(p.elementAt(i+1).type == QPainterPath::CurveToDataElement);
       
   271                 Q_ASSERT(p.elementAt(i+2).type == QPainterPath::CurveToDataElement);
       
   272                 CGPathAddCurveToPoint(ret, 0,
       
   273                         elm.x+off, elm.y+off,
       
   274                         p.elementAt(i+1).x+off, p.elementAt(i+1).y+off,
       
   275                         p.elementAt(i+2).x+off, p.elementAt(i+2).y+off);
       
   276                 i+=2;
       
   277                 break;
       
   278             default:
       
   279                 qFatal("QCoreGraphicsPaintEngine::drawPath(), unhandled type: %d", elm.type);
       
   280                 break;
       
   281         }
       
   282     }
       
   283     if(!p.isEmpty()
       
   284             && p.elementAt(p.elementCount() - 1).x == startPt.x()
       
   285             && p.elementAt(p.elementCount() - 1).y == startPt.y())
       
   286         CGPathCloseSubpath(ret);
       
   287     return ret;
       
   288 }
       
   289 
       
   290 CGColorSpaceRef QCoreGraphicsPaintEngine::m_genericColorSpace = 0;
       
   291 QHash<CGDirectDisplayID, CGColorSpaceRef> QCoreGraphicsPaintEngine::m_displayColorSpaceHash;
       
   292 bool QCoreGraphicsPaintEngine::m_postRoutineRegistered = false;
       
   293 
       
   294 CGColorSpaceRef QCoreGraphicsPaintEngine::macGenericColorSpace()
       
   295 {
       
   296 #if 0
       
   297     if (!m_genericColorSpace) {
       
   298 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
       
   299         if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
       
   300             m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
       
   301         } else
       
   302 #endif
       
   303         {
       
   304             m_genericColorSpace = CGColorSpaceCreateDeviceRGB();
       
   305         }
       
   306         if (!m_postRoutineRegistered) {
       
   307             m_postRoutineRegistered = true;
       
   308             qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces);
       
   309         }
       
   310     }
       
   311     return m_genericColorSpace;
       
   312 #else
       
   313     // Just return the main display colorspace for the moment.
       
   314     return macDisplayColorSpace();
       
   315 #endif
       
   316 }
       
   317 
       
   318 /*
       
   319     Ideally, we should pass the widget in here, and use CGGetDisplaysWithRect() etc.
       
   320     to support multiple displays correctly.
       
   321 */
       
   322 CGColorSpaceRef QCoreGraphicsPaintEngine::macDisplayColorSpace(const QWidget *widget)
       
   323 {
       
   324     CGColorSpaceRef colorSpace;
       
   325 
       
   326     CGDirectDisplayID displayID;
       
   327     CMProfileRef displayProfile = 0;
       
   328     if (widget == 0) {
       
   329         displayID = CGMainDisplayID();
       
   330     } else {
       
   331         const QRect &qrect = widget->window()->geometry();
       
   332         CGRect rect = CGRectMake(qrect.x(), qrect.y(), qrect.width(), qrect.height());
       
   333         CGDisplayCount throwAway;
       
   334         CGDisplayErr dErr = CGGetDisplaysWithRect(rect, 1, &displayID, &throwAway);
       
   335         if (dErr != kCGErrorSuccess)
       
   336             return macDisplayColorSpace(0); // fall back on main display
       
   337     }
       
   338     if ((colorSpace = m_displayColorSpaceHash.value(displayID)))
       
   339         return colorSpace;
       
   340 
       
   341     CMError err = CMGetProfileByAVID((CMDisplayIDType)displayID, &displayProfile);
       
   342     if (err == noErr) {
       
   343         colorSpace = CGColorSpaceCreateWithPlatformColorSpace(displayProfile);
       
   344     } else if (widget) {
       
   345         return macDisplayColorSpace(0); // fall back on main display
       
   346     }
       
   347 
       
   348     if (colorSpace == 0)
       
   349         colorSpace = CGColorSpaceCreateDeviceRGB();
       
   350 
       
   351     m_displayColorSpaceHash.insert(displayID, colorSpace);
       
   352     CMCloseProfile(displayProfile);
       
   353     if (!m_postRoutineRegistered) {
       
   354         m_postRoutineRegistered = true;
       
   355         qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces);
       
   356     }
       
   357     return colorSpace;
       
   358 }
       
   359 
       
   360 void QCoreGraphicsPaintEngine::cleanUpMacColorSpaces()
       
   361 {
       
   362     if (m_genericColorSpace) {
       
   363         CFRelease(m_genericColorSpace);
       
   364         m_genericColorSpace = 0;
       
   365     }
       
   366     QHash<CGDirectDisplayID, CGColorSpaceRef>::const_iterator it = m_displayColorSpaceHash.constBegin();
       
   367     while (it != m_displayColorSpaceHash.constEnd()) {
       
   368         if (it.value())
       
   369             CFRelease(it.value());
       
   370         ++it;
       
   371     }
       
   372     m_displayColorSpaceHash.clear();
       
   373 }
       
   374 
       
   375 void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform)
       
   376 {
       
   377     CGAffineTransform old_xform = CGAffineTransformIdentity;
       
   378     if(orig_xform) { //setup xforms
       
   379         old_xform = CGContextGetCTM(hd);
       
   380         CGContextConcatCTM(hd, CGAffineTransformInvert(old_xform));
       
   381         CGContextConcatCTM(hd, *orig_xform);
       
   382     }
       
   383 
       
   384     //do the clipping
       
   385     CGContextBeginPath(hd);
       
   386     if(rgn.isEmpty()) {
       
   387         CGContextAddRect(hd, CGRectMake(0, 0, 0, 0));
       
   388     } else {
       
   389 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
       
   390         if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
       
   391             QCFType<HIMutableShapeRef> shape = rgn.toHIMutableShape();
       
   392             Q_ASSERT(!HIShapeIsEmpty(shape));
       
   393             HIShapeReplacePathInCGContext(shape, hd);
       
   394         } else
       
   395 #endif
       
   396         {
       
   397             QVector<QRect> rects = rgn.rects();
       
   398             const int count = rects.size();
       
   399             for(int i = 0; i < count; i++) {
       
   400                 const QRect &r = rects[i];
       
   401                 CGRect mac_r = CGRectMake(r.x(), r.y(), r.width(), r.height());
       
   402                 CGContextAddRect(hd, mac_r);
       
   403             }
       
   404         }
       
   405 
       
   406     }
       
   407     CGContextClip(hd);
       
   408 
       
   409     if(orig_xform) {//reset xforms
       
   410         CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd)));
       
   411         CGContextConcatCTM(hd, old_xform);
       
   412     }
       
   413 }
       
   414 
       
   415 
       
   416 //pattern handling (tiling)
       
   417 #if 1
       
   418 #  define QMACPATTERN_MASK_MULTIPLIER 32
       
   419 #else
       
   420 #  define QMACPATTERN_MASK_MULTIPLIER 1
       
   421 #endif
       
   422 class QMacPattern
       
   423 {
       
   424 public:
       
   425     QMacPattern() : as_mask(false), pdev(0), image(0) { data.bytes = 0; }
       
   426     ~QMacPattern() { CGImageRelease(image); }
       
   427     int width() {
       
   428         if(image)
       
   429             return CGImageGetWidth(image);
       
   430         if(data.bytes)
       
   431             return 8*QMACPATTERN_MASK_MULTIPLIER;
       
   432         return data.pixmap.width();
       
   433     }
       
   434     int height() {
       
   435         if(image)
       
   436             return CGImageGetHeight(image);
       
   437         if(data.bytes)
       
   438             return 8*QMACPATTERN_MASK_MULTIPLIER;
       
   439         return data.pixmap.height();
       
   440     }
       
   441 
       
   442     //input
       
   443     QColor foreground;
       
   444     bool as_mask;
       
   445     struct {
       
   446         QPixmap pixmap;
       
   447         const uchar *bytes;
       
   448     } data;
       
   449     QPaintDevice *pdev;
       
   450     //output
       
   451     CGImageRef image;
       
   452 };
       
   453 static void qt_mac_draw_pattern(void *info, CGContextRef c)
       
   454 {
       
   455     QMacPattern *pat = (QMacPattern*)info;
       
   456     int w = 0, h = 0;
       
   457     bool isBitmap = (pat->data.pixmap.depth() == 1);
       
   458     if(!pat->image) { //lazy cache
       
   459         if(pat->as_mask) {
       
   460             Q_ASSERT(pat->data.bytes);
       
   461             w = h = 8;
       
   462 #if (QMACPATTERN_MASK_MULTIPLIER == 1)
       
   463             CGDataProviderRef provider = CGDataProviderCreateWithData(0, pat->data.bytes, w*h, 0);
       
   464             pat->image = CGImageMaskCreate(w, h, 1, 1, 1, provider, 0, false);
       
   465             CGDataProviderRelease(provider);
       
   466 #else
       
   467             const int numBytes = (w*h)/sizeof(uchar);
       
   468             uchar xor_bytes[numBytes];
       
   469             for(int i = 0; i < numBytes; ++i)
       
   470                 xor_bytes[i] = pat->data.bytes[i] ^ 0xFF;
       
   471             CGDataProviderRef provider = CGDataProviderCreateWithData(0, xor_bytes, w*h, 0);
       
   472             CGImageRef swatch = CGImageMaskCreate(w, h, 1, 1, 1, provider, 0, false);
       
   473             CGDataProviderRelease(provider);
       
   474 
       
   475             const QColor c0(0, 0, 0, 0), c1(255, 255, 255, 255);
       
   476             QPixmap pm(w*QMACPATTERN_MASK_MULTIPLIER, h*QMACPATTERN_MASK_MULTIPLIER);
       
   477             pm.fill(c0);
       
   478             CGContextRef pm_ctx = qt_mac_cg_context(&pm);
       
   479             CGContextSetFillColorWithColor(c, cgColorForQColor(c1, pat->pdev));
       
   480             CGRect rect = CGRectMake(0, 0, w, h);
       
   481             for(int x = 0; x < QMACPATTERN_MASK_MULTIPLIER; ++x) {
       
   482                 rect.origin.x = x * w;
       
   483                 for(int y = 0; y < QMACPATTERN_MASK_MULTIPLIER; ++y) {
       
   484                     rect.origin.y = y * h;
       
   485                     qt_mac_drawCGImage(pm_ctx, &rect, swatch);
       
   486                 }
       
   487             }
       
   488             pat->image = qt_mac_create_imagemask(pm, pm.rect());
       
   489             CGImageRelease(swatch);
       
   490             CGContextRelease(pm_ctx);
       
   491             w *= QMACPATTERN_MASK_MULTIPLIER;
       
   492             h *= QMACPATTERN_MASK_MULTIPLIER;
       
   493 #endif
       
   494         } else {
       
   495             w = pat->data.pixmap.width();
       
   496             h = pat->data.pixmap.height();
       
   497             if (isBitmap)
       
   498                 pat->image = qt_mac_create_imagemask(pat->data.pixmap, pat->data.pixmap.rect());
       
   499             else
       
   500                 pat->image = (CGImageRef)pat->data.pixmap.macCGHandle();
       
   501         }
       
   502     } else {
       
   503         w = CGImageGetWidth(pat->image);
       
   504         h = CGImageGetHeight(pat->image);
       
   505     }
       
   506 
       
   507     //draw
       
   508     bool needRestore = false;
       
   509     if (CGImageIsMask(pat->image)) {
       
   510         CGContextSaveGState(c);
       
   511         CGContextSetFillColorWithColor(c, cgColorForQColor(pat->foreground, pat->pdev));
       
   512     }
       
   513     CGRect rect = CGRectMake(0, 0, w, h);
       
   514     qt_mac_drawCGImage(c, &rect, pat->image);
       
   515     if(needRestore)
       
   516         CGContextRestoreGState(c);
       
   517 }
       
   518 static void qt_mac_dispose_pattern(void *info)
       
   519 {
       
   520     QMacPattern *pat = (QMacPattern*)info;
       
   521     delete pat;
       
   522 }
       
   523 
       
   524 /*****************************************************************************
       
   525   QCoreGraphicsPaintEngine member functions
       
   526  *****************************************************************************/
       
   527 
       
   528 inline static QPaintEngine::PaintEngineFeatures qt_mac_cg_features()
       
   529 {
       
   530     return QPaintEngine::PaintEngineFeatures(QPaintEngine::AllFeatures & ~QPaintEngine::PaintOutsidePaintEvent
       
   531                                               & ~QPaintEngine::PerspectiveTransform
       
   532                                               & ~QPaintEngine::ConicalGradientFill
       
   533                                               & ~QPaintEngine::LinearGradientFill
       
   534                                               & ~QPaintEngine::RadialGradientFill
       
   535                                               & ~QPaintEngine::BrushStroke);
       
   536 }
       
   537 
       
   538 QCoreGraphicsPaintEngine::QCoreGraphicsPaintEngine()
       
   539 : QPaintEngine(*(new QCoreGraphicsPaintEnginePrivate), qt_mac_cg_features())
       
   540 {
       
   541 }
       
   542 
       
   543 QCoreGraphicsPaintEngine::QCoreGraphicsPaintEngine(QPaintEnginePrivate &dptr)
       
   544 : QPaintEngine(dptr, qt_mac_cg_features())
       
   545 {
       
   546 }
       
   547 
       
   548 QCoreGraphicsPaintEngine::~QCoreGraphicsPaintEngine()
       
   549 {
       
   550 }
       
   551 
       
   552 bool
       
   553 QCoreGraphicsPaintEngine::begin(QPaintDevice *pdev)
       
   554 {
       
   555     Q_D(QCoreGraphicsPaintEngine);
       
   556     if(isActive()) {                         // already active painting
       
   557         qWarning("QCoreGraphicsPaintEngine::begin: Painter already active");
       
   558         return false;
       
   559     }
       
   560 
       
   561     //initialization
       
   562     d->pdev = pdev;
       
   563     d->complexXForm = false;
       
   564     d->cosmeticPen = QCoreGraphicsPaintEnginePrivate::CosmeticSetPenWidth;
       
   565     d->cosmeticPenSize = 1;
       
   566     d->current.clipEnabled = false;
       
   567     d->pixelSize = QPoint(1,1);
       
   568     d->hd = qt_mac_cg_context(pdev);
       
   569     if(d->hd) {
       
   570         d->saveGraphicsState();
       
   571         d->orig_xform = CGContextGetCTM(d->hd);
       
   572         if (d->shading) {
       
   573             CGShadingRelease(d->shading);
       
   574             d->shading = 0;
       
   575         }
       
   576         d->setClip(0);  //clear the context's clipping
       
   577     }
       
   578 
       
   579     setActive(true);
       
   580 
       
   581     if(d->pdev->devType() == QInternal::Widget) {                    // device is a widget
       
   582         QWidget *w = (QWidget*)d->pdev;
       
   583         bool unclipped = w->testAttribute(Qt::WA_PaintUnclipped);
       
   584 
       
   585         if((w->windowType() == Qt::Desktop)) {
       
   586             if(!unclipped)
       
   587                 qWarning("QCoreGraphicsPaintEngine::begin: Does not support clipped desktop on Mac OS X");
       
   588             // ## need to do [qt_mac_window_for(w) makeKeyAndOrderFront]; (need to rename the file)
       
   589         } else if(unclipped) {
       
   590             qWarning("QCoreGraphicsPaintEngine::begin: Does not support unclipped painting");
       
   591         }
       
   592     } else if(d->pdev->devType() == QInternal::Pixmap) {             // device is a pixmap
       
   593         QPixmap *pm = (QPixmap*)d->pdev;
       
   594         if(pm->isNull()) {
       
   595             qWarning("QCoreGraphicsPaintEngine::begin: Cannot paint null pixmap");
       
   596             end();
       
   597             return false;
       
   598         }
       
   599     }
       
   600 
       
   601     setDirty(QPaintEngine::DirtyPen);
       
   602     setDirty(QPaintEngine::DirtyBrush);
       
   603     setDirty(QPaintEngine::DirtyBackground);
       
   604     setDirty(QPaintEngine::DirtyHints);
       
   605     return true;
       
   606 }
       
   607 
       
   608 bool
       
   609 QCoreGraphicsPaintEngine::end()
       
   610 {
       
   611     Q_D(QCoreGraphicsPaintEngine);
       
   612     setActive(false);
       
   613     if(d->pdev->devType() == QInternal::Widget && static_cast<QWidget*>(d->pdev)->windowType() == Qt::Desktop) {
       
   614 #ifndef QT_MAC_USE_COCOA
       
   615         HideWindow(qt_mac_window_for(static_cast<QWidget*>(d->pdev)));
       
   616 #else
       
   617 //        // ### need to do [qt_mac_window_for(static_cast<QWidget *>(d->pdev)) orderOut]; (need to rename)
       
   618 #endif
       
   619 
       
   620 	}
       
   621     if(d->shading) {
       
   622         CGShadingRelease(d->shading);
       
   623         d->shading = 0;
       
   624     }
       
   625     d->pdev = 0;
       
   626     if(d->hd) {
       
   627         d->restoreGraphicsState();
       
   628         CGContextSynchronize(d->hd);
       
   629         CGContextRelease(d->hd);
       
   630         d->hd = 0;
       
   631     }
       
   632     return true;
       
   633 }
       
   634 
       
   635 void
       
   636 QCoreGraphicsPaintEngine::updateState(const QPaintEngineState &state)
       
   637 {
       
   638     Q_D(QCoreGraphicsPaintEngine);
       
   639     QPaintEngine::DirtyFlags flags = state.state();
       
   640 
       
   641     if (flags & DirtyTransform)
       
   642         updateMatrix(state.transform());
       
   643 
       
   644     if (flags & DirtyClipEnabled) {
       
   645         if (state.isClipEnabled())
       
   646             updateClipPath(painter()->clipPath(), Qt::ReplaceClip);
       
   647         else
       
   648             updateClipPath(QPainterPath(), Qt::NoClip);
       
   649     }
       
   650 
       
   651     if (flags & DirtyClipPath) {
       
   652         updateClipPath(state.clipPath(), state.clipOperation());
       
   653     } else if (flags & DirtyClipRegion) {
       
   654         updateClipRegion(state.clipRegion(), state.clipOperation());
       
   655     }
       
   656 
       
   657     // If the clip has changed we need to update all other states
       
   658     // too, since they are included in the system context on OSX,
       
   659     // and changing the clip resets that context back to scratch.
       
   660     if (flags & (DirtyClipPath | DirtyClipRegion | DirtyClipEnabled))
       
   661         flags |= AllDirty;
       
   662 
       
   663     if (flags & DirtyPen)
       
   664         updatePen(state.pen());
       
   665     if (flags & (DirtyBrush|DirtyBrushOrigin))
       
   666         updateBrush(state.brush(), state.brushOrigin());
       
   667     if (flags & DirtyFont)
       
   668         updateFont(state.font());
       
   669     if (flags & DirtyOpacity)
       
   670         updateOpacity(state.opacity());
       
   671     if (flags & DirtyHints)
       
   672         updateRenderHints(state.renderHints());
       
   673     if (flags & DirtyCompositionMode)
       
   674         updateCompositionMode(state.compositionMode());
       
   675 
       
   676     if (flags & (DirtyPen | DirtyTransform)) {
       
   677         if (!d->current.pen.isCosmetic()) {
       
   678             d->cosmeticPen = QCoreGraphicsPaintEnginePrivate::CosmeticNone;
       
   679         } else if (d->current.transform.m11() < d->current.transform.m22()-1.0 ||
       
   680                   d->current.transform.m11() > d->current.transform.m22()+1.0) {
       
   681             d->cosmeticPen = QCoreGraphicsPaintEnginePrivate::CosmeticTransformPath;
       
   682             d->cosmeticPenSize = d->adjustPenWidth(d->current.pen.widthF());
       
   683             if (!d->cosmeticPenSize)
       
   684                 d->cosmeticPenSize = 1.0;
       
   685         } else {
       
   686             d->cosmeticPen = QCoreGraphicsPaintEnginePrivate::CosmeticSetPenWidth;
       
   687             static const float sqrt2 = sqrt(2);
       
   688             qreal width = d->current.pen.widthF();
       
   689             if (!width)
       
   690                 width = 1;
       
   691             d->cosmeticPenSize = sqrt(pow(d->pixelSize.y(), 2) + pow(d->pixelSize.x(), 2)) / sqrt2 * width;
       
   692         }
       
   693     }
       
   694 }
       
   695 
       
   696 void
       
   697 QCoreGraphicsPaintEngine::updatePen(const QPen &pen)
       
   698 {
       
   699     Q_D(QCoreGraphicsPaintEngine);
       
   700     Q_ASSERT(isActive());
       
   701     d->current.pen = pen;
       
   702     d->setStrokePen(pen);
       
   703 }
       
   704 
       
   705 void
       
   706 QCoreGraphicsPaintEngine::updateBrush(const QBrush &brush, const QPointF &brushOrigin)
       
   707 {
       
   708     Q_D(QCoreGraphicsPaintEngine);
       
   709     Q_ASSERT(isActive());
       
   710     d->current.brush = brush;
       
   711 
       
   712 #ifdef QT_MAC_USE_NATIVE_GRADIENTS
       
   713     // Quartz supports only pad spread
       
   714     if (const QGradient *gradient = brush.gradient()) {
       
   715         if (drawGradientNatively(gradient)) {
       
   716             gccaps |= QPaintEngine::LinearGradientFill | QPaintEngine::RadialGradientFill;
       
   717         } else {
       
   718             gccaps &= ~(QPaintEngine::LinearGradientFill | QPaintEngine::RadialGradientFill);
       
   719         }
       
   720     }
       
   721 #endif
       
   722 
       
   723     if (d->shading) {
       
   724         CGShadingRelease(d->shading);
       
   725         d->shading = 0;
       
   726     }
       
   727     d->setFillBrush(brushOrigin);
       
   728 }
       
   729 
       
   730 void
       
   731 QCoreGraphicsPaintEngine::updateOpacity(qreal opacity)
       
   732 {
       
   733     Q_D(QCoreGraphicsPaintEngine);
       
   734     CGContextSetAlpha(d->hd, opacity);
       
   735 }
       
   736 
       
   737 void
       
   738 QCoreGraphicsPaintEngine::updateFont(const QFont &)
       
   739 {
       
   740     Q_D(QCoreGraphicsPaintEngine);
       
   741     Q_ASSERT(isActive());
       
   742     updatePen(d->current.pen);
       
   743 }
       
   744 
       
   745 void
       
   746 QCoreGraphicsPaintEngine::updateMatrix(const QTransform &transform)
       
   747 {
       
   748     Q_D(QCoreGraphicsPaintEngine);
       
   749     Q_ASSERT(isActive());
       
   750 
       
   751     if (qt_is_nan(transform.m11()) || qt_is_nan(transform.m12()) || qt_is_nan(transform.m13())
       
   752 	|| qt_is_nan(transform.m21()) || qt_is_nan(transform.m22()) || qt_is_nan(transform.m23())
       
   753 	|| qt_is_nan(transform.m31()) || qt_is_nan(transform.m32()) || qt_is_nan(transform.m33()))
       
   754 	return;
       
   755 
       
   756     d->current.transform = transform;
       
   757     d->setTransform(transform.isIdentity() ? 0 : &transform);
       
   758     d->complexXForm = (transform.m11() != 1 || transform.m22() != 1
       
   759             || transform.m12() != 0 || transform.m21() != 0);
       
   760     d->pixelSize = d->devicePixelSize(d->hd);
       
   761 }
       
   762 
       
   763 void
       
   764 QCoreGraphicsPaintEngine::updateClipPath(const QPainterPath &p, Qt::ClipOperation op)
       
   765 {
       
   766     Q_D(QCoreGraphicsPaintEngine);
       
   767     Q_ASSERT(isActive());
       
   768     if(op == Qt::NoClip) {
       
   769         if(d->current.clipEnabled) {
       
   770             d->current.clipEnabled = false;
       
   771             d->current.clip = QRegion();
       
   772             d->setClip(0);
       
   773         }
       
   774     } else {
       
   775         if(!d->current.clipEnabled)
       
   776             op = Qt::ReplaceClip;
       
   777         d->current.clipEnabled = true;
       
   778         QRegion clipRegion(p.toFillPolygon().toPolygon(), p.fillRule());
       
   779         if(op == Qt::ReplaceClip) {
       
   780             d->current.clip = clipRegion;
       
   781             d->setClip(0);
       
   782             if(p.isEmpty()) {
       
   783                 CGRect rect = CGRectMake(0, 0, 0, 0);
       
   784                 CGContextClipToRect(d->hd, rect);
       
   785             } else {
       
   786                 CGMutablePathRef path = qt_mac_compose_path(p);
       
   787                 CGContextBeginPath(d->hd);
       
   788                 CGContextAddPath(d->hd, path);
       
   789                 if(p.fillRule() == Qt::WindingFill)
       
   790                     CGContextClip(d->hd);
       
   791                 else
       
   792                     CGContextEOClip(d->hd);
       
   793                 CGPathRelease(path);
       
   794             }
       
   795         } else if(op == Qt::IntersectClip) {
       
   796             d->current.clip = d->current.clip.intersected(clipRegion);
       
   797             d->setClip(&d->current.clip);
       
   798         } else if(op == Qt::UniteClip) {
       
   799             d->current.clip = d->current.clip.united(clipRegion);
       
   800             d->setClip(&d->current.clip);
       
   801         }
       
   802     }
       
   803 }
       
   804 
       
   805 void
       
   806 QCoreGraphicsPaintEngine::updateClipRegion(const QRegion &clipRegion, Qt::ClipOperation op)
       
   807 {
       
   808     Q_D(QCoreGraphicsPaintEngine);
       
   809     Q_ASSERT(isActive());
       
   810     if(op == Qt::NoClip) {
       
   811         d->current.clipEnabled = false;
       
   812         d->current.clip = QRegion();
       
   813         d->setClip(0);
       
   814     } else {
       
   815         if(!d->current.clipEnabled)
       
   816             op = Qt::ReplaceClip;
       
   817         d->current.clipEnabled = true;
       
   818         if(op == Qt::IntersectClip)
       
   819             d->current.clip = d->current.clip.intersected(clipRegion);
       
   820         else if(op == Qt::ReplaceClip)
       
   821             d->current.clip = clipRegion;
       
   822         else if(op == Qt::UniteClip)
       
   823             d->current.clip = d->current.clip.united(clipRegion);
       
   824         d->setClip(&d->current.clip);
       
   825     }
       
   826 }
       
   827 
       
   828 void
       
   829 QCoreGraphicsPaintEngine::drawPath(const QPainterPath &p)
       
   830 {
       
   831     Q_D(QCoreGraphicsPaintEngine);
       
   832     Q_ASSERT(isActive());
       
   833 
       
   834     if (state->compositionMode() == QPainter::CompositionMode_Destination)
       
   835         return;
       
   836 
       
   837     CGMutablePathRef path = qt_mac_compose_path(p);
       
   838     uchar ops = QCoreGraphicsPaintEnginePrivate::CGStroke;
       
   839     if(p.fillRule() == Qt::WindingFill)
       
   840         ops |= QCoreGraphicsPaintEnginePrivate::CGFill;
       
   841     else
       
   842         ops |= QCoreGraphicsPaintEnginePrivate::CGEOFill;
       
   843     CGContextBeginPath(d->hd);
       
   844     d->drawPath(ops, path);
       
   845     CGPathRelease(path);
       
   846 }
       
   847 
       
   848 void
       
   849 QCoreGraphicsPaintEngine::drawRects(const QRectF *rects, int rectCount)
       
   850 {
       
   851     Q_D(QCoreGraphicsPaintEngine);
       
   852     Q_ASSERT(isActive());
       
   853 
       
   854     if (state->compositionMode() == QPainter::CompositionMode_Destination)
       
   855         return;
       
   856 
       
   857     for (int i=0; i<rectCount; ++i) {
       
   858         QRectF r = rects[i];
       
   859 
       
   860         CGMutablePathRef path = CGPathCreateMutable();
       
   861         CGPathAddRect(path, 0, qt_mac_compose_rect(r));
       
   862         d->drawPath(QCoreGraphicsPaintEnginePrivate::CGFill|QCoreGraphicsPaintEnginePrivate::CGStroke,
       
   863                 path);
       
   864         CGPathRelease(path);
       
   865     }
       
   866 }
       
   867 
       
   868 void
       
   869 QCoreGraphicsPaintEngine::drawPoints(const QPointF *points, int pointCount)
       
   870 {
       
   871     Q_D(QCoreGraphicsPaintEngine);
       
   872     Q_ASSERT(isActive());
       
   873 
       
   874     if (state->compositionMode() == QPainter::CompositionMode_Destination)
       
   875         return;
       
   876 
       
   877     if (d->current.pen.capStyle() == Qt::FlatCap)
       
   878         CGContextSetLineCap(d->hd, kCGLineCapSquare);
       
   879 
       
   880     CGMutablePathRef path = CGPathCreateMutable();
       
   881     for(int i=0; i < pointCount; i++) {
       
   882         float x = points[i].x(), y = points[i].y();
       
   883         CGPathMoveToPoint(path, 0, x, y);
       
   884         CGPathAddLineToPoint(path, 0, x+0.001, y);
       
   885     }
       
   886 
       
   887     bool doRestore = false;
       
   888     if(d->cosmeticPen == QCoreGraphicsPaintEnginePrivate::CosmeticNone && !(state->renderHints() & QPainter::Antialiasing)) {
       
   889         //we don't want adjusted pens for point rendering
       
   890         doRestore = true;
       
   891         d->saveGraphicsState();
       
   892         CGContextSetLineWidth(d->hd, d->current.pen.widthF());
       
   893     }
       
   894     d->drawPath(QCoreGraphicsPaintEnginePrivate::CGStroke, path);
       
   895     if (doRestore)
       
   896         d->restoreGraphicsState();
       
   897     CGPathRelease(path);
       
   898     if (d->current.pen.capStyle() == Qt::FlatCap)
       
   899         CGContextSetLineCap(d->hd, kCGLineCapButt);
       
   900 }
       
   901 
       
   902 void
       
   903 QCoreGraphicsPaintEngine::drawEllipse(const QRectF &r)
       
   904 {
       
   905     Q_D(QCoreGraphicsPaintEngine);
       
   906     Q_ASSERT(isActive());
       
   907 
       
   908     if (state->compositionMode() == QPainter::CompositionMode_Destination)
       
   909         return;
       
   910 
       
   911     CGMutablePathRef path = CGPathCreateMutable();
       
   912     CGAffineTransform transform = CGAffineTransformMakeScale(r.width() / r.height(), 1);
       
   913     CGPathAddArc(path, &transform,(r.x() + (r.width() / 2)) / (r.width() / r.height()),
       
   914             r.y() + (r.height() / 2), r.height() / 2, 0, (2 * M_PI), false);
       
   915     d->drawPath(QCoreGraphicsPaintEnginePrivate::CGFill | QCoreGraphicsPaintEnginePrivate::CGStroke,
       
   916             path);
       
   917     CGPathRelease(path);
       
   918 }
       
   919 
       
   920 void
       
   921 QCoreGraphicsPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
       
   922 {
       
   923     Q_D(QCoreGraphicsPaintEngine);
       
   924     Q_ASSERT(isActive());
       
   925 
       
   926     if (state->compositionMode() == QPainter::CompositionMode_Destination)
       
   927         return;
       
   928 
       
   929     CGMutablePathRef path = CGPathCreateMutable();
       
   930     CGPathMoveToPoint(path, 0, points[0].x(), points[0].y());
       
   931     for(int x = 1; x < pointCount; ++x)
       
   932         CGPathAddLineToPoint(path, 0, points[x].x(), points[x].y());
       
   933     if(mode != PolylineMode && points[0] != points[pointCount-1])
       
   934         CGPathAddLineToPoint(path, 0, points[0].x(), points[0].y());
       
   935     uint op = QCoreGraphicsPaintEnginePrivate::CGStroke;
       
   936     if (mode != PolylineMode)
       
   937         op |= mode == OddEvenMode ? QCoreGraphicsPaintEnginePrivate::CGEOFill
       
   938             : QCoreGraphicsPaintEnginePrivate::CGFill;
       
   939     d->drawPath(op, path);
       
   940     CGPathRelease(path);
       
   941 }
       
   942 
       
   943 void
       
   944 QCoreGraphicsPaintEngine::drawLines(const QLineF *lines, int lineCount)
       
   945 {
       
   946     Q_D(QCoreGraphicsPaintEngine);
       
   947     Q_ASSERT(isActive());
       
   948 
       
   949     if (state->compositionMode() == QPainter::CompositionMode_Destination)
       
   950         return;
       
   951 
       
   952     CGMutablePathRef path = CGPathCreateMutable();
       
   953     for(int i = 0; i < lineCount; i++) {
       
   954         const QPointF start = lines[i].p1(), end = lines[i].p2();
       
   955         CGPathMoveToPoint(path, 0, start.x(), start.y());
       
   956         CGPathAddLineToPoint(path, 0, end.x(), end.y());
       
   957     }
       
   958     d->drawPath(QCoreGraphicsPaintEnginePrivate::CGStroke, path);
       
   959     CGPathRelease(path);
       
   960 }
       
   961 
       
   962 void QCoreGraphicsPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
       
   963 {
       
   964     Q_D(QCoreGraphicsPaintEngine);
       
   965     Q_ASSERT(isActive());
       
   966 
       
   967     if (state->compositionMode() == QPainter::CompositionMode_Destination)
       
   968         return;
       
   969 
       
   970     if(pm.isNull())
       
   971         return;
       
   972 
       
   973     bool differentSize = (QRectF(0, 0, pm.width(), pm.height()) != sr), doRestore = false;
       
   974     CGRect rect = CGRectMake(qRound(r.x()), qRound(r.y()), qRound(r.width()), qRound(r.height()));
       
   975     QCFType<CGImageRef> image;
       
   976     bool isBitmap = (pm.depth() == 1);
       
   977     if (isBitmap) {
       
   978         doRestore = true;
       
   979         d->saveGraphicsState();
       
   980 
       
   981         const QColor &col = d->current.pen.color();
       
   982         CGContextSetFillColorWithColor(d->hd, cgColorForQColor(col, d->pdev));
       
   983         image = qt_mac_create_imagemask(pm, sr);
       
   984     } else if (differentSize) {
       
   985         QCFType<CGImageRef> img = pm.toMacCGImageRef();
       
   986         image = CGImageCreateWithImageInRect(img, CGRectMake(qRound(sr.x()), qRound(sr.y()), qRound(sr.width()), qRound(sr.height())));
       
   987     } else {
       
   988         image = (CGImageRef)pm.macCGHandle();
       
   989     }
       
   990     qt_mac_drawCGImage(d->hd, &rect, image);
       
   991     if (doRestore)
       
   992         d->restoreGraphicsState();
       
   993 }
       
   994 
       
   995 static void drawImageReleaseData (void *info, const void *, size_t)
       
   996 {
       
   997     delete static_cast<QImage *>(info);
       
   998 }
       
   999 
       
  1000 CGImageRef qt_mac_createCGImageFromQImage(const QImage &img, const QImage **imagePtr = 0)
       
  1001 {
       
  1002     QImage *image;
       
  1003     if (img.depth() != 32)
       
  1004         image = new QImage(img.convertToFormat(QImage::Format_ARGB32_Premultiplied));
       
  1005     else
       
  1006         image = new QImage(img);
       
  1007 
       
  1008     uint cgflags = kCGImageAlphaNone;
       
  1009     switch (image->format()) {
       
  1010     case QImage::Format_ARGB32_Premultiplied:
       
  1011         cgflags = kCGImageAlphaPremultipliedFirst;
       
  1012         break;
       
  1013     case QImage::Format_ARGB32:
       
  1014         cgflags = kCGImageAlphaFirst;
       
  1015         break;
       
  1016     case QImage::Format_RGB32:
       
  1017         cgflags = kCGImageAlphaNoneSkipFirst;
       
  1018     default:
       
  1019         break;
       
  1020     }
       
  1021 #if defined(kCGBitmapByteOrder32Host) //only needed because CGImage.h added symbols in the minor version
       
  1022     cgflags |= kCGBitmapByteOrder32Host;
       
  1023 #endif
       
  1024     QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(image,
       
  1025                                                           static_cast<const QImage *>(image)->bits(),
       
  1026                                                           image->numBytes(),
       
  1027                                                           drawImageReleaseData);
       
  1028     if (imagePtr)
       
  1029         *imagePtr = image;
       
  1030     return CGImageCreate(image->width(), image->height(), 8, 32,
       
  1031                                         image->bytesPerLine(),
       
  1032                                         QCoreGraphicsPaintEngine::macGenericColorSpace(),
       
  1033                                         cgflags, dataProvider, 0, false, kCGRenderingIntentDefault);
       
  1034 
       
  1035 }
       
  1036 
       
  1037 void QCoreGraphicsPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRectF &sr,
       
  1038                                          Qt::ImageConversionFlags flags)
       
  1039 {
       
  1040     Q_D(QCoreGraphicsPaintEngine);
       
  1041     Q_UNUSED(flags);
       
  1042     Q_ASSERT(isActive());
       
  1043 
       
  1044     if (img.isNull() || state->compositionMode() == QPainter::CompositionMode_Destination)
       
  1045         return;
       
  1046 
       
  1047     const QImage *image;
       
  1048     QCFType<CGImageRef> cgimage = qt_mac_createCGImageFromQImage(img, &image);
       
  1049     CGRect rect = CGRectMake(r.x(), r.y(), r.width(), r.height());
       
  1050     if (QRectF(0, 0, img.width(), img.height()) != sr)
       
  1051         cgimage = CGImageCreateWithImageInRect(cgimage, CGRectMake(sr.x(), sr.y(),
       
  1052                                                sr.width(), sr.height()));
       
  1053     qt_mac_drawCGImage(d->hd, &rect, cgimage);
       
  1054 }
       
  1055 
       
  1056 void QCoreGraphicsPaintEngine::initialize()
       
  1057 {
       
  1058 }
       
  1059 
       
  1060 void QCoreGraphicsPaintEngine::cleanup()
       
  1061 {
       
  1062 }
       
  1063 
       
  1064 CGContextRef
       
  1065 QCoreGraphicsPaintEngine::handle() const
       
  1066 {
       
  1067     return d_func()->hd;
       
  1068 }
       
  1069 
       
  1070 void
       
  1071 QCoreGraphicsPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap,
       
  1072         const QPointF &p)
       
  1073 {
       
  1074     Q_D(QCoreGraphicsPaintEngine);
       
  1075     Q_ASSERT(isActive());
       
  1076 
       
  1077     if (state->compositionMode() == QPainter::CompositionMode_Destination)
       
  1078         return;
       
  1079 
       
  1080     //save the old state
       
  1081     d->saveGraphicsState();
       
  1082 
       
  1083     //setup the pattern
       
  1084     QMacPattern *qpattern = new QMacPattern;
       
  1085     qpattern->data.pixmap = pixmap;
       
  1086     qpattern->foreground = d->current.pen.color();
       
  1087     qpattern->pdev = d->pdev;
       
  1088     CGPatternCallbacks callbks;
       
  1089     callbks.version = 0;
       
  1090     callbks.drawPattern = qt_mac_draw_pattern;
       
  1091     callbks.releaseInfo = qt_mac_dispose_pattern;
       
  1092     const int width = qpattern->width(), height = qpattern->height();
       
  1093     CGAffineTransform trans = CGContextGetCTM(d->hd);
       
  1094     CGPatternRef pat = CGPatternCreate(qpattern, CGRectMake(0, 0, width, height),
       
  1095             trans, width, height,
       
  1096             kCGPatternTilingNoDistortion, true, &callbks);
       
  1097     CGColorSpaceRef cs = CGColorSpaceCreatePattern(0);
       
  1098     CGContextSetFillColorSpace(d->hd, cs);
       
  1099     CGFloat component = 1.0; //just one
       
  1100     CGContextSetFillPattern(d->hd, pat, &component);
       
  1101     CGSize phase = CGSizeApplyAffineTransform(CGSizeMake(-(p.x()-r.x()), -(p.y()-r.y())), trans);
       
  1102     CGContextSetPatternPhase(d->hd, phase);
       
  1103 
       
  1104     //fill the rectangle
       
  1105     CGRect mac_rect = CGRectMake(r.x(), r.y(), r.width(), r.height());
       
  1106     CGContextFillRect(d->hd, mac_rect);
       
  1107 
       
  1108     //restore the state
       
  1109     d->restoreGraphicsState();
       
  1110     //cleanup
       
  1111     CGColorSpaceRelease(cs);
       
  1112     CGPatternRelease(pat);
       
  1113 }
       
  1114 
       
  1115 void QCoreGraphicsPaintEngine::drawTextItem(const QPointF &pos, const QTextItem &item)
       
  1116 {
       
  1117     Q_D(QCoreGraphicsPaintEngine);
       
  1118     if (d->current.transform.type() == QTransform::TxProject
       
  1119 #ifndef QMAC_NATIVE_GRADIENTS
       
  1120         || painter()->pen().brush().gradient()  //Just let the base engine "emulate" the gradient
       
  1121 #endif
       
  1122         ) {
       
  1123         QPaintEngine::drawTextItem(pos, item);
       
  1124         return;
       
  1125     }
       
  1126 
       
  1127     if (state->compositionMode() == QPainter::CompositionMode_Destination)
       
  1128         return;
       
  1129 
       
  1130     const QTextItemInt &ti = static_cast<const QTextItemInt &>(item);
       
  1131 
       
  1132     QPen oldPen = painter()->pen();
       
  1133     QBrush oldBrush = painter()->brush();
       
  1134     QPointF oldBrushOrigin = painter()->brushOrigin();
       
  1135     updatePen(Qt::NoPen);
       
  1136     updateBrush(oldPen.brush(), QPointF(0, 0));
       
  1137 
       
  1138     Q_ASSERT(type() == QPaintEngine::CoreGraphics);
       
  1139 
       
  1140     QFontEngine *fe = ti.fontEngine;
       
  1141 
       
  1142     const bool textAA = state->renderHints() & QPainter::TextAntialiasing && fe->fontDef.pointSize > qt_antialiasing_threshold && !(fe->fontDef.styleStrategy & QFont::NoAntialias);
       
  1143     const bool lineAA = state->renderHints() & QPainter::Antialiasing;
       
  1144     if(textAA != lineAA)
       
  1145         CGContextSetShouldAntialias(d->hd, textAA);
       
  1146 
       
  1147     if (ti.glyphs.numGlyphs) {
       
  1148         switch (fe->type()) {
       
  1149         case QFontEngine::Mac:
       
  1150 #ifdef QT_MAC_USE_COCOA
       
  1151             static_cast<QCoreTextFontEngine *>(fe)->draw(d->hd, pos.x(), pos.y(), ti, paintDevice()->height());
       
  1152 #else
       
  1153             static_cast<QFontEngineMac *>(fe)->draw(d->hd, pos.x(), pos.y(), ti, paintDevice()->height());
       
  1154 #endif
       
  1155             break;
       
  1156         case QFontEngine::Box:
       
  1157             d->drawBoxTextItem(pos, ti);
       
  1158             break;
       
  1159         default:
       
  1160             break;
       
  1161         }
       
  1162     }
       
  1163 
       
  1164     if(textAA != lineAA)
       
  1165         CGContextSetShouldAntialias(d->hd, !textAA);
       
  1166 
       
  1167     updatePen(oldPen);
       
  1168     updateBrush(oldBrush, oldBrushOrigin);
       
  1169 }
       
  1170 
       
  1171 QPainter::RenderHints
       
  1172 QCoreGraphicsPaintEngine::supportedRenderHints() const
       
  1173 {
       
  1174     return QPainter::RenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
       
  1175 }
       
  1176 enum CGCompositeMode {
       
  1177         kCGCompositeModeClear            = 0,
       
  1178         kCGCompositeModeCopy             = 1,
       
  1179         kCGCompositeModeSourceOver       = 2,
       
  1180         kCGCompositeModeSourceIn         = 3,
       
  1181         kCGCompositeModeSourceOut        = 4,
       
  1182         kCGCompositeModeSourceAtop       = 5,
       
  1183         kCGCompositeModeDestinationOver  = 6,
       
  1184         kCGCompositeModeDestinationIn    = 7,
       
  1185         kCGCompositeModeDestinationOut   = 8,
       
  1186         kCGCompositeModeDestinationAtop  = 9,
       
  1187         kCGCompositeModeXOR              = 10,
       
  1188         kCGCompositeModePlusDarker       = 11, // (max (0, (1-d) + (1-s)))
       
  1189         kCGCompositeModePlusLighter      = 12, // (min (1, s + d))
       
  1190     };
       
  1191 extern "C" {
       
  1192     extern void CGContextSetCompositeOperation(CGContextRef, int);
       
  1193 } // private function, but is in all versions of OS X.
       
  1194 void
       
  1195 QCoreGraphicsPaintEngine::updateCompositionMode(QPainter::CompositionMode mode)
       
  1196 {
       
  1197 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
       
  1198     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
       
  1199         int cg_mode = kCGBlendModeNormal;
       
  1200         switch(mode) {
       
  1201         case QPainter::CompositionMode_Multiply:
       
  1202             cg_mode = kCGBlendModeMultiply;
       
  1203             break;
       
  1204         case QPainter::CompositionMode_Screen:
       
  1205             cg_mode = kCGBlendModeScreen;
       
  1206             break;
       
  1207         case QPainter::CompositionMode_Overlay:
       
  1208             cg_mode = kCGBlendModeOverlay;
       
  1209             break;
       
  1210         case QPainter::CompositionMode_Darken:
       
  1211             cg_mode = kCGBlendModeDarken;
       
  1212             break;
       
  1213         case QPainter::CompositionMode_Lighten:
       
  1214             cg_mode = kCGBlendModeLighten;
       
  1215             break;
       
  1216         case QPainter::CompositionMode_ColorDodge:
       
  1217             cg_mode = kCGBlendModeColorDodge;
       
  1218             break;
       
  1219         case QPainter::CompositionMode_ColorBurn:
       
  1220             cg_mode = kCGBlendModeColorBurn;
       
  1221             break;
       
  1222         case QPainter::CompositionMode_HardLight:
       
  1223             cg_mode = kCGBlendModeHardLight;
       
  1224             break;
       
  1225         case QPainter::CompositionMode_SoftLight:
       
  1226             cg_mode = kCGBlendModeSoftLight;
       
  1227             break;
       
  1228         case QPainter::CompositionMode_Difference:
       
  1229             cg_mode = kCGBlendModeDifference;
       
  1230             break;
       
  1231         case QPainter::CompositionMode_Exclusion:
       
  1232             cg_mode = kCGBlendModeExclusion;
       
  1233             break;
       
  1234         case QPainter::CompositionMode_Plus:
       
  1235             cg_mode = kCGBlendModePlusLighter;
       
  1236             break;
       
  1237         case QPainter::CompositionMode_SourceOver:
       
  1238             cg_mode = kCGBlendModeNormal;
       
  1239             break;
       
  1240         case QPainter::CompositionMode_DestinationOver:
       
  1241             cg_mode = kCGBlendModeDestinationOver;
       
  1242             break;
       
  1243         case QPainter::CompositionMode_Clear:
       
  1244             cg_mode = kCGBlendModeClear;
       
  1245             break;
       
  1246         case QPainter::CompositionMode_Source:
       
  1247             cg_mode = kCGBlendModeCopy;
       
  1248             break;
       
  1249         case QPainter::CompositionMode_Destination:
       
  1250             cg_mode = -1;
       
  1251             break;
       
  1252         case QPainter::CompositionMode_SourceIn:
       
  1253             cg_mode = kCGBlendModeSourceIn;
       
  1254             break;
       
  1255         case QPainter::CompositionMode_DestinationIn:
       
  1256             cg_mode = kCGCompositeModeDestinationIn;
       
  1257             break;
       
  1258         case QPainter::CompositionMode_SourceOut:
       
  1259             cg_mode = kCGBlendModeSourceOut;
       
  1260             break;
       
  1261         case QPainter::CompositionMode_DestinationOut:
       
  1262             cg_mode = kCGBlendModeDestinationOver;
       
  1263             break;
       
  1264         case QPainter::CompositionMode_SourceAtop:
       
  1265             cg_mode = kCGBlendModeSourceAtop;
       
  1266             break;
       
  1267         case QPainter::CompositionMode_DestinationAtop:
       
  1268             cg_mode = kCGBlendModeDestinationAtop;
       
  1269             break;
       
  1270         case QPainter::CompositionMode_Xor:
       
  1271             cg_mode = kCGBlendModeXOR;
       
  1272             break;
       
  1273         default:
       
  1274             break;
       
  1275         }
       
  1276         if (cg_mode > -1) {
       
  1277             CGContextSetBlendMode(d_func()->hd, CGBlendMode(cg_mode));
       
  1278         }
       
  1279     } else
       
  1280 #endif
       
  1281     // The standard porter duff ops.
       
  1282     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_3
       
  1283             && mode <= QPainter::CompositionMode_Xor) {
       
  1284         int cg_mode = kCGCompositeModeCopy;
       
  1285         switch (mode) {
       
  1286         case QPainter::CompositionMode_SourceOver:
       
  1287             cg_mode = kCGCompositeModeSourceOver;
       
  1288             break;
       
  1289         case QPainter::CompositionMode_DestinationOver:
       
  1290             cg_mode = kCGCompositeModeDestinationOver;
       
  1291             break;
       
  1292         case QPainter::CompositionMode_Clear:
       
  1293             cg_mode = kCGCompositeModeClear;
       
  1294             break;
       
  1295         default:
       
  1296             qWarning("QCoreGraphicsPaintEngine: Unhandled composition mode %d", (int)mode);
       
  1297             break;
       
  1298         case QPainter::CompositionMode_Source:
       
  1299             cg_mode = kCGCompositeModeCopy;
       
  1300             break;
       
  1301         case QPainter::CompositionMode_Destination:
       
  1302             cg_mode = CGCompositeMode(-1);
       
  1303             break;
       
  1304         case QPainter::CompositionMode_SourceIn:
       
  1305             cg_mode = kCGCompositeModeSourceIn;
       
  1306             break;
       
  1307         case QPainter::CompositionMode_DestinationIn:
       
  1308             cg_mode = kCGCompositeModeDestinationIn;
       
  1309             break;
       
  1310         case QPainter::CompositionMode_SourceOut:
       
  1311             cg_mode = kCGCompositeModeSourceOut;
       
  1312             break;
       
  1313         case QPainter::CompositionMode_DestinationOut:
       
  1314             cg_mode = kCGCompositeModeDestinationOut;
       
  1315             break;
       
  1316         case QPainter::CompositionMode_SourceAtop:
       
  1317             cg_mode = kCGCompositeModeSourceAtop;
       
  1318             break;
       
  1319         case QPainter::CompositionMode_DestinationAtop:
       
  1320             cg_mode = kCGCompositeModeDestinationAtop;
       
  1321             break;
       
  1322         case QPainter::CompositionMode_Xor:
       
  1323             cg_mode = kCGCompositeModeXOR;
       
  1324             break;
       
  1325         }
       
  1326         if (cg_mode > -1)
       
  1327             CGContextSetCompositeOperation(d_func()->hd, CGCompositeMode(cg_mode));
       
  1328     } else {
       
  1329 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
       
  1330         bool needPrivateAPI = false;
       
  1331         if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
       
  1332             int cg_mode = kCGBlendModeNormal;
       
  1333             switch (mode) {
       
  1334             case QPainter::CompositionMode_Multiply:
       
  1335                 cg_mode = kCGBlendModeMultiply;
       
  1336                 break;
       
  1337             case QPainter::CompositionMode_Screen:
       
  1338                 cg_mode = kCGBlendModeScreen;
       
  1339                 break;
       
  1340             case QPainter::CompositionMode_Overlay:
       
  1341                 cg_mode = kCGBlendModeOverlay;
       
  1342                 break;
       
  1343             case QPainter::CompositionMode_Darken:
       
  1344                 cg_mode = kCGBlendModeDarken;
       
  1345                 break;
       
  1346             case QPainter::CompositionMode_Lighten:
       
  1347                 cg_mode = kCGBlendModeLighten;
       
  1348                 break;
       
  1349             case QPainter::CompositionMode_ColorDodge:
       
  1350                 cg_mode = kCGBlendModeColorDodge;
       
  1351                 break;
       
  1352             case QPainter::CompositionMode_ColorBurn:
       
  1353                 cg_mode = kCGBlendModeColorBurn;
       
  1354                 break;
       
  1355             case QPainter::CompositionMode_HardLight:
       
  1356                 cg_mode = kCGBlendModeHardLight;
       
  1357                 break;
       
  1358             case QPainter::CompositionMode_SoftLight:
       
  1359                 cg_mode = kCGBlendModeSoftLight;
       
  1360                 break;
       
  1361             case QPainter::CompositionMode_Difference:
       
  1362                 cg_mode = kCGBlendModeDifference;
       
  1363                 break;
       
  1364             case QPainter::CompositionMode_Exclusion:
       
  1365                 cg_mode = kCGBlendModeExclusion;
       
  1366                 break;
       
  1367             case QPainter::CompositionMode_Plus:
       
  1368                 needPrivateAPI = true;
       
  1369                 cg_mode = kCGCompositeModePlusLighter;
       
  1370                 break;
       
  1371             default:
       
  1372                 break;
       
  1373             }
       
  1374             if (!needPrivateAPI)
       
  1375                 CGContextSetBlendMode(d_func()->hd, CGBlendMode(cg_mode));
       
  1376             else
       
  1377                 CGContextSetCompositeOperation(d_func()->hd, CGCompositeMode(cg_mode));
       
  1378         }
       
  1379 #endif
       
  1380     }
       
  1381 }
       
  1382 
       
  1383 void
       
  1384 QCoreGraphicsPaintEngine::updateRenderHints(QPainter::RenderHints hints)
       
  1385 {
       
  1386     Q_D(QCoreGraphicsPaintEngine);
       
  1387     CGContextSetShouldAntialias(d->hd, hints & QPainter::Antialiasing);
       
  1388     static const CGFloat ScaleFactor = qt_mac_get_scalefactor();
       
  1389     if (ScaleFactor > 1.) {
       
  1390         CGContextSetInterpolationQuality(d->hd, kCGInterpolationHigh);
       
  1391     } else {
       
  1392         CGContextSetInterpolationQuality(d->hd, (hints & QPainter::SmoothPixmapTransform) ?
       
  1393                                          kCGInterpolationHigh : kCGInterpolationNone);
       
  1394     }
       
  1395     CGContextSetShouldSmoothFonts(d->hd, hints & QPainter::TextAntialiasing);
       
  1396 }
       
  1397 
       
  1398 /*
       
  1399     Returns the size of one device pixel in user-space coordinates.
       
  1400 */
       
  1401 QPointF QCoreGraphicsPaintEnginePrivate::devicePixelSize(CGContextRef)
       
  1402 {
       
  1403     QPointF p1 = current.transform.inverted().map(QPointF(0, 0));
       
  1404     QPointF p2 = current.transform.inverted().map(QPointF(1, 1));
       
  1405     return QPointF(qAbs(p2.x() - p1.x()), qAbs(p2.y() - p1.y()));
       
  1406 }
       
  1407 
       
  1408 /*
       
  1409     Adjusts the pen width so we get correct line widths in the
       
  1410     non-transformed, aliased case.
       
  1411 */
       
  1412 float QCoreGraphicsPaintEnginePrivate::adjustPenWidth(float penWidth)
       
  1413 {
       
  1414     Q_Q(QCoreGraphicsPaintEngine);
       
  1415     float ret = penWidth;
       
  1416     if (!complexXForm && !(q->state->renderHints() & QPainter::Antialiasing)) {
       
  1417         if (penWidth < 2)
       
  1418             ret = 1;
       
  1419         else if (penWidth < 3)
       
  1420             ret = 1.5;
       
  1421         else
       
  1422             ret = penWidth -1;
       
  1423     }
       
  1424     return ret;
       
  1425 }
       
  1426 
       
  1427 void
       
  1428 QCoreGraphicsPaintEnginePrivate::setStrokePen(const QPen &pen)
       
  1429 {
       
  1430     //pencap
       
  1431     CGLineCap cglinecap = kCGLineCapButt;
       
  1432     if(pen.capStyle() == Qt::SquareCap)
       
  1433         cglinecap = kCGLineCapSquare;
       
  1434     else if(pen.capStyle() == Qt::RoundCap)
       
  1435         cglinecap = kCGLineCapRound;
       
  1436     CGContextSetLineCap(hd, cglinecap);
       
  1437     CGContextSetLineWidth(hd, adjustPenWidth(pen.widthF()));
       
  1438 
       
  1439     //join
       
  1440     CGLineJoin cglinejoin = kCGLineJoinMiter;
       
  1441     if(pen.joinStyle() == Qt::BevelJoin)
       
  1442         cglinejoin = kCGLineJoinBevel;
       
  1443     else if(pen.joinStyle() == Qt::RoundJoin)
       
  1444         cglinejoin = kCGLineJoinRound;
       
  1445     CGContextSetLineJoin(hd, cglinejoin);
       
  1446 //    CGContextSetMiterLimit(hd, pen.miterLimit());
       
  1447 
       
  1448     //pen style
       
  1449     QVector<CGFloat> linedashes;
       
  1450     if(pen.style() == Qt::CustomDashLine) {
       
  1451         QVector<qreal> customs = pen.dashPattern();
       
  1452         for(int i = 0; i < customs.size(); ++i)
       
  1453             linedashes.append(customs.at(i));
       
  1454     } else if(pen.style() == Qt::DashLine) {
       
  1455         linedashes.append(4);
       
  1456         linedashes.append(2);
       
  1457     } else if(pen.style() == Qt::DotLine) {
       
  1458         linedashes.append(1);
       
  1459         linedashes.append(2);
       
  1460     } else if(pen.style() == Qt::DashDotLine) {
       
  1461         linedashes.append(4);
       
  1462         linedashes.append(2);
       
  1463         linedashes.append(1);
       
  1464         linedashes.append(2);
       
  1465     } else if(pen.style() == Qt::DashDotDotLine) {
       
  1466         linedashes.append(4);
       
  1467         linedashes.append(2);
       
  1468         linedashes.append(1);
       
  1469         linedashes.append(2);
       
  1470         linedashes.append(1);
       
  1471         linedashes.append(2);
       
  1472     }
       
  1473     const CGFloat cglinewidth = pen.widthF() <= 0.0f ? 1.0f : float(pen.widthF());
       
  1474     for(int i = 0; i < linedashes.size(); ++i) {
       
  1475         linedashes[i] *= cglinewidth;
       
  1476         if(cglinewidth < 3 && (cglinecap == kCGLineCapSquare || cglinecap == kCGLineCapRound)) {
       
  1477             if((i%2))
       
  1478                 linedashes[i] += cglinewidth/2;
       
  1479             else
       
  1480                 linedashes[i] -= cglinewidth/2;
       
  1481         }
       
  1482     }
       
  1483     CGContextSetLineDash(hd, pen.dashOffset() * cglinewidth, linedashes.data(), linedashes.size());
       
  1484 
       
  1485     // color
       
  1486     CGContextSetStrokeColorWithColor(hd, cgColorForQColor(pen.color(), pdev));
       
  1487 }
       
  1488 
       
  1489 // Add our own patterns here to deal with the fact that the coordinate system
       
  1490 // is flipped vertically with Quartz2D.
       
  1491 static const uchar *qt_mac_patternForBrush(int brushStyle)
       
  1492 {
       
  1493     Q_ASSERT(brushStyle > Qt::SolidPattern && brushStyle < Qt::LinearGradientPattern);
       
  1494     static const uchar dense1_pat[] = { 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00 };
       
  1495     static const uchar dense2_pat[] = { 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88 };
       
  1496     static const uchar dense3_pat[] = { 0x11, 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa };
       
  1497     static const uchar dense4_pat[] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 };
       
  1498     static const uchar dense5_pat[] = { 0xee, 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55 };
       
  1499     static const uchar dense6_pat[] = { 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff, 0x77 };
       
  1500     static const uchar dense7_pat[] = { 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 0xff };
       
  1501     static const uchar hor_pat[]    = { 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff };
       
  1502     static const uchar ver_pat[]    = { 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef };
       
  1503     static const uchar cross_pat[]  = { 0xef, 0xef, 0xef, 0xef, 0x00, 0xef, 0xef, 0xef };
       
  1504     static const uchar fdiag_pat[]  = { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe };
       
  1505     static const uchar bdiag_pat[]  = { 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f };
       
  1506     static const uchar dcross_pat[] = { 0x7e, 0xbd, 0xdb, 0xe7, 0xe7, 0xdb, 0xbd, 0x7e };
       
  1507     static const uchar *const pat_tbl[] = {
       
  1508         dense1_pat, dense2_pat, dense3_pat, dense4_pat, dense5_pat,
       
  1509         dense6_pat, dense7_pat,
       
  1510         hor_pat, ver_pat, cross_pat, bdiag_pat, fdiag_pat, dcross_pat };
       
  1511     return pat_tbl[brushStyle - Qt::Dense1Pattern];
       
  1512 }
       
  1513 
       
  1514 void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset)
       
  1515 {
       
  1516     // pattern
       
  1517     Qt::BrushStyle bs = current.brush.style();
       
  1518 #ifdef QT_MAC_USE_NATIVE_GRADIENTS
       
  1519     if (bs == Qt::LinearGradientPattern || bs == Qt::RadialGradientPattern) {
       
  1520         const QGradient *grad = static_cast<const QGradient*>(current.brush.gradient());
       
  1521         if (drawGradientNatively(grad)) {
       
  1522             Q_ASSERT(grad->spread() == QGradient::PadSpread);
       
  1523 
       
  1524             static const CGFloat domain[] = { 0.0f, +1.0f };
       
  1525             static const CGFunctionCallbacks callbacks = { 0, qt_mac_color_gradient_function, 0 };
       
  1526             CGFunctionRef fill_func = CGFunctionCreate(reinterpret_cast<void *>(&current.brush),
       
  1527                     1, domain, 4, 0, &callbacks);
       
  1528 
       
  1529             CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pdev);
       
  1530             if (bs == Qt::LinearGradientPattern) {
       
  1531                 const QLinearGradient *linearGrad = static_cast<const QLinearGradient *>(grad);
       
  1532                 const QPointF start(linearGrad->start());
       
  1533                 const QPointF stop(linearGrad->finalStop());
       
  1534                 shading = CGShadingCreateAxial(colorspace, CGPointMake(start.x(), start.y()),
       
  1535                                                CGPointMake(stop.x(), stop.y()), fill_func, true, true);
       
  1536             } else {
       
  1537                 Q_ASSERT(bs == Qt::RadialGradientPattern);
       
  1538                 const QRadialGradient *radialGrad = static_cast<const QRadialGradient *>(grad);
       
  1539                 QPointF center(radialGrad->center());
       
  1540                 QPointF focal(radialGrad->focalPoint());
       
  1541                 qreal radius = radialGrad->radius();
       
  1542                 shading = CGShadingCreateRadial(colorspace, CGPointMake(focal.x(), focal.y()),
       
  1543                                                 0.0, CGPointMake(center.x(), center.y()), radius, fill_func, false, true);
       
  1544             }
       
  1545 
       
  1546             CGFunctionRelease(fill_func);
       
  1547         }
       
  1548     } else
       
  1549 #endif
       
  1550     if(bs != Qt::SolidPattern && bs != Qt::NoBrush
       
  1551 #ifndef QT_MAC_USE_NATIVE_GRADIENTS
       
  1552        && (bs < Qt::LinearGradientPattern || bs > Qt::ConicalGradientPattern)
       
  1553 #endif
       
  1554         )
       
  1555     {
       
  1556         QMacPattern *qpattern = new QMacPattern;
       
  1557         qpattern->pdev = pdev;
       
  1558         CGFloat components[4] = { 1.0, 1.0, 1.0, 1.0 };
       
  1559         CGColorSpaceRef base_colorspace = 0;
       
  1560         if(bs == Qt::TexturePattern) {
       
  1561             qpattern->data.pixmap = current.brush.texture();
       
  1562             if(qpattern->data.pixmap.isQBitmap()) {
       
  1563                 const QColor &col = current.brush.color();
       
  1564                 components[0] = qt_mac_convert_color_to_cg(col.red());
       
  1565                 components[1] = qt_mac_convert_color_to_cg(col.green());
       
  1566                 components[2] = qt_mac_convert_color_to_cg(col.blue());
       
  1567                 base_colorspace = QCoreGraphicsPaintEngine::macGenericColorSpace();
       
  1568             }
       
  1569         } else {
       
  1570             qpattern->as_mask = true;
       
  1571 
       
  1572             qpattern->data.bytes = qt_mac_patternForBrush(bs);
       
  1573             const QColor &col = current.brush.color();
       
  1574             components[0] = qt_mac_convert_color_to_cg(col.red());
       
  1575             components[1] = qt_mac_convert_color_to_cg(col.green());
       
  1576             components[2] = qt_mac_convert_color_to_cg(col.blue());
       
  1577             base_colorspace = QCoreGraphicsPaintEngine::macGenericColorSpace();
       
  1578         }
       
  1579         int width = qpattern->width(), height = qpattern->height();
       
  1580         qpattern->foreground = current.brush.color();
       
  1581 
       
  1582         CGColorSpaceRef fill_colorspace = CGColorSpaceCreatePattern(base_colorspace);
       
  1583         CGContextSetFillColorSpace(hd, fill_colorspace);
       
  1584 
       
  1585         CGAffineTransform xform = CGContextGetCTM(hd);
       
  1586         xform = CGAffineTransformConcat(qt_mac_convert_transform_to_cg(current.brush.transform()), xform);
       
  1587         xform = CGAffineTransformTranslate(xform, offset.x(), offset.y());
       
  1588 
       
  1589         CGPatternCallbacks callbks;
       
  1590         callbks.version = 0;
       
  1591         callbks.drawPattern = qt_mac_draw_pattern;
       
  1592         callbks.releaseInfo = qt_mac_dispose_pattern;
       
  1593         CGPatternRef fill_pattern = CGPatternCreate(qpattern, CGRectMake(0, 0, width, height),
       
  1594                 xform, width, height, kCGPatternTilingNoDistortion,
       
  1595                 !base_colorspace, &callbks);
       
  1596         CGContextSetFillPattern(hd, fill_pattern, components);
       
  1597 
       
  1598         CGPatternRelease(fill_pattern);
       
  1599         CGColorSpaceRelease(fill_colorspace);
       
  1600     } else if(bs != Qt::NoBrush) {
       
  1601         CGContextSetFillColorWithColor(hd, cgColorForQColor(current.brush.color(), pdev));
       
  1602     }
       
  1603 }
       
  1604 
       
  1605 void
       
  1606 QCoreGraphicsPaintEnginePrivate::setClip(const QRegion *rgn)
       
  1607 {
       
  1608     Q_Q(QCoreGraphicsPaintEngine);
       
  1609     if(hd) {
       
  1610         resetClip();
       
  1611         QRegion sysClip = q->systemClip();
       
  1612         if(!sysClip.isEmpty())
       
  1613             qt_mac_clip_cg(hd, sysClip, &orig_xform);
       
  1614         if(rgn)
       
  1615             qt_mac_clip_cg(hd, *rgn, 0);
       
  1616     }
       
  1617 }
       
  1618 
       
  1619 struct qt_mac_cg_transform_path {
       
  1620     CGMutablePathRef path;
       
  1621     CGAffineTransform transform;
       
  1622 };
       
  1623 
       
  1624 void qt_mac_cg_transform_path_apply(void *info, const CGPathElement *element)
       
  1625 {
       
  1626     Q_ASSERT(info && element);
       
  1627     qt_mac_cg_transform_path *t = (qt_mac_cg_transform_path*)info;
       
  1628     switch(element->type) {
       
  1629     case kCGPathElementMoveToPoint:
       
  1630         CGPathMoveToPoint(t->path, &t->transform, element->points[0].x, element->points[0].y);
       
  1631         break;
       
  1632     case kCGPathElementAddLineToPoint:
       
  1633         CGPathAddLineToPoint(t->path, &t->transform, element->points[0].x, element->points[0].y);
       
  1634         break;
       
  1635     case kCGPathElementAddQuadCurveToPoint:
       
  1636         CGPathAddQuadCurveToPoint(t->path, &t->transform, element->points[0].x, element->points[0].y,
       
  1637                                   element->points[1].x, element->points[1].y);
       
  1638         break;
       
  1639     case kCGPathElementAddCurveToPoint:
       
  1640         CGPathAddCurveToPoint(t->path, &t->transform, element->points[0].x, element->points[0].y,
       
  1641                               element->points[1].x, element->points[1].y,
       
  1642                               element->points[2].x, element->points[2].y);
       
  1643         break;
       
  1644     case kCGPathElementCloseSubpath:
       
  1645         CGPathCloseSubpath(t->path);
       
  1646         break;
       
  1647     default:
       
  1648         qDebug() << "Unhandled path transform type: " << element->type;
       
  1649     }
       
  1650 }
       
  1651 
       
  1652 void QCoreGraphicsPaintEnginePrivate::drawPath(uchar ops, CGMutablePathRef path)
       
  1653 {
       
  1654     Q_Q(QCoreGraphicsPaintEngine);
       
  1655     Q_ASSERT((ops & (CGFill | CGEOFill)) != (CGFill | CGEOFill)); //can't really happen
       
  1656     if((ops & (CGFill | CGEOFill))) {
       
  1657         if (shading) {
       
  1658             Q_ASSERT(path);
       
  1659             CGContextBeginPath(hd);
       
  1660             CGContextAddPath(hd, path);
       
  1661             saveGraphicsState();
       
  1662             if (ops & CGFill)
       
  1663                 CGContextClip(hd);
       
  1664             else if (ops & CGEOFill)
       
  1665                 CGContextEOClip(hd);
       
  1666             if (current.brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode) {
       
  1667                 CGRect boundingBox = CGPathGetBoundingBox(path);
       
  1668                 CGContextConcatCTM(hd,
       
  1669                     CGAffineTransformMake(boundingBox.size.width, 0,
       
  1670                                           0, boundingBox.size.height,
       
  1671                                           boundingBox.origin.x, boundingBox.origin.y));
       
  1672             }
       
  1673             CGContextDrawShading(hd, shading);
       
  1674             restoreGraphicsState();
       
  1675             ops &= ~CGFill;
       
  1676             ops &= ~CGEOFill;
       
  1677         } else if (current.brush.style() == Qt::NoBrush) {
       
  1678             ops &= ~CGFill;
       
  1679             ops &= ~CGEOFill;
       
  1680         }
       
  1681     }
       
  1682     if((ops & CGStroke) && current.pen.style() == Qt::NoPen)
       
  1683         ops &= ~CGStroke;
       
  1684 
       
  1685     if(ops & (CGEOFill | CGFill)) {
       
  1686         CGContextBeginPath(hd);
       
  1687         CGContextAddPath(hd, path);
       
  1688         if (ops & CGEOFill) {
       
  1689             CGContextEOFillPath(hd);
       
  1690         } else {
       
  1691             CGContextFillPath(hd);
       
  1692         }
       
  1693     }
       
  1694 
       
  1695     // Avoid saving and restoring the context if we can.
       
  1696     const bool needContextSave = (cosmeticPen != QCoreGraphicsPaintEnginePrivate::CosmeticNone ||
       
  1697                                   !(q->state->renderHints() & QPainter::Antialiasing));
       
  1698     if(ops & CGStroke) {
       
  1699         if (needContextSave)
       
  1700             saveGraphicsState();
       
  1701         CGContextBeginPath(hd);
       
  1702 
       
  1703         // Translate a fraction of a pixel size in the y direction
       
  1704         // to make sure that primitives painted at pixel borders
       
  1705         // fills the right pixel. This is needed since the y xais
       
  1706         // in the Quartz coordinate system is inverted compared to Qt.
       
  1707         if (!(q->state->renderHints() & QPainter::Antialiasing)) {
       
  1708             if (current.pen.style() == Qt::SolidLine || current.pen.width() >= 3)
       
  1709                 CGContextTranslateCTM(hd, double(pixelSize.x()) * 0.25, double(pixelSize.y()) * 0.25);
       
  1710             else if (current.pen.style() == Qt::DotLine && QSysInfo::MacintoshVersion == QSysInfo::MV_10_3)
       
  1711                 ; // Do nothing.
       
  1712             else
       
  1713                 CGContextTranslateCTM(hd, 0, double(pixelSize.y()) * 0.1);
       
  1714         }
       
  1715 
       
  1716         if (cosmeticPen != QCoreGraphicsPaintEnginePrivate::CosmeticNone) {
       
  1717             // If antialiazing is enabled, use the cosmetic pen size directly.
       
  1718             if (q->state->renderHints() & QPainter::Antialiasing)
       
  1719                 CGContextSetLineWidth(hd,  cosmeticPenSize);
       
  1720             else if (current.pen.widthF() <= 1)
       
  1721                 CGContextSetLineWidth(hd, cosmeticPenSize * 0.9f);
       
  1722             else
       
  1723                 CGContextSetLineWidth(hd, cosmeticPenSize);
       
  1724         }
       
  1725         if(cosmeticPen == QCoreGraphicsPaintEnginePrivate::CosmeticTransformPath) {
       
  1726             qt_mac_cg_transform_path t;
       
  1727             t.transform = qt_mac_convert_transform_to_cg(current.transform);
       
  1728             t.path = CGPathCreateMutable();
       
  1729             CGPathApply(path, &t, qt_mac_cg_transform_path_apply); //transform the path
       
  1730             setTransform(0); //unset the context transform
       
  1731             CGContextSetLineWidth(hd,  cosmeticPenSize);
       
  1732             CGContextAddPath(hd, t.path);
       
  1733             CGPathRelease(t.path);
       
  1734         } else {
       
  1735             CGContextAddPath(hd, path);
       
  1736         }
       
  1737 
       
  1738         CGContextStrokePath(hd);
       
  1739         if (needContextSave)
       
  1740             restoreGraphicsState();
       
  1741     }
       
  1742 }
       
  1743 
       
  1744 QT_END_NAMESPACE