diff options
Diffstat (limited to 'src/gui/painting/qcoregraphics.mm')
-rw-r--r-- | src/gui/painting/qcoregraphics.mm | 215 |
1 files changed, 125 insertions, 90 deletions
diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm index e2497eaadb..27b46202f5 100644 --- a/src/gui/painting/qcoregraphics.mm +++ b/src/gui/painting/qcoregraphics.mm @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** 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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qcoregraphics_p.h" @@ -47,6 +11,8 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qoperatingsystemversion.h> +QT_USE_NAMESPACE + QT_BEGIN_NAMESPACE // ---------------------- Images ---------------------- @@ -56,22 +22,22 @@ CGBitmapInfo qt_mac_bitmapInfoForImage(const QImage &image) CGBitmapInfo bitmapInfo = kCGImageAlphaNone; switch (image.format()) { case QImage::Format_ARGB32: - bitmapInfo = kCGImageAlphaFirst | kCGBitmapByteOrder32Host; + bitmapInfo = CGBitmapInfo(kCGImageAlphaFirst) | kCGBitmapByteOrder32Host; break; case QImage::Format_RGB32: - bitmapInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; + bitmapInfo = CGBitmapInfo(kCGImageAlphaNoneSkipFirst) | kCGBitmapByteOrder32Host; break; case QImage::Format_RGBA8888_Premultiplied: - bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big; + bitmapInfo = CGBitmapInfo(kCGImageAlphaPremultipliedLast) | kCGBitmapByteOrder32Big; break; case QImage::Format_RGBA8888: - bitmapInfo = kCGImageAlphaLast | kCGBitmapByteOrder32Big; + bitmapInfo = CGBitmapInfo(kCGImageAlphaLast) | kCGBitmapByteOrder32Big; break; case QImage::Format_RGBX8888: - bitmapInfo = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big; + bitmapInfo = CGBitmapInfo(kCGImageAlphaNoneSkipLast) | kCGBitmapByteOrder32Big; break; case QImage::Format_ARGB32_Premultiplied: - bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; + bitmapInfo = CGBitmapInfo(kCGImageAlphaPremultipliedFirst) | kCGBitmapByteOrder32Host; break; default: break; } @@ -124,49 +90,81 @@ QImage qt_mac_toQImage(CGImageRef image) #ifdef Q_OS_MACOS -static NSImage *qt_mac_cgimage_to_nsimage(CGImageRef image) +QT_END_NAMESPACE + +@implementation NSImage (QtExtras) ++ (instancetype)imageFromQImage:(const QImage &)image { - NSImage *newImage = [[NSImage alloc] initWithCGImage:image size:NSZeroSize]; - return newImage; + if (image.isNull()) + return nil; + + QCFType<CGImageRef> cgImage = image.toCGImage(); + if (!cgImage) + return nil; + + // We set up the NSImage using an explicit NSBitmapImageRep, instead of + // [NSImage initWithCGImage:size:], as the former allows us to correctly + // set the size of the representation to account for the device pixel + // ratio of the original image, which in turn will be reflected by the + // NSImage. + auto nsImage = [[NSImage alloc] initWithSize:NSZeroSize]; + auto *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; + imageRep.size = image.deviceIndependentSize().toCGSize(); + [nsImage addRepresentation:[imageRep autorelease]]; + Q_ASSERT(CGSizeEqualToSize(nsImage.size, imageRep.size)); + + return [nsImage autorelease]; } -NSImage *qt_mac_create_nsimage(const QPixmap &pm) ++ (instancetype)imageFromQIcon:(const QIcon &)icon { - if (pm.isNull()) - return 0; - QImage image = pm.toImage(); - CGImageRef cgImage = qt_mac_toCGImage(image); - NSImage *nsImage = qt_mac_cgimage_to_nsimage(cgImage); - nsImage.size = (pm.size() / pm.devicePixelRatioF()).toCGSize(); - CGImageRelease(cgImage); - return nsImage; + return [NSImage imageFromQIcon:icon withSize:0]; } -NSImage *qt_mac_create_nsimage(const QIcon &icon, int defaultSize) ++ (instancetype)imageFromQIcon:(const QIcon &)icon withSize:(int)size { if (icon.isNull()) return nil; - NSImage *nsImage = [[NSImage alloc] init]; - QList<QSize> availableSizes = icon.availableSizes(); - if (availableSizes.isEmpty() && defaultSize > 0) - availableSizes << QSize(defaultSize, defaultSize); - for (QSize size : qAsConst(availableSizes)) { - QPixmap pm = icon.pixmap(size); - if (pm.isNull()) + auto availableSizes = icon.availableSizes(); + if (availableSizes.isEmpty() && size > 0) + availableSizes << QSize(size, size); + + auto nsImage = [[[NSImage alloc] initWithSize:NSZeroSize] autorelease]; + + for (QSize size : std::as_const(availableSizes)) { + QImage image = icon.pixmap(size).toImage(); + if (image.isNull()) continue; - QImage image = pm.toImage(); - CGImageRef cgImage = qt_mac_toCGImage(image); - NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; - [nsImage addRepresentation:imageRep]; - [imageRep release]; - CGImageRelease(cgImage); + + QCFType<CGImageRef> cgImage = image.toCGImage(); + if (!cgImage) + continue; + + auto *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; + imageRep.size = image.deviceIndependentSize().toCGSize(); + [nsImage addRepresentation:[imageRep autorelease]]; } + + if (!nsImage.representations.count) + return nil; + + [nsImage setTemplate:icon.isMask()]; + + if (size) + nsImage.size = CGSizeMake(size, size); + return nsImage; } +@end + +QT_BEGIN_NAMESPACE QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size) { + // ### TODO: add parameter so that we can decide whether to maintain the aspect + // ratio of the image (positioning the image inside the pixmap of size \a size), + // or whether we want to fill the resulting pixmap by stretching the image. const NSSize pixmapSize = NSMakeSize(size.width(), size.height()); QPixmap pixmap(pixmapSize.width, pixmapSize.height); pixmap.fill(Qt::transparent); @@ -187,6 +185,25 @@ QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size) #endif // Q_OS_MACOS +#ifdef QT_PLATFORM_UIKIT + +QImage qt_mac_toQImage(const UIImage *image, QSizeF size) +{ + // ### TODO: same as above + QImage ret(size.width(), size.height(), QImage::Format_ARGB32_Premultiplied); + ret.fill(Qt::transparent); + QMacCGContext ctx(&ret); + if (!ctx) + return QImage(); + UIGraphicsPushContext(ctx); + const CGRect rect = CGRectMake(0, 0, size.width(), size.height()); + [image drawInRect:rect]; + UIGraphicsPopContext(); + return ret; +} + +#endif // QT_PLATFORM_UIKIT + // ---------------------- Colors and Brushes ---------------------- QColor qt_mac_toQColor(CGColorRef color) @@ -212,18 +229,33 @@ QColor qt_mac_toQColor(CGColorRef color) QColor qt_mac_toQColor(const NSColor *color) { QColor qtColor; - NSString *colorSpace = [color colorSpaceName]; - if (colorSpace == NSDeviceCMYKColorSpace) { - CGFloat cyan, magenta, yellow, black, alpha; - [color getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha]; - qtColor.setCmykF(cyan, magenta, yellow, black, alpha); - } else { - NSColor *tmpColor; - tmpColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace]; - CGFloat red, green, blue, alpha; + switch (color.type) { + case NSColorTypeComponentBased: { + const NSColorSpace *colorSpace = [color colorSpace]; + if (colorSpace == NSColorSpace.genericRGBColorSpace + && color.numberOfComponents == 4) { // rbga + CGFloat components[4]; + [color getComponents:components]; + qtColor.setRgbF(components[0], components[1], components[2], components[3]); + break; + } else if (colorSpace == NSColorSpace.genericCMYKColorSpace + && color.numberOfComponents == 5) { // cmyk + alpha + CGFloat components[5]; + [color getComponents:components]; + qtColor.setCmykF(components[0], components[1], components[2], components[3], components[4]); + break; + } + } + Q_FALLTHROUGH(); + default: { + const NSColor *tmpColor = [color colorUsingColorSpace:NSColorSpace.genericRGBColorSpace]; + CGFloat red = 0, green = 0, blue = 0, alpha = 0; [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha]; qtColor.setRgbF(red, green, blue, alpha); + break; + } } + return qtColor; } #endif @@ -249,9 +281,9 @@ static bool qt_mac_isSystemColorOrInstance(const NSColor *color, NSString *color // We specifically do not want isKindOfClass: here if ([color.className isEqualToString:className]) // NSPatternColorSpace return true; - if ([color.catalogNameComponent isEqualToString:@"System"] && - [color.colorNameComponent isEqualToString:colorNameComponent] && - [color.colorSpaceName isEqualToString:NSNamedColorSpace]) + if (color.type == NSColorTypeCatalog && + [color.catalogNameComponent isEqualToString:@"System"] && + [color.colorNameComponent isEqualToString:colorNameComponent]) return true; return false; } @@ -307,8 +339,8 @@ QBrush qt_mac_toQBrush(const NSColor *color, QPalette::ColorGroup colorGroup) return qtBrush; } - if (NSColor *patternColor = [color colorUsingColorSpaceName:NSPatternColorSpace]) { - NSImage *patternImage = patternColor.patternImage; + if (color.type == NSColorTypePattern) { + NSImage *patternImage = color.patternImage; const QSizeF sz(patternImage.size.width, patternImage.size.height); // FIXME: QBrush is not resolution independent (QTBUG-49774) qtBrush.setTexture(qt_mac_toQPixmap(patternImage, sz)); @@ -376,11 +408,14 @@ void QMacCGContext::initialize(QPaintDevice *paintDevice) // Find the underlying QImage of the paint device switch (int deviceType = paintDevice->devType()) { case QInternal::Pixmap: { - auto *platformPixmap = static_cast<QPixmap*>(paintDevice)->handle(); - if (platformPixmap && platformPixmap->classId() == QPlatformPixmap::RasterClass) - initialize(platformPixmap->buffer()); - else - qWarning() << "QMacCGContext: Unsupported pixmap class" << platformPixmap->classId(); + if (auto *platformPixmap = static_cast<QPixmap*>(paintDevice)->handle()) { + if (platformPixmap->classId() == QPlatformPixmap::RasterClass) + initialize(platformPixmap->buffer()); + else + qWarning() << "QMacCGContext: Unsupported pixmap class" << platformPixmap->classId(); + } else { + qWarning() << "QMacCGContext: Empty platformPixmap"; + } break; } case QInternal::Image: @@ -464,7 +499,7 @@ void QMacCGContext::initialize(const QImage *image, QPainter *painter) clip &= painterClip; } - qt_mac_clip_cg(context, clip, 0); + qt_mac_clip_cg(context, clip, nullptr); CGContextTranslateCTM(context, deviceTransform.dx(), deviceTransform.dy()); } |