Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qcoregraphics.mm
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qcoregraphics_p.h"
5
6#include <private/qcore_mac_p.h>
7#include <qpa/qplatformpixmap.h>
8#include <QtGui/qicon.h>
9#include <QtGui/private/qpaintengine_p.h>
10#include <QtCore/qdebug.h>
11#include <QtCore/qcoreapplication.h>
12#include <QtCore/qoperatingsystemversion.h>
13
15
17
18// ---------------------- Images ----------------------
19
21{
22 CGBitmapInfo bitmapInfo = kCGImageAlphaNone;
23 switch (image.format()) {
25 bitmapInfo = CGBitmapInfo(kCGImageAlphaFirst) | kCGBitmapByteOrder32Host;
26 break;
28 bitmapInfo = CGBitmapInfo(kCGImageAlphaNoneSkipFirst) | kCGBitmapByteOrder32Host;
29 break;
31 bitmapInfo = CGBitmapInfo(kCGImageAlphaPremultipliedLast) | kCGBitmapByteOrder32Big;
32 break;
34 bitmapInfo = CGBitmapInfo(kCGImageAlphaLast) | kCGBitmapByteOrder32Big;
35 break;
37 bitmapInfo = CGBitmapInfo(kCGImageAlphaNoneSkipLast) | kCGBitmapByteOrder32Big;
38 break;
40 bitmapInfo = CGBitmapInfo(kCGImageAlphaPremultipliedFirst) | kCGBitmapByteOrder32Host;
41 break;
42 default: break;
43 }
44 return bitmapInfo;
45}
46
47CGImageRef qt_mac_toCGImage(const QImage &inImage)
48{
49 CGImageRef cgImage = inImage.toCGImage();
50 if (cgImage)
51 return cgImage;
52
53 // Convert image data to a known-good format if the fast conversion fails.
54 return inImage.convertToFormat(QImage::Format_ARGB32_Premultiplied).toCGImage();
55}
56
58{
59 static const auto deleter = [](void *image, const void *, size_t) { delete static_cast<QImage *>(image); };
60 QCFType<CGDataProviderRef> dataProvider =
61 CGDataProviderCreateWithData(new QImage(image), image.bits(),
62 image.sizeInBytes(), deleter);
63
64 return CGImageMaskCreate(image.width(), image.height(), 8, image.depth(),
65 image.bytesPerLine(), dataProvider, NULL, false);
66}
67
68void qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGImageRef inImage)
69{
70 CGContextSaveGState( inContext );
71 CGContextTranslateCTM (inContext, 0, inBounds->origin.y + CGRectGetMaxY(*inBounds));
72 CGContextScaleCTM(inContext, 1, -1);
73
74 CGContextDrawImage(inContext, *inBounds, inImage);
75
76 CGContextRestoreGState(inContext);
77}
78
80{
81 const size_t w = CGImageGetWidth(image),
82 h = CGImageGetHeight(image);
84 ret.fill(Qt::transparent);
85 CGRect rect = CGRectMake(0, 0, w, h);
88 return ret;
89}
90
91#ifdef Q_OS_MACOS
92
94
95@implementation NSImage (QtExtras)
96+ (instancetype)imageFromQImage:(const QImage &)image
97{
98 if (image.isNull())
99 return nil;
100
101 QCFType<CGImageRef> cgImage = image.toCGImage();
102 if (!cgImage)
103 return nil;
104
105 // We set up the NSImage using an explicit NSBitmapImageRep, instead of
106 // [NSImage initWithCGImage:size:], as the former allows us to correctly
107 // set the size of the representation to account for the device pixel
108 // ratio of the original image, which in turn will be reflected by the
109 // NSImage.
110 auto nsImage = [[NSImage alloc] initWithSize:NSZeroSize];
111 auto *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
112 imageRep.size = image.deviceIndependentSize().toCGSize();
113 [nsImage addRepresentation:[imageRep autorelease]];
114 Q_ASSERT(CGSizeEqualToSize(nsImage.size, imageRep.size));
115
116 return [nsImage autorelease];
117}
118
119+ (instancetype)imageFromQIcon:(const QIcon &)icon
120{
121 return [NSImage imageFromQIcon:icon withSize:0];
122}
123
124+ (instancetype)imageFromQIcon:(const QIcon &)icon withSize:(int)size
125{
126 if (icon.isNull())
127 return nil;
128
129 auto availableSizes = icon.availableSizes();
130 if (availableSizes.isEmpty() && size > 0)
131 availableSizes << QSize(size, size);
132
133 auto nsImage = [[[NSImage alloc] initWithSize:NSZeroSize] autorelease];
134
135 for (QSize size : std::as_const(availableSizes)) {
137 if (image.isNull())
138 continue;
139
140 QCFType<CGImageRef> cgImage = image.toCGImage();
141 if (!cgImage)
142 continue;
143
144 auto *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
145 imageRep.size = image.deviceIndependentSize().toCGSize();
146 [nsImage addRepresentation:[imageRep autorelease]];
147 }
148
149 if (!nsImage.representations.count)
150 return nil;
151
152 [nsImage setTemplate:icon.isMask()];
153
154 if (size)
155 nsImage.size = CGSizeMake(size, size);
156
157 return nsImage;
158}
159@end
160
162
163QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size)
164{
165 const NSSize pixmapSize = NSMakeSize(size.width(), size.height());
166 QPixmap pixmap(pixmapSize.width, pixmapSize.height);
168 [image setSize:pixmapSize];
169 const NSRect iconRect = NSMakeRect(0, 0, pixmapSize.width, pixmapSize.height);
171 if (!ctx)
172 return QPixmap();
173 NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithCGContext:ctx flipped:YES];
174 if (!gc)
175 return QPixmap();
176 [NSGraphicsContext saveGraphicsState];
177 [NSGraphicsContext setCurrentContext:gc];
178 [image drawInRect:iconRect fromRect:iconRect operation:NSCompositingOperationSourceOver fraction:1.0 respectFlipped:YES hints:nil];
179 [NSGraphicsContext restoreGraphicsState];
180 return pixmap;
181}
182
183#endif // Q_OS_MACOS
184
185// ---------------------- Colors and Brushes ----------------------
186
188{
189 QColor qtColor;
190 CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color));
191 const CGFloat *components = CGColorGetComponents(color);
192 if (model == kCGColorSpaceModelRGB) {
193 qtColor.setRgbF(components[0], components[1], components[2], components[3]);
194 } else if (model == kCGColorSpaceModelCMYK) {
195 qtColor.setCmykF(components[0], components[1], components[2], components[3]);
196 } else if (model == kCGColorSpaceModelMonochrome) {
197 qtColor.setRgbF(components[0], components[0], components[0], components[1]);
198 } else {
199 // Colorspace we can't deal with.
200 qWarning("Qt: qt_mac_toQColor: cannot convert from colorspace model: %d", model);
201 Q_ASSERT(false);
202 }
203 return qtColor;
204}
205
206#ifdef Q_OS_MACOS
207QColor qt_mac_toQColor(const NSColor *color)
208{
209 QColor qtColor;
210 switch (color.type) {
211 case NSColorTypeComponentBased: {
212 const NSColorSpace *colorSpace = [color colorSpace];
213 if (colorSpace == NSColorSpace.genericRGBColorSpace
214 && color.numberOfComponents == 4) { // rbga
216 [color getComponents:components];
217 qtColor.setRgbF(components[0], components[1], components[2], components[3]);
218 break;
219 } else if (colorSpace == NSColorSpace.genericCMYKColorSpace
220 && color.numberOfComponents == 5) { // cmyk + alpha
222 [color getComponents:components];
223 qtColor.setCmykF(components[0], components[1], components[2], components[3], components[4]);
224 break;
225 }
226 }
228 default: {
229 const NSColor *tmpColor = [color colorUsingColorSpace:NSColorSpace.genericRGBColorSpace];
230 CGFloat red = 0, green = 0, blue = 0, alpha = 0;
231 [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha];
232 qtColor.setRgbF(red, green, blue, alpha);
233 break;
234 }
235 }
236
237 return qtColor;
238}
239#endif
240
242{
243 QBrush qtBrush;
244 CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color));
245 if (model == kCGColorSpaceModelPattern) {
246 // Colorspace we can't deal with; the color is drawn directly using a callback.
247 qWarning("Qt: qt_mac_toQBrush: cannot convert from colorspace model: %d", model);
248 Q_ASSERT(false);
249 } else {
250 qtBrush.setStyle(Qt::SolidPattern);
252 }
253 return qtBrush;
254}
255
256#ifdef Q_OS_MACOS
257static bool qt_mac_isSystemColorOrInstance(const NSColor *color, NSString *colorNameComponent, NSString *className)
258{
259 // We specifically do not want isKindOfClass: here
260 if ([color.className isEqualToString:className]) // NSPatternColorSpace
261 return true;
262 if (color.type == NSColorTypeCatalog &&
263 [color.catalogNameComponent isEqualToString:@"System"] &&
264 [color.colorNameComponent isEqualToString:colorNameComponent])
265 return true;
266 return false;
267}
268
269QBrush qt_mac_toQBrush(const NSColor *color, QPalette::ColorGroup colorGroup)
270{
271 QBrush qtBrush;
272
273 // QTBUG-49773: This calls NSDrawMenuItemBackground to render a 1 by n gradient; could use HITheme
274 if ([color.className isEqualToString:@"NSMenuItemHighlightColor"]) {
275 qWarning("Qt: qt_mac_toQBrush: cannot convert from NSMenuItemHighlightColor");
276 return qtBrush;
277 }
278
279 // Not a catalog color or a manifestation of System.windowBackgroundColor;
280 // only retrieved from NSWindow.backgroundColor directly
281 if ([color.className isEqualToString:@"NSMetalPatternColor"]) {
282 // NSTexturedBackgroundWindowMask, could theoretically handle this without private API by
283 // creating a window with the appropriate properties and then calling NSWindow.backgroundColor.patternImage,
284 // which returns a texture sized 1 by (window height, including frame), backed by a CGPattern
285 // which follows the window key state... probably need to allow QBrush to store a function pointer
286 // like CGPattern does
287 qWarning("Qt: qt_mac_toQBrush: cannot convert from NSMetalPatternColor");
288 return qtBrush;
289 }
290
291 // No public API to get these colors/stops;
292 // both accurately obtained through runtime object inspection on OS X 10.11
293 // (the NSColor object has NSGradient i-vars for both color groups)
294 if (qt_mac_isSystemColorOrInstance(color, @"_sourceListBackgroundColor", @"NSSourceListBackgroundColor")) {
295 QLinearGradient gradient;
296 if (colorGroup == QPalette::Active) {
297 gradient.setColorAt(0, QColor(233, 237, 242));
298 gradient.setColorAt(0.5, QColor(225, 229, 235));
299 gradient.setColorAt(1, QColor(209, 216, 224));
300 } else {
301 gradient.setColorAt(0, QColor(248, 248, 248));
302 gradient.setColorAt(0.5, QColor(240, 240, 240));
303 gradient.setColorAt(1, QColor(235, 235, 235));
304 }
305 return QBrush(gradient);
306 }
307
308 // A couple colors are special... they are actually instances of NSGradientPatternColor, which
309 // override set/setFill/setStroke to instead initialize an internal color
310 // ([NSColor colorWithCalibratedWhite:0.909804 alpha:1.000000]) while still returning the
311 // ruled lines pattern image (from OS X 10.4) to the user from -[NSColor patternImage]
312 // (and providing no public API to get the underlying color without this insanity)
313 if (qt_mac_isSystemColorOrInstance(color, @"controlColor", @"NSGradientPatternColor") ||
314 qt_mac_isSystemColorOrInstance(color, @"windowBackgroundColor", @"NSGradientPatternColor")) {
315 qtBrush.setStyle(Qt::SolidPattern);
316 qtBrush.setColor(qt_mac_toQColor(color.CGColor));
317 return qtBrush;
318 }
319
320 if (color.type == NSColorTypePattern) {
321 NSImage *patternImage = color.patternImage;
322 const QSizeF sz(patternImage.size.width, patternImage.size.height);
323 // FIXME: QBrush is not resolution independent (QTBUG-49774)
324 qtBrush.setTexture(qt_mac_toQPixmap(patternImage, sz));
325 } else {
326 qtBrush.setStyle(Qt::SolidPattern);
328 }
329 return qtBrush;
330}
331#endif
332
333// ---------------------- Geometry Helpers ----------------------
334
335void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform)
336{
337 CGAffineTransform old_xform = CGAffineTransformIdentity;
338 if (orig_xform) { //setup xforms
339 old_xform = CGContextGetCTM(hd);
340 CGContextConcatCTM(hd, CGAffineTransformInvert(old_xform));
341 CGContextConcatCTM(hd, *orig_xform);
342 }
343
344 //do the clipping
345 CGContextBeginPath(hd);
346 if (rgn.isEmpty()) {
347 CGContextAddRect(hd, CGRectMake(0, 0, 0, 0));
348 } else {
349 for (const QRect &r : rgn) {
350 CGRect mac_r = CGRectMake(r.x(), r.y(), r.width(), r.height());
351 CGContextAddRect(hd, mac_r);
352 }
353 }
354 CGContextClip(hd);
355
356 if (orig_xform) {//reset xforms
357 CGContextConcatCTM(hd, CGAffineTransformInvert(CGContextGetCTM(hd)));
358 CGContextConcatCTM(hd, old_xform);
359 }
360}
361
362// move to QRegion?
363void qt_mac_scale_region(QRegion *region, qreal scaleFactor)
364{
365 if (!region || !region->rectCount())
366 return;
367
368 QVector<QRect> scaledRects;
369 scaledRects.reserve(region->rectCount());
370
371 for (const QRect &rect : *region)
372 scaledRects.append(QRect(rect.topLeft() * scaleFactor, rect.size() * scaleFactor));
373
374 region->setRects(&scaledRects[0], scaledRects.count());
375}
376
377// ---------------------- QMacCGContext ----------------------
378
380{
381 initialize(paintDevice);
382}
383
384void QMacCGContext::initialize(QPaintDevice *paintDevice)
385{
386 // Find the underlying QImage of the paint device
387 switch (int deviceType = paintDevice->devType()) {
388 case QInternal::Pixmap: {
389 if (auto *platformPixmap = static_cast<QPixmap*>(paintDevice)->handle()) {
392 else
393 qWarning() << "QMacCGContext: Unsupported pixmap class" << platformPixmap->classId();
394 } else {
395 qWarning() << "QMacCGContext: Empty platformPixmap";
396 }
397 break;
398 }
399 case QInternal::Image:
400 initialize(static_cast<const QImage *>(paintDevice));
401 break;
403 qWarning() << "QMacCGContext: not implemented: Widget class";
404 break;
405 default:
406 qWarning() << "QMacCGContext:: Unsupported paint device type" << deviceType;
407 }
408}
409
411{
412 QPaintEngine *paintEngine = painter->paintEngine();
413
414 // Handle the case of QMacPrintEngine, which has an internal QCoreGraphicsPaintEngine
415 while (QPaintEngine *aggregateEngine = QPaintEnginePrivate::get(paintEngine)->aggregateEngine())
416 paintEngine = aggregateEngine;
417
418 paintEngine->syncState();
419
420 if (Qt::HANDLE handle = QPaintEnginePrivate::get(paintEngine)->nativeHandle()) {
421 context = static_cast<CGContextRef>(handle);
422 return;
423 }
424
425 if (paintEngine->type() != QPaintEngine::Raster) {
426 qWarning() << "QMacCGContext:: Unsupported paint engine type" << paintEngine->type();
427 return;
428 }
429
430 // The raster paint engine always operates on a QImage
431 Q_ASSERT(paintEngine->paintDevice()->devType() == QInternal::Image);
432
433 // On behalf of one of these supported painter devices
434 switch (int painterDeviceType = painter->device()->devType()) {
436 case QInternal::Image:
438 break;
439 default:
440 qWarning() << "QMacCGContext:: Unsupported paint device type" << painterDeviceType;
441 return;
442 }
443
444 // Applying the clip is so entangled with the rest of the context setup
445 // that for simplicity we just pass in the painter.
446 initialize(static_cast<const QImage *>(paintEngine->paintDevice()), painter);
447}
448
449void QMacCGContext::initialize(const QImage *image, QPainter *painter)
450{
451 QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
452 context = CGBitmapContextCreate((void *)image->bits(), image->width(), image->height(), 8,
453 image->bytesPerLine(), colorSpace, qt_mac_bitmapInfoForImage(*image));
454
455 // Invert y axis
456 CGContextTranslateCTM(context, 0, image->height());
457 CGContextScaleCTM(context, 1, -1);
458
459 const qreal devicePixelRatio = image->devicePixelRatio();
460
462 // Set the clip rect which is an intersection of the system clip and the painter clip
465
466 if (painter->hasClipping()) {
467 // To make matters more interesting the painter clip is in device-independent pixels,
468 // so we need to scale it to match the device-pixels of the system clip.
469 QRegion painterClip = painter->clipRegion();
470 qt_mac_scale_region(&painterClip, devicePixelRatio);
471
472 painterClip.translate(deviceTransform.dx(), deviceTransform.dy());
473
474 if (clip.isEmpty())
475 clip = painterClip;
476 else
477 clip &= painterClip;
478 }
479
480 qt_mac_clip_cg(context, clip, nullptr);
481
482 CGContextTranslateCTM(context, deviceTransform.dx(), deviceTransform.dy());
483 }
484
485 // Scale the context so that painting happens in device-independent pixels
486 CGContextScaleCTM(context, devicePixelRatio, devicePixelRatio);
487}
488
\inmodule QtGui
Definition qbrush.h:30
void setColor(const QColor &color)
Sets the brush color to the given color.
Definition qbrush.cpp:687
void setStyle(Qt::BrushStyle)
Sets the brush style to style.
Definition qbrush.cpp:655
void setTexture(const QPixmap &pixmap)
Sets the brush pixmap to pixmap.
Definition qbrush.cpp:728
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
void setRgbF(float r, float g, float b, float a=1.0)
Sets the color channels of this color to r (red), g (green), b (blue) and a (alpha,...
Definition qcolor.cpp:1317
void setCmykF(float c, float m, float y, float k, float a=1.0)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qcolor.cpp:2712
void setColorAt(qreal pos, const QColor &color)
Creates a stop point at the given position with the given color.
Definition qbrush.cpp:1563
The QIcon class provides scalable icons in different modes and states.
Definition qicon.h:20
bool isNull() const
Returns true if the icon is empty; otherwise returns false.
Definition qicon.cpp:973
QList< QSize > availableSizes(Mode mode=Normal, State state=Off) const
Definition qicon.cpp:1098
QPixmap pixmap(const QSize &size, Mode mode=Normal, State state=Off) const
Returns a pixmap with the requested size, mode, and state, generating one if necessary.
Definition qicon.cpp:788
\inmodule QtGui
Definition qimage.h:37
@ Format_RGBA8888
Definition qimage.h:59
@ Format_RGB32
Definition qimage.h:46
@ Format_RGBA8888_Premultiplied
Definition qimage.h:60
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
@ Format_ARGB32
Definition qimage.h:47
@ Format_RGBX8888
Definition qimage.h:58
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const &
Definition qimage.h:124
\inmodule QtGui
Definition qbrush.h:394
Definition qlist.h:74
qsizetype count() const noexcept
Definition qlist.h:387
void reserve(qsizetype size)
Definition qlist.h:746
void append(parameter_type t)
Definition qlist.h:441
QMacCGContext()=default
virtual int devType() const
static QPaintEnginePrivate * get(QPaintEngine *paintEngine)
\inmodule QtGui
virtual Type type() const =0
Reimplement this function to return the paint engine \l{Type}.
QRegion systemClip() const
QPaintDevice * paintDevice() const
Returns the device that this engine is painting on, if painting is active; otherwise returns \nullptr...
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
QPaintDevice * device() const
Returns the paint device on which this painter is currently painting, or \nullptr if the painter is n...
QPaintEngine * paintEngine() const
Returns the paint engine that the painter is currently operating on if the painter is active; otherwi...
QRegion clipRegion() const
Returns the currently set clip region.
const QTransform & deviceTransform() const
Returns the matrix that transforms from logical coordinates to device coordinates of the platform dep...
bool hasClipping() const
Returns true if clipping has been set; otherwise returns false.
ColorGroup
\value Disabled \value Active \value Inactive \value Normal synonym for Active
Definition qpalette.h:48
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
QImage toImage() const
Converts the pixmap to a QImage.
Definition qpixmap.cpp:412
virtual QImage * buffer()
ClassId classId() const
\inmodule QtCore\reentrant
Definition qrect.h:30
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
int rectCount() const noexcept
void translate(int dx, int dy)
Translates (moves) the region dx along the X axis and dy along the Y axis.
void setRects(const QRect *rect, int num)
Sets the region using the array of rectangles specified by rects and number.
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
\inmodule QtCore
Definition qsize.h:207
\inmodule QtCore
Definition qsize.h:25
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
EGLContext ctx
rect
[4]
Combined button and popup list for selecting options.
@ transparent
Definition qnamespace.h:46
void * HANDLE
@ SolidPattern
Definition image.cpp:4
static void * context
float CGFloat
#define Q_FALLTHROUGH()
void qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGImageRef inImage)
QBrush qt_mac_toQBrush(CGColorRef color)
void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform)
QColor qt_mac_toQColor(CGColorRef color)
QImage qt_mac_toQImage(CGImageRef image)
void qt_mac_scale_region(QRegion *region, qreal scaleFactor)
CGImageRef qt_mac_toCGImage(const QImage &inImage)
QT_USE_NAMESPACE QT_BEGIN_NAMESPACE CGBitmapInfo qt_mac_bitmapInfoForImage(const QImage &image)
CGImageRef qt_mac_toCGImageMask(const QImage &image)
static bool initialize()
Definition qctf.cpp:67
#define qWarning
Definition qlogging.h:162
return ret
GLuint64 GLenum void * handle
GLfloat GLfloat GLfloat w
[0]
GLint GLenum GLint components
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLfloat GLfloat GLfloat GLfloat h
GLbyte GLbyte blue
Definition qopenglext.h:385
GLfloat GLfloat GLfloat alpha
Definition qopenglext.h:418
GLbyte green
Definition qopenglext.h:385
struct CGContext * CGContextRef
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
double qreal
Definition qtypes.h:92
static QWindowsDirect2DPlatformPixmap * platformPixmap(QPixmap *p)
static QInputDevice::DeviceType deviceType(const UINT cursorType)
const char className[16]
[1]
Definition qwizard.cpp:100
QSqlQueryModel * model
[16]
rect deviceTransform(view->viewportTransform()).map(QPointF(0
widget render & pixmap
QPainter painter(this)
[7]
QGraphicsSvgItem * red