//----------------------------------------------------------------------------- void CGDrawContext::lineTo (const CPoint& point) { CGContextRef context = beginCGContext (true, currentState.drawMode.integralMode ()); if (context) { applyLineStyle (context); if ((((int32_t)currentState.frameWidth) % 2)) CGContextTranslateCTM (context, 0.5f, -0.5f); CGContextBeginPath (context); if (currentState.drawMode.integralMode ()) { CGContextMoveToPoint (context, round (currentState.penLoc.h), round (currentState.penLoc.v)); CGContextAddLineToPoint (context, round (point.h), round (point.v)); } else { CGContextMoveToPoint (context, currentState.penLoc.h, currentState.penLoc.v); CGContextAddLineToPoint (context, point.h, point.v); } CGContextDrawPath (context, kCGPathStroke); releaseCGContext (context); } currentState.penLoc = point; }
//----------------------------------------------------------------------------- void CGDrawContext::drawArc (const CRect &rect, const float _startAngle, const float _endAngle, const CDrawStyle drawStyle) // in degree { CGContextRef context = beginCGContext (true, getDrawMode ().integralMode ()); if (context) { CGPathDrawingMode m; switch (drawStyle) { case kDrawFilled : m = kCGPathFill; break; case kDrawFilledAndStroked : m = kCGPathFillStroke; break; default : m = kCGPathStroke; break; } applyLineStyle (context); CGContextBeginPath (context); CGDrawContextInternal::addOvalToPath (context, CPoint (rect.left + rect.getWidth () / 2., rect.top + rect.getHeight () / 2.), static_cast<CGFloat> (rect.getWidth () / 2.), static_cast<CGFloat> (rect.getHeight () / 2.), _startAngle, _endAngle); CGContextDrawPath (context, m); releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::drawLines (const CPoint* points, const int32_t& numLines) { CGContextRef context = beginCGContext (true, currentState.drawMode.integralMode ()); if (context) { applyLineStyle (context); if ((((int32_t)currentState.frameWidth) % 2)) CGContextTranslateCTM (context, 0.5f, -0.5f); CGPoint* cgPoints = new CGPoint[numLines*2]; for (int32_t i = 0; i < numLines * 2; i += 2) { if (currentState.drawMode.integralMode ()) { cgPoints[i].x = round (points[i].x); cgPoints[i+1].x = round (points[i+1].x); cgPoints[i].y = round (points[i].y); cgPoints[i+1].y = round (points[i+1].y); } else { cgPoints[i].x = points[i].x; cgPoints[i+1].x = points[i+1].x; cgPoints[i].y = points[i].y; cgPoints[i+1].y = points[i+1].y; } } CGContextStrokeLineSegments (context, cgPoints, numLines*2); delete [] cgPoints; releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::drawRect (const CRect &rect, const CDrawStyle drawStyle) { CGContextRef context = beginCGContext (true, currentState.drawMode.integralMode ()); if (context) { CGPathDrawingMode m; switch (drawStyle) { case kDrawFilled : m = kCGPathFill; break; case kDrawFilledAndStroked : m = kCGPathFillStroke; break; default : m = kCGPathStroke; break; } applyLineStyle (context); CGRect r; if (currentState.drawMode.integralMode ()) { r = CGRectMake (round (rect.left), round (rect.top + 1), round (rect.width () - 1), round (rect.height () - 1)); } else { r = CGRectMake (rect.left, rect.top + 1, rect.width () - 1, rect.height () - 1); } if ((((int32_t)currentState.frameWidth) % 2)) CGContextTranslateCTM (context, 0.5f, -0.5f); CGContextBeginPath (context); CGContextAddRect (context, r); CGContextDrawPath (context, m); releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::drawEllipse (const CRect &rect, const CDrawStyle drawStyle) { CGContextRef context = beginCGContext (true, getDrawMode ().integralMode ()); if (context) { CGRect r = CGRectMake (static_cast<CGFloat> (rect.left), static_cast<CGFloat> (rect.top + 1), static_cast<CGFloat> (rect.getWidth () - 1), static_cast<CGFloat> (rect.getHeight () - 1)); CGPathDrawingMode m; switch (drawStyle) { case kDrawFilled : m = kCGPathFill; break; case kDrawFilledAndStroked : m = kCGPathFillStroke; break; default : m = kCGPathStroke; break; } applyLineStyle (context); if (getDrawMode ().integralMode ()) { r = pixelAlligned (r); applyLineWidthCTM (context); } CGContextAddEllipseInRect (context, r); CGContextDrawPath (context, m); releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::drawLines (const LineList& lines) { if (lines.size () == 0) return; CGContextRef context = beginCGContext (true, getDrawMode ().integralMode ()); if (context) { applyLineStyle (context); CGPoint* cgPoints = new CGPoint[lines.size () * 2]; uint32_t index = 0; VSTGUI_RANGE_BASED_FOR_LOOP(LineList, lines, LinePair, line) cgPoints[index] = CGPointFromCPoint (line.first); cgPoints[index+1] = CGPointFromCPoint (line.second); if (getDrawMode ().integralMode ()) { cgPoints[index] = pixelAlligned (cgPoints[index]); cgPoints[index+1] = pixelAlligned (cgPoints[index+1]); } index += 2; VSTGUI_RANGE_BASED_FOR_LOOP_END if (getDrawMode ().integralMode ()) { int32_t frameWidth = static_cast<int32_t> (currentState.frameWidth); if (frameWidth % 2) CGContextTranslateCTM (context, 0.5, 0.5); } CGContextStrokeLineSegments (context, cgPoints, lines.size () * 2); delete [] cgPoints; releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::drawLine (const LinePair& line) { CGContextRef context = beginCGContext (true, getDrawMode ().integralMode ()); if (context) { applyLineStyle (context); CGContextBeginPath (context); CGPoint first = CGPointFromCPoint (line.first); CGPoint second = CGPointFromCPoint (line.second); if (getDrawMode ().integralMode ()) { first = pixelAlligned (first); second = pixelAlligned (second); int32_t frameWidth = static_cast<int32_t> (currentState.frameWidth); if (frameWidth % 2) CGContextTranslateCTM (context, 0.5, 0.5); } CGContextMoveToPoint (context, first.x, first.y); CGContextAddLineToPoint (context, second.x, second.y); CGContextDrawPath (context, kCGPathStroke); releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::fillLinearGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& startPoint, const CPoint& endPoint, bool evenOdd, CGraphicsTransform* t) { QuartzGraphicsPath* path = dynamic_cast<QuartzGraphicsPath*> (_path); if (path == 0) return; const QuartzGradient* cgGradient = dynamic_cast<const QuartzGradient*> (&gradient); if (cgGradient == 0) return; CGContextRef cgContext = beginCGContext (true, currentState.drawMode.integralMode ()); if (cgContext) { if (t) { CGContextSaveGState (cgContext); CGAffineTransform transform = QuartzGraphicsPath::createCGAfflineTransform (*t); CGContextConcatCTM (cgContext, transform); CGContextAddPath (cgContext, path->getCGPathRef ()); CGContextRestoreGState (cgContext); } else CGContextAddPath (cgContext, path->getCGPathRef ()); if (evenOdd) CGContextEOClip (cgContext); else CGContextClip (cgContext); CGContextDrawLinearGradient (cgContext, *cgGradient, CGPointMake (startPoint.x, startPoint.y), CGPointMake (endPoint.x, endPoint.y), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); releaseCGContext (cgContext); } }
//----------------------------------------------------------------------------- void CGDrawContext::drawBitmap (CBitmap* bitmap, const CRect& inRect, const CPoint& inOffset, float alpha) { if (bitmap == 0 || alpha == 0.f) return; CGBitmap* cgBitmap = bitmap->getPlatformBitmap () ? dynamic_cast<CGBitmap*> (bitmap->getPlatformBitmap ()) : 0; CGImageRef image = cgBitmap ? cgBitmap->getCGImage () : 0; if (image) { CGContextRef context = beginCGContext (false, true); if (context) { CRect rect (inRect); rect.makeIntegral (); CPoint offset (inOffset); offset.makeIntegral (); CGContextSetAlpha (context, (CGFloat)alpha*currentState.globalAlpha); CGRect dest; dest.origin.x = rect.left - offset.h; dest.origin.y = -(rect.top) - (bitmap->getHeight () - offset.v); dest.size.width = cgBitmap->getSize ().x; dest.size.height = cgBitmap->getSize ().y; CGRect clipRect2; clipRect2.origin.x = rect.left; clipRect2.origin.y = -(rect.top) - rect.height (); clipRect2.size.width = rect.width (); clipRect2.size.height = rect.height (); CGContextClipToRect (context, clipRect2); CGLayerRef layer = cgBitmap->getCGLayer (); if (layer == 0) { BitmapDrawCountMap::iterator it = bitmapDrawCount.find (cgBitmap); if (it == bitmapDrawCount.end ()) { bitmapDrawCount.insert (std::pair<CGBitmap*, int32_t> (cgBitmap, 1)); CGContextDrawImage (context, dest, image); } else { it->second++; layer = cgBitmap->createCGLayer (context); } } if (layer) { CGContextDrawLayerInRect (context, dest, layer); } releaseCGContext (context); } } }
//----------------------------------------------------------------------------- void CGDrawContext::drawGraphicsPath (CGraphicsPath* _path, PathDrawMode mode, CGraphicsTransform* t) { QuartzGraphicsPath* path = dynamic_cast<QuartzGraphicsPath*> (_path); if (path == 0) return; CGContextRef context = beginCGContext (true, getDrawMode ().integralMode ()); if (context) { CGPathDrawingMode cgMode; switch (mode) { case kPathFilledEvenOdd: { cgMode = kCGPathEOFill; break; } case kPathStroked: { cgMode = kCGPathStroke; applyLineStyle (context); break; } default: { cgMode = kCGPathFill; break; } } if (getDrawMode ().integralMode ()) { applyLineWidthCTM (context); path->pixelAlign (this, t); CGContextAddPath (context, path->getCGPathRef ()); } else if (t) { CGContextSaveGState (context); CGAffineTransform transform = QuartzGraphicsPath::createCGAffineTransform (*t); CGContextConcatCTM (context, transform); CGContextAddPath (context, path->getCGPathRef ()); CGContextRestoreGState (context); } else CGContextAddPath (context, path->getCGPathRef ()); CGContextDrawPath (context, cgMode); releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::clearRect (const CRect& rect) { CGContextRef context = beginCGContext (true, currentState.drawMode.integralMode ()); if (context) { CGRect cgRect; if (currentState.drawMode.integralMode ()) cgRect = CGRectMake (round (rect.left), round (rect.top), round (rect.width ()), round (rect.height ())); else cgRect = CGRectMake (rect.left, rect.top, rect.width (), rect.height ()); CGContextClearRect (context, cgRect); releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::clearRect (const CRect& rect) { CGContextRef context = beginCGContext (true, getDrawMode ().integralMode ()); if (context) { CGRect cgRect = CGRectFromCRect (rect); if (getDrawMode ().integralMode ()) { cgRect = pixelAlligned (cgRect); } CGContextClearRect (context, cgRect); releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::drawEllipse (const CRect &rect, const CDrawStyle drawStyle) { CGContextRef context = beginCGContext (true, currentState.drawMode.integralMode ()); if (context) { CGPathDrawingMode m; switch (drawStyle) { case kDrawFilled : m = kCGPathFill; break; case kDrawFilledAndStroked : m = kCGPathFillStroke; break; default : m = kCGPathStroke; break; } applyLineStyle (context); if (rect.width () != rect.height ()) { CGContextSaveGState (context); CGContextBeginPath (context); CGRect cgRect = CGRectMake (rect.left, rect.top, rect.width (), rect.height ()); CGPoint center = CGPointMake (CGRectGetMidX (cgRect), CGRectGetMidY (cgRect)); CGFloat a = CGRectGetWidth (cgRect) / 2.; CGFloat b = CGRectGetHeight (cgRect) / 2.; CGContextTranslateCTM (context, center.x, center.y); CGContextScaleCTM (context, a, b); CGContextMoveToPoint (context, 1, 0); CGContextAddArc (context, 0, 0, 1, radians (0), radians (360), 0); CGContextClosePath (context); CGContextRestoreGState (context); CGContextDrawPath (context, m); } else { CGFloat radius = rect.width () * 0.5; CGContextBeginPath (context); CGContextAddArc (context, rect.left + radius, rect.top + radius, radius, radians (0), radians (360), 0); CGContextClosePath (context); CGContextDrawPath (context, m); } releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::fillLinearGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& startPoint, const CPoint& endPoint, bool evenOdd, CGraphicsTransform* t) { QuartzGraphicsPath* path = dynamic_cast<QuartzGraphicsPath*> (_path); if (path == 0) return; const QuartzGradient* cgGradient = dynamic_cast<const QuartzGradient*> (&gradient); if (cgGradient == 0) return; CGContextRef context = beginCGContext (true, getDrawMode ().integralMode ()); if (context) { CGPoint start = CGPointFromCPoint (startPoint); CGPoint end = CGPointFromCPoint (endPoint); if (getDrawMode ().integralMode ()) { path->pixelAlign (this, t); applyLineWidthCTM (context); CGContextAddPath (context, path->getCGPathRef ()); start = pixelAlligned (start); end = pixelAlligned (end); } else if (t) { CGContextSaveGState (context); CGAffineTransform transform = QuartzGraphicsPath::createCGAffineTransform (*t); CGContextConcatCTM (context, transform); CGContextAddPath (context, path->getCGPathRef ()); CGContextRestoreGState (context); } else CGContextAddPath (context, path->getCGPathRef ()); if (evenOdd) CGContextEOClip (context); else CGContextClip (context); CGContextDrawLinearGradient (context, *cgGradient, start, end, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::fillRadialGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& center, CCoord radius, const CPoint& originOffset, bool evenOdd, CGraphicsTransform* t) { QuartzGraphicsPath* path = dynamic_cast<QuartzGraphicsPath*> (_path); if (path == 0) return; const QuartzGradient* cgGradient = dynamic_cast<const QuartzGradient*> (&gradient); if (cgGradient == 0) return; CGContextRef context = beginCGContext (true, getDrawMode ().integralMode ()); if (context) { if (getDrawMode ().integralMode ()) { path->pixelAlign (this, t); CGContextAddPath (context, path->getCGPathRef ()); } else if (t) { CGContextSaveGState (context); CGAffineTransform transform = QuartzGraphicsPath::createCGAffineTransform (*t); CGContextConcatCTM (context, transform); CGContextAddPath (context, path->getCGPathRef ()); CGContextRestoreGState (context); } else CGContextAddPath (context, path->getCGPathRef ()); if (evenOdd) CGContextEOClip (context); else CGContextClip (context); CPoint startCenter = center + originOffset; CGContextDrawRadialGradient (context, *cgGradient, CGPointFromCPoint (startCenter), 0, CGPointFromCPoint (center), static_cast<CGFloat> (radius), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::fillRectWithBitmap (CBitmap* bitmap, const CRect& srcRect, const CRect& dstRect, float alpha) { if (bitmap == 0 || alpha == 0.f || srcRect.isEmpty () || dstRect.isEmpty ()) return; if (!(srcRect.left == 0 && srcRect.right == 0 && srcRect.right == bitmap->getWidth () && srcRect.bottom == bitmap->getHeight ())) { // CGContextDrawTiledImage does not work with parts of a bitmap CDrawContext::fillRectWithBitmap(bitmap, srcRect, dstRect, alpha); return; } IPlatformBitmap* platformBitmap = bitmap->getBestPlatformBitmapForScaleFactor (scaleFactor); CPoint bitmapSize = platformBitmap->getSize (); if (srcRect.right > bitmapSize.x || srcRect.bottom > bitmapSize.y) return; CGBitmap* cgBitmap = platformBitmap ? dynamic_cast<CGBitmap*> (platformBitmap) : 0; CGImageRef image = cgBitmap ? cgBitmap->getCGImage () : 0; if (image) { CGContextRef context = beginCGContext (false, true); if (context) { // TODO: Check if this works with retina images CGRect clipRect = CGRectFromCRect (dstRect); clipRect.origin.y = -(clipRect.origin.y) - clipRect.size.height; clipRect = pixelAlligned (clipRect); CGContextClipToRect (context, clipRect); CGRect r = {}; r.size.width = CGImageGetWidth (image); r.size.height = CGImageGetHeight (image); CGContextDrawTiledImage (context, r, image); releaseCGContext (context); } } }
//----------------------------------------------------------------------------- void CGDrawContext::drawArc (const CRect &rect, const float _startAngle, const float _endAngle, const CDrawStyle drawStyle) // in degree { CGContextRef context = beginCGContext (true, currentState.drawMode.integralMode ()); if (context) { CGPathDrawingMode m; switch (drawStyle) { case kDrawFilled : m = kCGPathFill; break; case kDrawFilledAndStroked : m = kCGPathFillStroke; break; default : m = kCGPathStroke; break; } applyLineStyle (context); CGContextBeginPath (context); addOvalToPath (context, CPoint (rect.left + rect.width () / 2, rect.top + rect.height () / 2), rect.width () / 2, rect.height () / 2, -_startAngle, -_endAngle); if (drawStyle == kDrawFilled || kDrawFilledAndStroked) CGContextAddLineToPoint (context, rect.left + rect.width () / 2, rect.top + rect.height () / 2); CGContextDrawPath (context, m); releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::drawPolygon (const CPoint* pPoints, int32_t numberOfPoints, const CDrawStyle drawStyle) { CGContextRef context = beginCGContext (true, currentState.drawMode.integralMode ()); if (context) { CGPathDrawingMode m; switch (drawStyle) { case kDrawFilled : m = kCGPathFill; break; case kDrawFilledAndStroked : m = kCGPathFillStroke; break; default : m = kCGPathStroke; break; } applyLineStyle (context); CGContextBeginPath (context); CGContextMoveToPoint (context, pPoints[0].h, pPoints[0].v); for (int32_t i = 1; i < numberOfPoints; i++) CGContextAddLineToPoint (context, pPoints[i].h, pPoints[i].v); CGContextDrawPath (context, m); releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::drawPolygon (const PointList& polygonPointList, const CDrawStyle drawStyle) { if (polygonPointList.size () == 0) return; CGContextRef context = beginCGContext (true, getDrawMode ().integralMode ()); if (context) { CGPathDrawingMode m; switch (drawStyle) { case kDrawFilled : m = kCGPathFill; break; case kDrawFilledAndStroked : m = kCGPathFillStroke; break; default : m = kCGPathStroke; break; } applyLineStyle (context); CGContextBeginPath (context); CGPoint p = CGPointFromCPoint(polygonPointList[0]); if (getDrawMode ().integralMode ()) p = pixelAlligned (p); CGContextMoveToPoint (context, p.x, p.y); for (uint32_t i = 1; i < polygonPointList.size (); i++) { p = CGPointFromCPoint (polygonPointList[i]); if (getDrawMode ().integralMode ()) p = pixelAlligned (p); CGContextAddLineToPoint (context, p.x, p.y); } CGContextDrawPath (context, m); releaseCGContext (context); } }
//----------------------------------------------------------------------------- void CGDrawContext::drawBitmap (CBitmap* bitmap, const CRect& inRect, const CPoint& inOffset, float alpha) { if (bitmap == 0 || alpha == 0.f) return; double transformedScaleFactor = scaleFactor; CGraphicsTransform t = getCurrentTransform (); if (t.m11 == t.m22 && t.m12 == 0 && t.m21 == 0) transformedScaleFactor *= t.m11; IPlatformBitmap* platformBitmap = bitmap->getBestPlatformBitmapForScaleFactor (transformedScaleFactor); CGBitmap* cgBitmap = platformBitmap ? dynamic_cast<CGBitmap*> (platformBitmap) : 0; CGImageRef image = cgBitmap ? cgBitmap->getCGImage () : 0; if (image) { CGContextRef context = beginCGContext (false, true); if (context) { CGLayerRef layer = cgBitmap->getCGLayer (); if (layer == 0) { BitmapDrawCountMap::iterator it = bitmapDrawCount.find (cgBitmap); if (it == bitmapDrawCount.end ()) { bitmapDrawCount.insert (std::pair<CGBitmap*, int32_t> (cgBitmap, 1)); } else { it->second++; layer = cgBitmap->createCGLayer (context); } } drawCGImageRef (context, image, layer, cgBitmap->getScaleFactor (), inRect, inOffset, alpha, bitmap); releaseCGContext (context); } } }