From c52bb0309071bed9e040c79d87f764bac6a396b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 12 Sep 2016 17:05:39 +0200 Subject: macOS: Move QMacCGContext helper into QtGui MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The implementation was duplicated and spread out between QMacStyle, QMacPaintEngine, and the Cocoa platform plugin. Moving it into QtGui allows using it on other Apple platform. Change-Id: Iadcbd71998204887e116271c575037789b6e2163 Reviewed-by: Jake Petroules Reviewed-by: Tor Arne Vestbø --- src/gui/painting/painting.pri | 5 + src/gui/painting/qcoregraphics.mm | 289 +++++++++++++++++++++++ src/gui/painting/qcoregraphics_p.h | 99 ++++++++ src/gui/painting/qpaintengine_p.h | 5 + src/plugins/platforms/cocoa/qcocoahelpers.h | 5 - src/plugins/platforms/cocoa/qcocoahelpers.mm | 138 +---------- src/plugins/platforms/cocoa/qcocoaintegration.mm | 7 +- src/plugins/platforms/cocoa/qcocoatheme.mm | 4 +- src/plugins/platforms/cocoa/qpaintengine_mac.mm | 84 +------ src/plugins/platforms/cocoa/qprintengine_mac_p.h | 3 + src/plugins/platforms/cocoa/qt_mac_p.h | 38 --- src/widgets/styles/qmacstyle_mac.mm | 279 +--------------------- 12 files changed, 415 insertions(+), 541 deletions(-) create mode 100644 src/gui/painting/qcoregraphics.mm create mode 100644 src/gui/painting/qcoregraphics_p.h diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index c47060a2ad..a61865a0b6 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -99,6 +99,11 @@ SOURCES += \ painting/qplatformbackingstore.cpp \ painting/qpathsimplifier.cpp +darwin { + HEADERS += painting/qcoregraphics_p.h + SOURCES += painting/qcoregraphics.mm +} + SSE2_SOURCES += painting/qdrawhelper_sse2.cpp SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \ diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm new file mode 100644 index 0000000000..fa5c9b61b2 --- /dev/null +++ b/src/gui/painting/qcoregraphics.mm @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcoregraphics_p.h" + +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + + +// ---------------------- Color Management ---------------------- + +static CGColorSpaceRef m_genericColorSpace = 0; +static QHash m_displayColorSpaceHash; +static bool m_postRoutineRegistered = false; + +static void qt_mac_cleanUpMacColorSpaces() +{ + if (m_genericColorSpace) { + CFRelease(m_genericColorSpace); + m_genericColorSpace = 0; + } + QHash::const_iterator it = m_displayColorSpaceHash.constBegin(); + while (it != m_displayColorSpaceHash.constEnd()) { + if (it.value()) + CFRelease(it.value()); + ++it; + } + m_displayColorSpaceHash.clear(); +} + +static CGColorSpaceRef qt_mac_displayColorSpace(const QWindow *window) +{ + CGColorSpaceRef colorSpace = 0; + uint32_t displayID = 0; + +#ifdef Q_OS_MACOS + if (window == 0) { + displayID = CGMainDisplayID(); + } else { + displayID = CGMainDisplayID(); + /* + ### get correct display + const QRect &qrect = window->geometry(); + CGRect rect = CGRectMake(qrect.x(), qrect.y(), qrect.width(), qrect.height()); + CGDisplayCount throwAway; + CGDisplayErr dErr = CGGetDisplaysWithRect(rect, 1, &displayID, &throwAway); + if (dErr != kCGErrorSuccess) + return macDisplayColorSpace(0); // fall back on main display + */ + } + if ((colorSpace = m_displayColorSpaceHash.value(displayID))) + return colorSpace; + + colorSpace = CGDisplayCopyColorSpace(displayID); +#else + Q_UNUSED(window); +#endif + + if (colorSpace == 0) + colorSpace = CGColorSpaceCreateDeviceRGB(); + + m_displayColorSpaceHash.insert(displayID, colorSpace); + if (!m_postRoutineRegistered) { + m_postRoutineRegistered = true; + qAddPostRoutine(qt_mac_cleanUpMacColorSpaces); + } + return colorSpace; +} + +CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice) +{ + Q_UNUSED(paintDevice); + + // FIXME: Move logic into each paint device once Qt has support for color spaces + return qt_mac_displayColorSpace(0); + + // The following code seems to take care of QWidget, but in reality doesn't, as + // qt_mac_displayColorSpace ignores the argument and always uses the main display. +#if 0 + bool isWidget = (paintDevice->devType() == QInternal::Widget); + return qt_mac_displayColorSpace(isWidget ? static_cast(paintDevice)->window() : 0); +#endif +} + +CGColorSpaceRef qt_mac_genericColorSpace() +{ +#if 0 + if (!m_genericColorSpace) { + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { + m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + } else + { + m_genericColorSpace = CGColorSpaceCreateDeviceRGB(); + } + if (!m_postRoutineRegistered) { + m_postRoutineRegistered = true; + qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces); + } + } + return m_genericColorSpace; +#else + // Just return the main display colorspace for the moment. + return qt_mac_displayColorSpace(0); +#endif +} + +// ---------------------- Geometry Helpers ---------------------- + +void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform) +{ + CGAffineTransform old_xform = CGAffineTransformIdentity; + if (orig_xform) { //setup xforms + old_xform = CGContextGetCTM(hd); + CGContextConcatCTM(hd, CGAffineTransformInvert(old_xform)); + CGContextConcatCTM(hd, *orig_xform); + } + + //do the clipping + CGContextBeginPath(hd); + if (rgn.isEmpty()) { + CGContextAddRect(hd, CGRectMake(0, 0, 0, 0)); + } else { + for (const QRect &r : rgn) { + CGRect mac_r = CGRectMake(r.x(), r.y(), r.width(), r.height()); + CGContextAddRect(hd, mac_r); + } + } + CGContextClip(hd); + + if (orig_xform) {//reset xforms + CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd))); + CGContextConcatCTM(hd, old_xform); + } +} + +// move to QRegion? +void qt_mac_scale_region(QRegion *region, qreal scaleFactor) +{ + if (!region || !region->rectCount()) + return; + + QVector scaledRects; + scaledRects.reserve(region->rectCount()); + + for (const QRect &rect : *region) + scaledRects.append(QRect(rect.topLeft() * scaleFactor, rect.size() * scaleFactor)); + + region->setRects(&scaledRects[0], scaledRects.count()); +} + +// ---------------------- QMacCGContext ---------------------- + +QMacCGContext::QMacCGContext(QPaintDevice *paintDevice) : context(0) +{ + // In Qt 5, QWidget and QPixmap (and QImage) paint devices are all QImages under the hood. + QImage *image = 0; + if (paintDevice->devType() == QInternal::Image) { + image = static_cast(paintDevice); + } else if (paintDevice->devType() == QInternal::Pixmap) { + + const QPixmap *pm = static_cast(paintDevice); + QPlatformPixmap *data = const_cast(pm)->data_ptr().data(); + if (data && data->classId() == QPlatformPixmap::RasterClass) { + image = data->buffer(); + } else { + qDebug("QMacCGContext: Unsupported pixmap class"); + } + } else if (paintDevice->devType() == QInternal::Widget) { + // TODO test: image = static_cast(static_cast(paintDevice)->backingStore()->paintDevice()); + qDebug("QMacCGContext: not implemented: Widget class"); + } + + if (!image) + return; // Context type not supported. + + CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(paintDevice); + uint flags = kCGImageAlphaPremultipliedFirst; + flags |= kCGBitmapByteOrder32Host; + + context = CGBitmapContextCreate(image->bits(), image->width(), image->height(), + 8, image->bytesPerLine(), colorspace, flags); + CGContextTranslateCTM(context, 0, image->height()); + CGContextScaleCTM(context, 1, -1); +} + +QMacCGContext::QMacCGContext(QPainter *painter) : context(0) +{ + QPaintEngine *paintEngine = painter->paintEngine(); + + // Handle the case of QMacPrintEngine, which has an internal QCoreGraphicsPaintEngine + while (QPaintEngine *aggregateEngine = QPaintEnginePrivate::get(paintEngine)->aggregateEngine()) + paintEngine = aggregateEngine; + + paintEngine->syncState(); + + if (Qt::HANDLE handle = QPaintEnginePrivate::get(paintEngine)->nativeHandle()) { + context = static_cast(handle); + return; + } + + int devType = painter->device()->devType(); + if (paintEngine->type() == QPaintEngine::Raster + && (devType == QInternal::Widget || + devType == QInternal::Pixmap || + devType == QInternal::Image)) { + + CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(paintEngine->paintDevice()); + uint flags = kCGImageAlphaPremultipliedFirst; +#ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version + flags |= kCGBitmapByteOrder32Host; +#endif + const QImage *image = static_cast(paintEngine->paintDevice()); + + context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), + 8, image->bytesPerLine(), colorspace, flags); + + // Invert y axis + CGContextTranslateCTM(context, 0, image->height()); + CGContextScaleCTM(context, 1, -1); + + const qreal devicePixelRatio = image->devicePixelRatio(); + + if (devType == QInternal::Widget) { + // Set the clip rect which is an intersection of the system clip + // and the painter clip. To make matters more interesting these + // are in device pixels and device-independent pixels, respectively. + QRegion clip = painter->paintEngine()->systemClip(); // get system clip in device pixels + QTransform native = painter->deviceTransform(); // get device transform. dx/dy is in device pixels + + if (painter->hasClipping()) { + QRegion r = painter->clipRegion(); // get painter clip, which is in device-independent pixels + qt_mac_scale_region(&r, devicePixelRatio); // scale painter clip to device pixels + r.translate(native.dx(), native.dy()); + if (clip.isEmpty()) + clip = r; + else + clip &= r; + } + qt_mac_clip_cg(context, clip, 0); // clip in device pixels + + // Scale the context so that painting happens in device-independent pixels + CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); + CGContextTranslateCTM(context, native.dx() / devicePixelRatio, native.dy() / devicePixelRatio); + } else { + // Scale to paint in device-independent pixels + CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); + } + } else { + qDebug() << "QMacCGContext:: Unsupported painter devtype type" << devType; + } +} + +QT_END_NAMESPACE diff --git a/src/gui/painting/qcoregraphics_p.h b/src/gui/painting/qcoregraphics_p.h new file mode 100644 index 0000000000..b6ea5474ec --- /dev/null +++ b/src/gui/painting/qcoregraphics_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOREGRAPHICS_P_H +#define QCOREGRAPHICS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +Q_GUI_EXPORT CGColorSpaceRef qt_mac_genericColorSpace(); +Q_GUI_EXPORT CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice); + +Q_GUI_EXPORT void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform); + +class Q_GUI_EXPORT QMacCGContext +{ +public: + inline QMacCGContext() { context = 0; } + QMacCGContext(QPaintDevice *pdev); + QMacCGContext(QPainter *p); + inline QMacCGContext(CGContextRef cg, bool takeOwnership = false) { + context = cg; + if (!takeOwnership) + CGContextRetain(context); + } + inline QMacCGContext(const QMacCGContext ©) : context(0) { *this = copy; } + inline ~QMacCGContext() { + if (context) + CGContextRelease(context); + } + inline bool isNull() const { return context; } + inline operator CGContextRef() { return context; } + inline QMacCGContext &operator=(const QMacCGContext ©) { + if (context) + CGContextRelease(context); + context = copy.context; + CGContextRetain(context); + return *this; + } + inline QMacCGContext &operator=(CGContextRef cg) { + if (context) + CGContextRelease(context); + context = cg; + CGContextRetain(context); //we do not take ownership + return *this; + } + +private: + CGContextRef context; +}; + +QT_END_NAMESPACE + +#endif // QCOREGRAPHICS_P_H diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h index 1a1df547bb..9d511f9bad 100644 --- a/src/gui/painting/qpaintengine_p.h +++ b/src/gui/painting/qpaintengine_p.h @@ -118,6 +118,11 @@ public: virtual void systemStateChanged() { } void drawBoxTextItem(const QPointF &p, const QTextItemInt &ti); + + static QPaintEnginePrivate *get(QPaintEngine *paintEngine) { return paintEngine->d_func(); } + + virtual QPaintEngine *aggregateEngine() { return 0; } + virtual Qt::HANDLE nativeHandle() { return 0; } }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h index 9b061bbae8..272b443b68 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.h +++ b/src/plugins/platforms/cocoa/qcocoahelpers.h @@ -95,9 +95,6 @@ Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions); // Misc void qt_mac_transformProccessToForegroundApplication(); -CGColorSpaceRef qt_mac_genericColorSpace(); -CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget); -CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice); QString qt_mac_applicationName(); int qt_mac_flipYCoordinate(int y); @@ -143,8 +140,6 @@ public: } }; -CGContextRef qt_mac_cg_context(QPaintDevice *pdev); - template T qt_mac_resolveOption(const T &fallback, const QByteArray &environment) { diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 6920f75887..21ffd8599f 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -47,6 +47,7 @@ #include #include #include +#include #ifndef QT_NO_WIDGETS #include @@ -402,97 +403,6 @@ void qt_mac_transformProccessToForegroundApplication() [[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular]; } } -static CGColorSpaceRef m_genericColorSpace = 0; -static QHash m_displayColorSpaceHash; -static bool m_postRoutineRegistered = false; - -CGColorSpaceRef qt_mac_genericColorSpace() -{ -#if 0 - if (!m_genericColorSpace) { - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { - m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); - } else - { - m_genericColorSpace = CGColorSpaceCreateDeviceRGB(); - } - if (!m_postRoutineRegistered) { - m_postRoutineRegistered = true; - qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces); - } - } - return m_genericColorSpace; -#else - // Just return the main display colorspace for the moment. - return qt_mac_displayColorSpace(0); -#endif -} - -/* - Ideally, we should pass the widget in here, and use CGGetDisplaysWithRect() etc. - to support multiple displays correctly. -*/ -CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget) -{ - CGColorSpaceRef colorSpace; - - CGDirectDisplayID displayID; - if (widget == 0) { - displayID = CGMainDisplayID(); - } else { - displayID = CGMainDisplayID(); - /* - ### get correct display - const QRect &qrect = widget->window()->geometry(); - CGRect rect = CGRectMake(qrect.x(), qrect.y(), qrect.width(), qrect.height()); - CGDisplayCount throwAway; - CGDisplayErr dErr = CGGetDisplaysWithRect(rect, 1, &displayID, &throwAway); - if (dErr != kCGErrorSuccess) - return macDisplayColorSpace(0); // fall back on main display - */ - } - if ((colorSpace = m_displayColorSpaceHash.value(displayID))) - return colorSpace; - - colorSpace = CGDisplayCopyColorSpace(displayID); - if (colorSpace == 0) - colorSpace = CGColorSpaceCreateDeviceRGB(); - - m_displayColorSpaceHash.insert(displayID, colorSpace); - if (!m_postRoutineRegistered) { - m_postRoutineRegistered = true; - void qt_mac_cleanUpMacColorSpaces(); - qAddPostRoutine(qt_mac_cleanUpMacColorSpaces); - } - return colorSpace; -} - -void qt_mac_cleanUpMacColorSpaces() -{ - if (m_genericColorSpace) { - CFRelease(m_genericColorSpace); - m_genericColorSpace = 0; - } - QHash::const_iterator it = m_displayColorSpaceHash.constBegin(); - while (it != m_displayColorSpaceHash.constEnd()) { - if (it.value()) - CFRelease(it.value()); - ++it; - } - m_displayColorSpaceHash.clear(); -} - -CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice) -{ -#ifdef QT_NO_WIDGETS - Q_UNUSED(paintDevice) - return qt_mac_displayColorSpace(0); -#else - bool isWidget = (paintDevice->devType() == QInternal::Widget); - return qt_mac_displayColorSpace(isWidget ? static_cast(paintDevice): 0); -#endif - -} QString qt_mac_applicationName() { @@ -599,49 +509,6 @@ QString qt_mac_removeAmpersandEscapes(QString s) return QPlatformTheme::removeMnemonics(s).trimmed(); } -/*! \internal - - Returns the CoreGraphics CGContextRef of the paint device. 0 is - returned if it can't be obtained. It is the caller's responsibility to - CGContextRelease the context when finished using it. - - \warning This function is only available on \macos. - \warning This function is duplicated in qmacstyle_mac.mm - */ -CGContextRef qt_mac_cg_context(QPaintDevice *pdev) -{ - // In Qt 5, QWidget and QPixmap (and QImage) paint devices are all QImages under the hood. - QImage *image = 0; - if (pdev->devType() == QInternal::Image) { - image = static_cast(pdev); - } else if (pdev->devType() == QInternal::Pixmap) { - - const QPixmap *pm = static_cast(pdev); - QPlatformPixmap *data = const_cast(pm)->data_ptr().data(); - if (data && data->classId() == QPlatformPixmap::RasterClass) { - image = data->buffer(); - } else { - qDebug("qt_mac_cg_context: Unsupported pixmap class"); - } - } else if (pdev->devType() == QInternal::Widget) { - // TODO test: image = static_cast(static_cast(pdev)->backingStore()->paintDevice()); - qDebug("qt_mac_cg_context: not implemented: Widget class"); - } - - if (!image) - return 0; // Context type not supported. - - CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pdev); - uint flags = kCGImageAlphaPremultipliedFirst; - flags |= kCGBitmapByteOrder32Host; - CGContextRef ret = 0; - ret = CGBitmapContextCreate(image->bits(), image->width(), image->height(), - 8, image->bytesPerLine(), colorspace, flags); - CGContextTranslateCTM(ret, 0, image->height()); - CGContextScaleCTM(ret, 1, -1); - return ret; -} - QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size) { const NSSize pixmapSize = NSMakeSize(size.width(), size.height()); @@ -669,9 +536,8 @@ QImage qt_mac_toQImage(CGImageRef image) QImage ret(w, h, QImage::Format_ARGB32_Premultiplied); ret.fill(Qt::transparent); CGRect rect = CGRectMake(0, 0, w, h); - CGContextRef ctx = qt_mac_cg_context(&ret); + QMacCGContext ctx(&ret); qt_mac_drawCGImage(ctx, &rect, image); - CGContextRelease(ctx); return ret; } diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 1793bd404e..f3f720654e 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -58,6 +58,8 @@ #include #include +#include + #include static void initResources() @@ -199,8 +201,6 @@ QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const return window; } -extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); - QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height) const { // TODO window should be handled @@ -251,9 +251,8 @@ QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height QPixmap pix(w, h); pix.fill(Qt::transparent); CGRect rect = CGRectMake(0, 0, w, h); - CGContextRef ctx = qt_mac_cg_context(&pix); + QMacCGContext ctx(&pix); qt_mac_drawCGImage(ctx, &rect, image); - CGContextRelease(ctx); QPainter painter(&windowPixmap); painter.drawPixmap(0, 0, pix); diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 95175871a4..d0879ed457 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -56,6 +56,7 @@ #include #include +#include #include #include #include @@ -197,7 +198,7 @@ QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height) CGRect rect = CGRectMake(0, 0, width, height); - CGContextRef ctx = qt_mac_cg_context(&ret); + QMacCGContext ctx(&ret); CGAffineTransform old_xform = CGContextGetCTM(ctx); CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform)); CGContextConcatCTM(ctx, CGAffineTransformIdentity); @@ -205,7 +206,6 @@ QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height) ::RGBColor b; b.blue = b.green = b.red = 255*255; PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon); - CGContextRelease(ctx); return ret; } diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm index 759c4d26a5..7e241e3ae6 100644 --- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm @@ -63,6 +63,7 @@ #include #include #include +#include #include "qcocoahelpers.h" @@ -74,84 +75,6 @@ QT_BEGIN_NAMESPACE QCoreGraphicsPaintEngine utility functions *****************************************************************************/ -static void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform) -{ - CGAffineTransform old_xform = CGAffineTransformIdentity; - if (orig_xform) { //setup xforms - old_xform = CGContextGetCTM(hd); - CGContextConcatCTM(hd, CGAffineTransformInvert(old_xform)); - CGContextConcatCTM(hd, *orig_xform); - } - - //do the clipping - CGContextBeginPath(hd); - if (rgn.isEmpty()) { - CGContextAddRect(hd, CGRectMake(0, 0, 0, 0)); - } else { - for (const QRect &r : rgn) { - CGRect mac_r = CGRectMake(r.x(), r.y(), r.width(), r.height()); - CGContextAddRect(hd, mac_r); - } - } - CGContextClip(hd); - - if (orig_xform) {//reset xforms - CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd))); - CGContextConcatCTM(hd, old_xform); - } -} - -// Implemented for qt_mac_p.h -QMacCGContext::QMacCGContext(QPainter *p) -{ - QPaintEngine *pe = p->paintEngine(); -#ifndef QT_NO_PRINTER - if (pe->type() == QPaintEngine::MacPrinter) - pe = static_cast(pe)->paintEngine(); -#endif - pe->syncState(); - context = 0; - if (pe->type() == QPaintEngine::CoreGraphics) - context = static_cast(pe)->handle(); - - int devType = p->device()->devType(); - if (pe->type() == QPaintEngine::Raster - && (devType == QInternal::Widget || devType == QInternal::Pixmap || devType == QInternal::Image)) { - - CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pe->paintDevice()); - uint flags = kCGImageAlphaPremultipliedFirst; -#ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version - flags |= kCGBitmapByteOrder32Host; -#endif - const QImage *image = (const QImage *) pe->paintDevice(); - - context = CGBitmapContextCreate((void *) image->bits(), image->width(), image->height(), - 8, image->bytesPerLine(), colorspace, flags); - - CGContextTranslateCTM(context, 0, image->height()); - CGContextScaleCTM(context, 1, -1); - - if (devType == QInternal::Widget) { - QRegion clip = p->paintEngine()->systemClip(); - QTransform native = p->deviceTransform(); - - if (p->hasClipping()) { - QRegion r = p->clipRegion(); - r.translate(native.dx(), native.dy()); - if (clip.isEmpty()) - clip = r; - else - clip &= r; - } - qt_mac_clip_cg(context, clip, 0); - - CGContextTranslateCTM(context, native.dx(), native.dy()); - } - } else { - CGContextRetain(context); - } -} - void qt_mac_cgimage_data_free(void *, const void *memoryToFree, size_t) { free(const_cast(memoryToFree)); @@ -453,7 +376,7 @@ static void qt_mac_draw_pattern(void *info, CGContextRef c) const QColor c0(0, 0, 0, 0), c1(255, 255, 255, 255); QPixmap pm(w*QMACPATTERN_MASK_MULTIPLIER, h*QMACPATTERN_MASK_MULTIPLIER); pm.fill(c0); - CGContextRef pm_ctx = qt_mac_cg_context(&pm); + QMacCGContext pm_ctx(&pm); CGContextSetFillColorWithColor(c, cgColorForQColor(c1, pat->pdev)); CGRect rect = CGRectMake(0, 0, w, h); for (int x = 0; x < QMACPATTERN_MASK_MULTIPLIER; ++x) { @@ -543,7 +466,8 @@ QCoreGraphicsPaintEngine::begin(QPaintDevice *pdev) d->cosmeticPenSize = 1; d->current.clipEnabled = false; d->pixelSize = QPoint(1,1); - d->hd = qt_mac_cg_context(pdev); + QMacCGContext ctx(pdev); + d->hd = CGContextRetain(ctx); if (d->hd) { d->saveGraphicsState(); d->orig_xform = CGContextGetCTM(d->hd); diff --git a/src/plugins/platforms/cocoa/qprintengine_mac_p.h b/src/plugins/platforms/cocoa/qprintengine_mac_p.h index e3cad3fd57..ee98275b63 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac_p.h +++ b/src/plugins/platforms/cocoa/qprintengine_mac_p.h @@ -149,6 +149,9 @@ public: PMPageFormat format() const { return static_cast([printInfo PMPageFormat]); } PMPrintSession session() const { return static_cast([printInfo PMPrintSession]); } PMPrintSettings settings() const { return static_cast([printInfo PMPrintSettings]); } + + QPaintEngine *aggregateEngine() Q_DECL_OVERRIDE { return paintEngine; } + Qt::HANDLE nativeHandle() Q_DECL_OVERRIDE { return q_func()->handle(); } }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qt_mac_p.h b/src/plugins/platforms/cocoa/qt_mac_p.h index 902cf5c636..ce17919e8c 100644 --- a/src/plugins/platforms/cocoa/qt_mac_p.h +++ b/src/plugins/platforms/cocoa/qt_mac_p.h @@ -90,44 +90,6 @@ public: } }; -class QMacCGContext -{ - CGContextRef context; -public: - QMacCGContext(QPainter *p); //qpaintengine_mac.mm - inline QMacCGContext() { context = 0; } - inline QMacCGContext(QPaintDevice *pdev) { - extern CGContextRef qt_mac_cg_context(QPaintDevice *); - context = qt_mac_cg_context(pdev); - } - inline QMacCGContext(CGContextRef cg, bool takeOwnership=false) { - context = cg; - if(!takeOwnership) - CGContextRetain(context); - } - inline QMacCGContext(const QMacCGContext ©) : context(0) { *this = copy; } - inline ~QMacCGContext() { - if(context) - CGContextRelease(context); - } - inline bool isNull() const { return context; } - inline operator CGContextRef() { return context; } - inline QMacCGContext &operator=(const QMacCGContext ©) { - if(context) - CGContextRelease(context); - context = copy.context; - CGContextRetain(context); - return *this; - } - inline QMacCGContext &operator=(CGContextRef cg) { - if(context) - CGContextRelease(context); - context = cg; - CGContextRetain(context); //we do not take ownership - return *this; - } -}; - class QMacInternalPasteboardMime; class QMimeData; diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 6aa5845a2c..1f17810fc9 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -96,6 +96,7 @@ #include #include #include +#include QT_USE_NAMESPACE @@ -520,47 +521,6 @@ static QString qt_mac_removeMnemonics(const QString &original) return returnText; } -static CGContextRef qt_mac_cg_context(const QPaintDevice *pdev); - -namespace { -class QMacCGContext -{ - CGContextRef context; -public: - QMacCGContext(QPainter *p); - inline QMacCGContext() { context = 0; } - inline QMacCGContext(const QPaintDevice *pdev) { - context = qt_mac_cg_context(pdev); - } - inline QMacCGContext(CGContextRef cg, bool takeOwnership=false) { - context = cg; - if (!takeOwnership) - CGContextRetain(context); - } - inline QMacCGContext(const QMacCGContext ©) : context(0) { *this = copy; } - inline ~QMacCGContext() { - if (context) - CGContextRelease(context); - } - inline bool isNull() const { return context; } - inline operator CGContextRef() { return context; } - inline QMacCGContext &operator=(const QMacCGContext ©) { - if (context) - CGContextRelease(context); - context = copy.context; - CGContextRetain(context); - return *this; - } - inline QMacCGContext &operator=(CGContextRef cg) { - if (context) - CGContextRelease(context); - context = cg; - CGContextRetain(context); //we do not take ownership - return *this; - } -}; -} // anonymous namespace - OSStatus qt_mac_shape2QRegionHelper(int inMessage, HIShapeRef, const CGRect *inRect, void *inRefcon) { QRegion *region = static_cast(inRefcon); @@ -581,7 +541,6 @@ OSStatus qt_mac_shape2QRegionHelper(int inMessage, HIShapeRef, const CGRect *inR return noErr; } - /*! \internal Create's a mutable shape, it's the caller's responsibility to release. @@ -611,86 +570,6 @@ QRegion qt_mac_fromHIShapeRef(HIShapeRef shape) return returnRegion; } -CGColorSpaceRef m_genericColorSpace = 0; -static QHash m_displayColorSpaceHash; -bool m_postRoutineRegistered = false; - -static CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget); -static CGColorSpaceRef qt_mac_genericColorSpace() -{ -#if 0 - if (!m_genericColorSpace) { - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) { - m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); - } else - { - m_genericColorSpace = CGColorSpaceCreateDeviceRGB(); - } - if (!m_postRoutineRegistered) { - m_postRoutineRegistered = true; - qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces); - } - } - return m_genericColorSpace; -#else - // Just return the main display colorspace for the moment. - return qt_mac_displayColorSpace(0); -#endif -} - -static void qt_mac_cleanUpMacColorSpaces() -{ - if (m_genericColorSpace) { - CFRelease(m_genericColorSpace); - m_genericColorSpace = 0; - } - QHash::const_iterator it = m_displayColorSpaceHash.constBegin(); - while (it != m_displayColorSpaceHash.constEnd()) { - if (it.value()) - CFRelease(it.value()); - ++it; - } - m_displayColorSpaceHash.clear(); -} - -/* - Ideally, we should pass the widget in here, and use CGGetDisplaysWithRect() etc. - to support multiple displays correctly. -*/ -static CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget) -{ - CGColorSpaceRef colorSpace; - - CGDirectDisplayID displayID; - if (widget == 0) { - displayID = CGMainDisplayID(); - } else { - displayID = CGMainDisplayID(); - /* - ### get correct display - const QRect &qrect = widget->window()->geometry(); - CGRect rect = CGRectMake(qrect.x(), qrect.y(), qrect.width(), qrect.height()); - CGDisplayCount throwAway; - CGDisplayErr dErr = CGGetDisplaysWithRect(rect, 1, &displayID, &throwAway); - if (dErr != kCGErrorSuccess) - return macDisplayColorSpace(0); // fall back on main display - */ - } - if ((colorSpace = m_displayColorSpaceHash.value(displayID))) - return colorSpace; - - colorSpace = CGDisplayCopyColorSpace(displayID); - if (colorSpace == 0) - colorSpace = CGColorSpaceCreateDeviceRGB(); - - m_displayColorSpaceHash.insert(displayID, colorSpace); - if (!m_postRoutineRegistered) { - m_postRoutineRegistered = true; - qAddPostRoutine(qt_mac_cleanUpMacColorSpaces); - } - return colorSpace; -} - bool qt_macWindowIsTextured(const QWidget *window) { if (QWindow *w = window->windowHandle()) @@ -2283,7 +2162,7 @@ void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QBrush painter->setClipRegion(rgn); - QCFType cg = qt_mac_cg_context(target); + QMacCGContext cg(target); CGContextSaveGState(cg); HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationInverted); @@ -2357,7 +2236,7 @@ void QMacStyle::polish(QWidget* w) mtinfo.menuType = kThemeMenuTypePopUp; // HIRect rect = CGRectMake(0, 0, px.width(), px.height()); // ### - //HIThemeDrawMenuBackground(&rect, &mtinfo, QCFType(qt_mac_cg_context(&px)), + //HIThemeDrawMenuBackground(&rect, &mtinfo, QMacCGContext(&px)), // kHIThemeOrientationNormal); QPalette pal = w->palette(); QBrush background(px); @@ -7187,158 +7066,6 @@ int QMacStyle::layoutSpacing(QSizePolicy::ControlType control1, return_SIZE(10, 8, 6); // guess } -static void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform) -{ - CGAffineTransform old_xform = CGAffineTransformIdentity; - if (orig_xform) { //setup xforms - old_xform = CGContextGetCTM(hd); - CGContextConcatCTM(hd, CGAffineTransformInvert(old_xform)); - CGContextConcatCTM(hd, *orig_xform); - } - - //do the clipping - CGContextBeginPath(hd); - if (rgn.isEmpty()) { - CGContextAddRect(hd, CGRectMake(0, 0, 0, 0)); - } else { - QCFType shape = qt_mac_toHIMutableShape(rgn); - Q_ASSERT(!HIShapeIsEmpty(shape)); - HIShapeReplacePathInCGContext(shape, hd); - } - CGContextClip(hd); - - if (orig_xform) {//reset xforms - CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd))); - CGContextConcatCTM(hd, old_xform); - } -} - -// move to QRegion? -void qt_mac_scale_region(QRegion *region, qreal scaleFactor) -{ - if (!region || !region->rectCount()) - return; - - QVector scaledRects; - scaledRects.reserve(region->rectCount()); - - for (const QRect &rect : *region) - scaledRects.append(QRect(rect.topLeft() * scaleFactor, rect.size() * scaleFactor)); - - region->setRects(&scaledRects[0], scaledRects.count()); -} - -static CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice); - -namespace { -QMacCGContext::QMacCGContext(QPainter *p) -{ - QPaintEngine *pe = p->paintEngine(); - pe->syncState(); - context = 0; - - int devType = p->device()->devType(); - if (pe->type() == QPaintEngine::Raster - && (devType == QInternal::Widget || - devType == QInternal::Pixmap || - devType == QInternal::Image)) { - - CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pe->paintDevice()); - uint flags = kCGImageAlphaPremultipliedFirst; - flags |= kCGBitmapByteOrder32Host; - - const QImage *image = (const QImage *) pe->paintDevice(); - - context = CGBitmapContextCreate((void *) image->bits(), image->width(), image->height(), - 8, image->bytesPerLine(), colorspace, flags); - - // Invert y axis. - CGContextTranslateCTM(context, 0, image->height()); - CGContextScaleCTM(context, 1, -1); - - const qreal devicePixelRatio = image->devicePixelRatio(); - - if (devType == QInternal::Widget) { - // Set the clip rect which is an intersection of the system clip - // and the painter clip. To make matters more interesting these - // are in device pixels and device-independent pixels, respectively. - QRegion clip = p->paintEngine()->systemClip(); // get system clip in device pixels - QTransform native = p->deviceTransform(); // get device transform. dx/dy is in device pixels - - if (p->hasClipping()) { - QRegion r = p->clipRegion(); // get painter clip, which is in device-independent pixels - qt_mac_scale_region(&r, devicePixelRatio); // scale painter clip to device pixels - r.translate(native.dx(), native.dy()); - if (clip.isEmpty()) - clip = r; - else - clip &= r; - } - qt_mac_clip_cg(context, clip, 0); // clip in device pixels - - // Scale the context so that painting happens in device-independet pixels. - CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); - CGContextTranslateCTM(context, native.dx() / devicePixelRatio, native.dy() / devicePixelRatio); - } else { - // Scale to paint in device-independent pixels. - CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio); - } - } else { - qDebug() << "QMacCGContext:: Unsupported painter devtype type" << devType; - } -} - -} // anonymous namespace - -static CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice) -{ - bool isWidget = (paintDevice->devType() == QInternal::Widget); - return qt_mac_displayColorSpace(isWidget ? static_cast(paintDevice) : 0); -} - -/*! \internal - - Returns the CoreGraphics CGContextRef of the paint device. 0 is - returned if it can't be obtained. It is the caller's responsibility to - CGContextRelease the context when finished using it. - - \warning This function is only available on \macos. - \warning This function is duplicated in the Cocoa platform plugin. -*/ - -CGContextRef qt_mac_cg_context(const QPaintDevice *pdev) -{ - if (pdev->devType() == QInternal::Pixmap) { - const QPixmap *pm = static_cast(pdev); - CGColorSpaceRef colorspace = qt_mac_colorSpaceForDeviceType(pdev); - uint flags = kCGImageAlphaPremultipliedFirst; - flags |= kCGBitmapByteOrder32Host; - CGContextRef ret = 0; - - QPlatformPixmap *data = const_cast(pm)->data_ptr().data(); - if (data->classId() == QPlatformPixmap::RasterClass) { - QImage *image = data->buffer(); - ret = CGBitmapContextCreate(image->bits(), image->width(), image->height(), - 8, image->bytesPerLine(), colorspace, flags); - } else { - qDebug("qt_mac_cg_context: Unsupported pixmap class"); - } - - CGContextTranslateCTM(ret, 0, pm->height()); - qreal devicePixelRatio = pdev->devicePixelRatioF(); - CGContextScaleCTM(ret, devicePixelRatio, devicePixelRatio); - CGContextScaleCTM(ret, 1, -1); - return ret; - } else if (pdev->devType() == QInternal::Widget) { - //CGContextRef ret = static_cast(static_cast(pdev)->macCGHandle()); - ///CGContextRetain(ret); - //return ret; - qDebug("qt_mac_cg_context: not implemented: Widget class"); - return 0; - } - return 0; -} - /* FontHash::FontHash() { -- cgit v1.2.3