aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--cocoa/PlatCocoa.h2
-rw-r--r--cocoa/PlatCocoa.mm60
-rwxr-xr-xgtk/PlatGTK.cxx26
-rw-r--r--qt/ScintillaEditBase/PlatQt.cpp32
-rw-r--r--qt/ScintillaEditBase/PlatQt.h1
-rw-r--r--src/Platform.h1
-rw-r--r--win32/PlatWin.cxx87
7 files changed, 209 insertions, 0 deletions
diff --git a/cocoa/PlatCocoa.h b/cocoa/PlatCocoa.h
index 98a9b11ed..f50c0e7f7 100644
--- a/cocoa/PlatCocoa.h
+++ b/cocoa/PlatCocoa.h
@@ -62,6 +62,7 @@ private:
void FillColour(const ColourDesired &back);
void FillColour(ColourAlpha fill);
+ void PenColourAlpha(ColourAlpha fore);
// 24-bit RGB+A bitmap data constants
static const int BITS_PER_COMPONENT = 8;
@@ -101,6 +102,7 @@ public:
void RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) override;
void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill,
ColourDesired outline, int alphaOutline, int flags) override;
+ void AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) override;
void GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) override;
void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) override;
void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) override;
diff --git a/cocoa/PlatCocoa.mm b/cocoa/PlatCocoa.mm
index a4f01c5c6..714e4f484 100644
--- a/cocoa/PlatCocoa.mm
+++ b/cocoa/PlatCocoa.mm
@@ -502,6 +502,17 @@ void SurfaceImpl::FillColour(const ColourDesired &back) {
//--------------------------------------------------------------------------------------------------
+void SurfaceImpl::PenColourAlpha(ColourAlpha fore) {
+ // Set the Stroke color to match
+ CGContextSetRGBStrokeColor(gc,
+ fore.GetRedComponent(),
+ fore.GetGreenComponent(),
+ fore.GetBlueComponent(),
+ fore.GetAlphaComponent());
+}
+
+//--------------------------------------------------------------------------------------------------
+
CGImageRef SurfaceImpl::CreateImage() {
// For now, assume that CreateImage can only be called on PixMap surfaces.
if (!bitmapData)
@@ -895,6 +906,55 @@ void Scintilla::SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, Colou
}
}
+void Scintilla::SurfaceImpl::AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) {
+ if (gc) {
+ const XYPOSITION halfStroke = fillStroke.stroke.width / 2.0f;
+ // Set the Fill color to match
+ FillColour(fillStroke.fill.colour);
+ PenColourAlpha(fillStroke.stroke.colour);
+ PRectangle rcFill = rc;
+ if (cornerSize == 0) {
+ // A simple rectangle, no rounded corners
+ if (fillStroke.fill.colour == fillStroke.stroke.colour) {
+ // Optimization for simple case
+ CGRect rect = PRectangleToCGRect(rcFill);
+ CGContextFillRect(gc, rect);
+ } else {
+ rcFill.left += fillStroke.stroke.width;
+ rcFill.top += fillStroke.stroke.width;
+ rcFill.right -= fillStroke.stroke.width;
+ rcFill.bottom -= fillStroke.stroke.width;
+ CGRect rect = PRectangleToCGRect(rcFill);
+ CGContextFillRect(gc, rect);
+ CGContextAddRect(gc, CGRectMake(rc.left + halfStroke, rc.top + halfStroke,
+ rc.Width() - fillStroke.stroke.width, rc.Height() - fillStroke.stroke.width));
+ CGContextStrokeRectWithWidth(gc,
+ CGRectMake(rc.left + halfStroke, rc.top + halfStroke,
+ rc.Width() - fillStroke.stroke.width, rc.Height() - fillStroke.stroke.width),
+ fillStroke.stroke.width);
+ }
+ } else {
+ // Approximate rounded corners with 45 degree chamfers.
+ // Drawing real circular arcs often leaves some over- or under-drawn pixels.
+ if (fillStroke.fill.colour == fillStroke.stroke.colour) {
+ // Specializing this case avoids a few stray light/dark pixels in corners.
+ rcFill.left -= halfStroke;
+ rcFill.top -= halfStroke;
+ rcFill.right += halfStroke;
+ rcFill.bottom += halfStroke;
+ DrawChamferedRectangle(gc, rcFill, cornerSize, kCGPathFill);
+ } else {
+ rcFill.left += halfStroke;
+ rcFill.top += halfStroke;
+ rcFill.right -= halfStroke;
+ rcFill.bottom -= halfStroke;
+ DrawChamferedRectangle(gc, rcFill, cornerSize-fillStroke.stroke.width, kCGPathFill);
+ DrawChamferedRectangle(gc, rc, cornerSize, kCGPathStroke);
+ }
+ }
+ }
+}
+
void Scintilla::SurfaceImpl::GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) {
if (!gc) {
return;
diff --git a/gtk/PlatGTK.cxx b/gtk/PlatGTK.cxx
index 3debf8fc8..b1079a31a 100755
--- a/gtk/PlatGTK.cxx
+++ b/gtk/PlatGTK.cxx
@@ -169,6 +169,7 @@ public:
void RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) override;
void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill,
ColourDesired outline, int alphaOutline, int flags) override;
+ void AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) override;
void GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) override;
void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) override;
void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) override;
@@ -592,6 +593,31 @@ void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fi
}
}
+void SurfaceImpl::AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) {
+ if (context && rc.Width() > 0) {
+ const float halfStroke = fillStroke.stroke.width / 2.0f;
+ const float doubleStroke = fillStroke.stroke.width * 2.0f;
+ PenColourAlpha(fillStroke.fill.colour);
+ if (cornerSize > 0)
+ PathRoundRectangle(context, rc.left + fillStroke.stroke.width, rc.top + fillStroke.stroke.width,
+ rc.Width() - doubleStroke, rc.Height() - doubleStroke, cornerSize);
+ else
+ cairo_rectangle(context, rc.left + fillStroke.stroke.width, rc.top + fillStroke.stroke.width,
+ rc.Width() - doubleStroke, rc.Height() - doubleStroke);
+ cairo_fill(context);
+
+ PenColourAlpha(fillStroke.stroke.colour);
+ if (cornerSize > 0)
+ PathRoundRectangle(context, rc.left + halfStroke, rc.top + halfStroke,
+ rc.Width() - fillStroke.stroke.width, rc.Height() - fillStroke.stroke.width, cornerSize);
+ else
+ cairo_rectangle(context, rc.left + halfStroke, rc.top + halfStroke,
+ rc.Width() - fillStroke.stroke.width, rc.Height() - fillStroke.stroke.width);
+ cairo_set_line_width(context, fillStroke.stroke.width);
+ cairo_stroke(context);
+ }
+}
+
void SurfaceImpl::GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) {
if (context) {
cairo_pattern_t *pattern;
diff --git a/qt/ScintillaEditBase/PlatQt.cpp b/qt/ScintillaEditBase/PlatQt.cpp
index 37fc409f7..a8553e658 100644
--- a/qt/ScintillaEditBase/PlatQt.cpp
+++ b/qt/ScintillaEditBase/PlatQt.cpp
@@ -390,6 +390,38 @@ void SurfaceImpl::AlphaRectangle(PRectangle rc,
}
}
+void SurfaceImpl::AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke)
+{
+ QColor qFill = QColorFromColourAlpha(fillStroke.fill.colour);
+ QBrush brushFill(qFill);
+ GetPainter()->setBrush(brushFill);
+ if (fillStroke.fill.colour == fillStroke.stroke.colour) {
+ painter->setPen(Qt::NoPen);
+ QRectF rect = QRectFFromPRect(rc);
+ if (cornerSize > 0.0f) {
+ // A radius of 1 shows no curve so add 1
+ qreal radius = cornerSize+1;
+ GetPainter()->drawRoundedRect(rect, radius, radius);
+ } else {
+ GetPainter()->fillRect(rect, brushFill);
+ }
+ } else {
+ QColor qOutline = QColorFromColourAlpha(fillStroke.stroke.colour);
+ QPen penOutline(qOutline);
+ penOutline.setWidthF(fillStroke.stroke.width);
+ GetPainter()->setPen(penOutline);
+
+ QRectF rect = QRectFFromPRect(rc.Inset(fillStroke.stroke.width / 2));
+ if (cornerSize > 0.0f) {
+ // A radius of 1 shows no curve so add 1
+ qreal radius = cornerSize+1;
+ GetPainter()->drawRoundedRect(rect, radius, radius);
+ } else {
+ GetPainter()->drawRect(rect);
+ }
+ }
+}
+
void SurfaceImpl::GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) {
QRectF rect = QRectFFromPRect(rc);
QLinearGradient linearGradient;
diff --git a/qt/ScintillaEditBase/PlatQt.h b/qt/ScintillaEditBase/PlatQt.h
index 173bd53d5..257dbda56 100644
--- a/qt/ScintillaEditBase/PlatQt.h
+++ b/qt/ScintillaEditBase/PlatQt.h
@@ -109,6 +109,7 @@ public:
ColourDesired back) override;
void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill,
int alphaFill, ColourDesired outline, int alphaOutline, int flags) override;
+ void AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) override;
void GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) override;
void DrawRGBAImage(PRectangle rc, int width, int height,
const unsigned char *pixelsImage) override;
diff --git a/src/Platform.h b/src/Platform.h
index abad8abfa..1b9f2a6d1 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -196,6 +196,7 @@ public:
virtual void RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back)=0;
virtual void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill,
ColourDesired outline, int alphaOutline, int flags)=0;
+ virtual void AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke)=0;
enum class GradientOptions { leftToRight, topToBottom };
virtual void GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options)=0;
virtual void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) = 0;
diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx
index 3fae8e90f..ae819bb69 100644
--- a/win32/PlatWin.cxx
+++ b/win32/PlatWin.cxx
@@ -494,6 +494,7 @@ public:
void RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) override;
void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill,
ColourDesired outline, int alphaOutline, int flags) override;
+ void AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) override;
void GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) override;
void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) override;
void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) override;
@@ -908,6 +909,55 @@ void SurfaceGDI::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fil
}
}
+void SurfaceGDI::AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) {
+ // TODO: Implement strokeWidth
+ const RECT rcw = RectFromPRectangle(rc);
+ const SIZE size = SizeOfRect(rcw);
+
+ if (size.cx > 0) {
+
+ DIBSection section(hdc, size);
+
+ if (section) {
+
+ // Ensure not distorted too much by corners when small
+ const LONG corner = std::min(static_cast<LONG>(cornerSize), (std::min(size.cx, size.cy) / 2) - 2);
+
+ constexpr DWORD valEmpty = dwordFromBGRA(0,0,0,0);
+ const DWORD valFill = dwordMultiplied(fillStroke.fill.colour, fillStroke.fill.colour.GetAlpha());
+ const DWORD valOutline = dwordMultiplied(fillStroke.stroke.colour, fillStroke.stroke.colour.GetAlpha());
+
+ // Draw a framed rectangle
+ for (int y=0; y<size.cy; y++) {
+ for (int x=0; x<size.cx; x++) {
+ if ((x==0) || (x==size.cx-1) || (y == 0) || (y == size.cy -1)) {
+ section.SetPixel(x, y, valOutline);
+ } else {
+ section.SetPixel(x, y, valFill);
+ }
+ }
+ }
+
+ // Make the corners transparent
+ for (LONG c=0; c<corner; c++) {
+ for (LONG x=0; x<c+1; x++) {
+ section.SetSymmetric(x, c - x, valEmpty);
+ }
+ }
+
+ // Draw the corner frame pieces
+ for (LONG x=1; x<corner; x++) {
+ section.SetSymmetric(x, corner - x, valOutline);
+ }
+
+ AlphaBlend(hdc, rcw.left, rcw.top, size.cx, size.cy, section.DC(), 0, 0, size.cx, size.cy, mergeAlpha);
+ }
+ } else {
+ BrushColour(fillStroke.stroke.colour);
+ FrameRect(hdc, &rcw, brush);
+ }
+}
+
void SurfaceGDI::GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) {
const RECT rcw = RectFromPRectangle(rc);
@@ -1242,6 +1292,14 @@ constexpr D2D_COLOR_F ColorFromColourAlpha(ColourAlpha colour) noexcept {
};
}
+constexpr D2D1_RECT_F RectangleInset(D2D1_RECT_F rect, FLOAT inset) noexcept {
+ return D2D1_RECT_F{
+ rect.left + inset,
+ rect.top + inset,
+ rect.right - inset,
+ rect.bottom - inset };
+}
+
}
class BlobInline;
@@ -1305,6 +1363,7 @@ public:
void RoundedRectangle(PRectangle rc, ColourDesired fore, ColourDesired back) override;
void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill,
ColourDesired outline, int alphaOutline, int flags) override;
+ void AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) override;
void GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) override;
void DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) override;
void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back) override;
@@ -1673,6 +1732,34 @@ void SurfaceD2D::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fil
}
}
+void SurfaceD2D::AlphaRectangle(PRectangle rc, XYPOSITION cornerSize, FillStroke fillStroke) {
+ const D2D1_RECT_F rect = RectangleFromPRectangle(rc);
+ const D2D1_RECT_F rectFill = RectangleInset(rect, fillStroke.stroke.width);
+ const float halfStroke = fillStroke.stroke.width / 2.0f;
+ const D2D1_RECT_F rectOutline = RectangleInset(rect, halfStroke);
+ if (pRenderTarget) {
+ if (cornerSize == 0) {
+ // When corner size is zero, draw square rectangle to prevent blurry pixels at corners
+ D2DPenColourAlpha(fillStroke.fill.colour);
+ pRenderTarget->FillRectangle(rectFill, pBrush);
+
+ D2DPenColourAlpha(fillStroke.stroke.colour);
+ pRenderTarget->DrawRectangle(rectOutline, pBrush, fillStroke.stroke.width);
+ } else {
+ const float cornerSizeF = static_cast<float>(cornerSize);
+ D2D1_ROUNDED_RECT roundedRectFill = {
+ rectFill, cornerSizeF - 1.0f, cornerSizeF - 1.0f };
+ D2DPenColourAlpha(fillStroke.fill.colour);
+ pRenderTarget->FillRoundedRectangle(roundedRectFill, pBrush);
+
+ D2D1_ROUNDED_RECT roundedRect = {
+ rectOutline, cornerSizeF, cornerSizeF};
+ D2DPenColourAlpha(fillStroke.stroke.colour);
+ pRenderTarget->DrawRoundedRectangle(roundedRect, pBrush, fillStroke.stroke.width);
+ }
+ }
+}
+
void SurfaceD2D::GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) {
if (pRenderTarget) {
D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES lgbp {