aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--cocoa/PlatCocoa.mm98
1 files changed, 84 insertions, 14 deletions
diff --git a/cocoa/PlatCocoa.mm b/cocoa/PlatCocoa.mm
index a58b2c9c0..1a4e591bf 100644
--- a/cocoa/PlatCocoa.mm
+++ b/cocoa/PlatCocoa.mm
@@ -593,7 +593,56 @@ void SurfaceImpl::RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesi
CGContextDrawPath( gc, kCGPathFillStroke );
}
-void Scintilla::SurfaceImpl::AlphaRectangle(PRectangle rc, int /*cornerSize*/, ColourDesired fill, int alphaFill,
+// DrawChamferedRectangle is a helper function for AlphaRectangle that either fills or strokes a
+// rectangle with its corners chamfered at 45 degrees.
+static void DrawChamferedRectangle(CGContextRef gc, PRectangle rc, int cornerSize, CGPathDrawingMode mode) {
+ // Points go clockwise, starting from just below the top left
+ CGPoint corners[4][2] =
+ {
+ {
+ { rc.left, rc.top + cornerSize },
+ { rc.left + cornerSize, rc.top },
+ },
+ {
+ { rc.right - cornerSize - 1, rc.top },
+ { rc.right - 1, rc.top + cornerSize },
+ },
+ {
+ { rc.right - 1, rc.bottom - cornerSize - 1 },
+ { rc.right - cornerSize - 1, rc.bottom - 1 },
+ },
+ {
+ { rc.left + cornerSize, rc.bottom - 1 },
+ { rc.left, rc.bottom - cornerSize - 1 },
+ },
+ };
+
+ // Align the points in the middle of the pixels
+ for( int i = 0; i < 4; ++ i )
+ {
+ for( int j = 0; j < 2; ++ j )
+ {
+ corners[i][j].x += 0.5;
+ corners[i][j].y += 0.5;
+ }
+ }
+
+ // Move to the last point to begin the path
+ CGContextBeginPath( gc );
+ CGContextMoveToPoint( gc, corners[3][1].x, corners[3][1].y );
+
+ for ( int i = 0; i < 4; ++ i )
+ {
+ CGContextAddLineToPoint( gc, corners[i][0].x, corners[i][0].y );
+ CGContextAddLineToPoint( gc, corners[i][1].x, corners[i][1].y );
+ }
+
+ // Close the path to enclose it for stroking and for filling, then draw it
+ CGContextClosePath( gc );
+ CGContextDrawPath( gc, mode );
+}
+
+void Scintilla::SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill,
ColourDesired outline, int alphaOutline, int /*flags*/)
{
if ( gc ) {
@@ -602,21 +651,42 @@ void Scintilla::SurfaceImpl::AlphaRectangle(PRectangle rc, int /*cornerSize*/, C
rc.right = lround(rc.right);
// Set the Fill color to match
CGContextSetRGBFillColor( gc, fill.GetRed() / 255.0, fill.GetGreen() / 255.0, fill.GetBlue() / 255.0, alphaFill / 255.0 );
+ CGContextSetRGBStrokeColor( gc, outline.GetRed() / 255.0, outline.GetGreen() / 255.0, outline.GetBlue() / 255.0, alphaOutline / 255.0 );
PRectangle rcFill = rc;
- if ((fill == outline) && (alphaFill == alphaOutline)) {
- // Optimization for simple case
- CGRect rect = PRectangleToCGRect( rcFill );
- CGContextFillRect( gc, rect );
+ if (cornerSize == 0) {
+ // A simple rectangle, no rounded corners
+ if ((fill == outline) && (alphaFill == alphaOutline)) {
+ // Optimization for simple case
+ CGRect rect = PRectangleToCGRect( rcFill );
+ CGContextFillRect( gc, rect );
+ } else {
+ rcFill.left += 1.0;
+ rcFill.top += 1.0;
+ rcFill.right -= 1.0;
+ rcFill.bottom -= 1.0;
+ CGRect rect = PRectangleToCGRect( rcFill );
+ CGContextFillRect( gc, rect );
+ CGContextAddRect( gc, CGRectMake( rc.left + 0.5, rc.top + 0.5, rc.Width() - 1, rc.Height() - 1 ) );
+ CGContextStrokePath( gc );
+ }
} else {
- rcFill.left += 1.0;
- rcFill.top += 1.0;
- rcFill.right -= 1.0;
- rcFill.bottom -= 1.0;
- CGRect rect = PRectangleToCGRect( rcFill );
- CGContextFillRect( gc, rect );
- CGContextSetRGBStrokeColor( gc, outline.GetRed() / 255.0, outline.GetGreen() / 255.0, outline.GetBlue() / 255.0, alphaOutline / 255.0 );
- CGContextAddRect( gc, CGRectMake( rc.left + 0.5, rc.top + 0.5, rc.Width() - 1, rc.Height() - 1 ) );
- CGContextStrokePath( gc );
+ // Approximate rounded corners with 45 degree chamfers.
+ // Drawing real circular arcs often leaves some over- or under-drawn pixels.
+ if ((fill == outline) && (alphaFill == alphaOutline)) {
+ // Specializing this case avoids a few stray light/dark pixels in corners.
+ rcFill.left -= 0.5;
+ rcFill.top -= 0.5;
+ rcFill.right += 0.5;
+ rcFill.bottom += 0.5;
+ DrawChamferedRectangle( gc, rcFill, cornerSize, kCGPathFill );
+ } else {
+ rcFill.left += 0.5;
+ rcFill.top += 0.5;
+ rcFill.right -= 0.5;
+ rcFill.bottom -= 0.5;
+ DrawChamferedRectangle( gc, rcFill, cornerSize-1, kCGPathFill );
+ DrawChamferedRectangle( gc, rc, cornerSize, kCGPathStroke );
+ }
}
}
}