aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--cocoa/PlatCocoa.h1
-rw-r--r--cocoa/PlatCocoa.mm44
-rw-r--r--gtk/PlatGTK.cxx27
-rw-r--r--include/Platform.h74
-rw-r--r--qt/ScintillaEditBase/PlatQt.cpp20
-rw-r--r--qt/ScintillaEditBase/PlatQt.h6
-rw-r--r--win32/PlatWin.cxx58
7 files changed, 226 insertions, 4 deletions
diff --git a/cocoa/PlatCocoa.h b/cocoa/PlatCocoa.h
index 6a9bada96..940de83d5 100644
--- a/cocoa/PlatCocoa.h
+++ b/cocoa/PlatCocoa.h
@@ -94,6 +94,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 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;
void Copy(PRectangle rc, Scintilla::Point from, Surface &surfaceSource) override;
diff --git a/cocoa/PlatCocoa.mm b/cocoa/PlatCocoa.mm
index 0e1e1544c..7d7eafb42 100644
--- a/cocoa/PlatCocoa.mm
+++ b/cocoa/PlatCocoa.mm
@@ -641,6 +641,50 @@ void Scintilla::SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, Colou
}
}
+void Scintilla::SurfaceImpl::GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) {
+ if (!gc) {
+ return;
+ }
+
+ CGPoint ptStart = CGPointMake(rc.left, rc.top);
+ CGPoint ptEnd = CGPointMake(rc.left, rc.bottom);
+ if (options == GradientOptions::leftToRight) {
+ ptEnd = CGPointMake(rc.right, rc.top);
+ }
+
+ std::vector<CGFloat> components;
+ std::vector<CGFloat> locations;
+ for (const ColourStop &stop : stops) {
+ locations.push_back(stop.position);
+ components.push_back(stop.colour.GetRedComponent());
+ components.push_back(stop.colour.GetGreenComponent());
+ components.push_back(stop.colour.GetBlueComponent());
+ components.push_back(stop.colour.GetAlphaComponent());
+ }
+
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ if (!colorSpace) {
+ return;
+ }
+
+ CGGradientRef gradiantRef = CGGradientCreateWithColorComponents(colorSpace,
+ components.data(),
+ locations.data(),
+ locations.size());
+ if (gradiantRef) {
+ CGContextSaveGState(gc);
+ CGRect rect = PRectangleToCGRect(rc);
+ CGContextClipToRect(gc, rect);
+ CGContextBeginPath(gc);
+ CGContextAddRect(gc, rect);
+ CGContextClosePath(gc);
+ CGContextDrawLinearGradient(gc, gradiantRef, ptStart, ptEnd, 0);
+ CGGradientRelease(gradiantRef);
+ CGContextRestoreGState(gc);
+ }
+ CGColorSpaceRelease(colorSpace);
+}
+
static void ProviderReleaseData(void *, const void *data, size_t) {
const unsigned char *pixels = static_cast<const unsigned char *>(data);
delete []pixels;
diff --git a/gtk/PlatGTK.cxx b/gtk/PlatGTK.cxx
index 42db59903..0f5ea58d9 100644
--- a/gtk/PlatGTK.cxx
+++ b/gtk/PlatGTK.cxx
@@ -161,6 +161,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 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;
void Copy(PRectangle rc, Point from, Surface &surfaceSource) override;
@@ -545,6 +546,32 @@ void SurfaceImpl::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fi
}
}
+void SurfaceImpl::GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) {
+ if (context) {
+ cairo_pattern_t *pattern;
+ switch (options) {
+ case GradientOptions::leftToRight:
+ pattern = cairo_pattern_create_linear(rc.left, rc.top, rc.right, rc.top);
+ break;
+ case GradientOptions::topToBottom:
+ default:
+ pattern = cairo_pattern_create_linear(rc.left, rc.top, rc.left, rc.bottom);
+ break;
+ }
+ for (const ColourStop &stop : stops) {
+ cairo_pattern_add_color_stop_rgba(pattern, stop.position,
+ stop.colour.GetRedComponent(),
+ stop.colour.GetGreenComponent(),
+ stop.colour.GetBlueComponent(),
+ stop.colour.GetAlphaComponent());
+ }
+ cairo_rectangle(context, rc.left, rc.top, rc.Width(), rc.Height());
+ cairo_set_source(context, pattern);
+ cairo_fill(context);
+ cairo_pattern_destroy(pattern);
+ }
+}
+
void SurfaceImpl::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) {
PLATFORM_ASSERT(context);
if (rc.Width() > width)
diff --git a/include/Platform.h b/include/Platform.h
index 0b730944f..e83b8e5e5 100644
--- a/include/Platform.h
+++ b/include/Platform.h
@@ -164,12 +164,13 @@ public:
};
/**
- * Holds a desired RGB colour.
+ * Holds an RGB colour with 8 bits for each component.
*/
+constexpr const float componentMaximum = 255.0f;
class ColourDesired {
int co;
public:
- ColourDesired(int co_=0) noexcept : co(co_) {
+ explicit ColourDesired(int co_=0) noexcept : co(co_) {
}
ColourDesired(unsigned int red, unsigned int green, unsigned int blue) noexcept :
@@ -184,17 +185,80 @@ public:
return co;
}
+ // Red, green and blue values as bytes 0..255
unsigned char GetRed() const noexcept {
return co & 0xff;
}
-
unsigned char GetGreen() const noexcept {
return (co >> 8) & 0xff;
}
-
unsigned char GetBlue() const noexcept {
return (co >> 16) & 0xff;
}
+
+ // Red, green and blue values as float 0..1.0
+ float GetRedComponent() const noexcept {
+ return GetRed() / componentMaximum;
+ }
+ float GetGreenComponent() const noexcept {
+ return GetGreen() / componentMaximum;
+ }
+ float GetBlueComponent() const noexcept {
+ return GetBlue() / componentMaximum;
+ }
+};
+
+/**
+* Holds an RGBA colour.
+*/
+class ColourAlpha : public ColourDesired {
+public:
+ explicit ColourAlpha(int co_ = 0) noexcept : ColourDesired(co_) {
+ }
+
+ ColourAlpha(unsigned int red, unsigned int green, unsigned int blue) noexcept :
+ ColourDesired(red | (green << 8) | (blue << 16)) {
+ }
+
+ ColourAlpha(unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha) noexcept :
+ ColourDesired(red | (green << 8) | (blue << 16) | (alpha << 24)) {
+ }
+
+ ColourAlpha(ColourDesired cd, unsigned int alpha) noexcept :
+ ColourDesired(cd.AsInteger() | (alpha << 24)) {
+ }
+
+ ColourDesired GetColour() const noexcept {
+ return ColourDesired(AsInteger() & 0xffffff);
+ }
+
+ unsigned char GetAlpha() const noexcept {
+ return (AsInteger() >> 24) & 0xff;
+ }
+
+ float GetAlphaComponent() const noexcept {
+ return GetAlpha() / componentMaximum;
+ }
+
+ ColourAlpha MixedWith(ColourAlpha other) const noexcept {
+ const unsigned int red = (GetRed() + other.GetRed()) / 2;
+ const unsigned int green = (GetGreen() + other.GetGreen()) / 2;
+ const unsigned int blue = (GetBlue() + other.GetBlue()) / 2;
+ const unsigned int alpha = (GetAlpha() + other.GetAlpha()) / 2;
+ return ColourAlpha(red, green, blue, alpha);
+ }
+};
+
+/**
+* Holds an element of a gradient with an RGBA colour and a relative position.
+*/
+class ColourStop {
+public:
+ float position;
+ ColourAlpha colour;
+ ColourStop(float position_, ColourAlpha colour_) noexcept :
+ position(position_), colour(colour_) {
+ }
};
/**
@@ -284,6 +348,8 @@ 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;
+ 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;
virtual void Ellipse(PRectangle rc, ColourDesired fore, ColourDesired back)=0;
virtual void Copy(PRectangle rc, Point from, Surface &surfaceSource)=0;
diff --git a/qt/ScintillaEditBase/PlatQt.cpp b/qt/ScintillaEditBase/PlatQt.cpp
index 0a4609acc..44082c77a 100644
--- a/qt/ScintillaEditBase/PlatQt.cpp
+++ b/qt/ScintillaEditBase/PlatQt.cpp
@@ -353,6 +353,26 @@ void SurfaceImpl::AlphaRectangle(PRectangle rc,
GetPainter()->drawRoundedRect(rect, radius, radius);
}
+void SurfaceImpl::GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) {
+ QRectF rect = QRectFFromPRect(rc);
+ QLinearGradient linearGradient;
+ switch (options) {
+ case GradientOptions::leftToRight:
+ linearGradient = QLinearGradient(rc.left, rc.top, rc.right, rc.top);
+ break;
+ case GradientOptions::topToBottom:
+ default:
+ linearGradient = QLinearGradient(rc.left, rc.top, rc.left, rc.bottom);
+ break;
+ }
+ linearGradient.setSpread(QGradient::RepeatSpread);
+ for (const ColourStop &stop : stops) {
+ linearGradient.setColorAt(stop.position, QColorFromColourAlpha(stop.colour));
+ }
+ QBrush brush = QBrush(linearGradient);
+ GetPainter()->fillRect(rect, brush);
+}
+
static std::vector<unsigned char> ImageByteSwapped(int width, int height, const unsigned char *pixelsImage)
{
// Input is RGBA, but Format_ARGB32 is BGRA, so swap the red bytes and blue bytes
diff --git a/qt/ScintillaEditBase/PlatQt.h b/qt/ScintillaEditBase/PlatQt.h
index 0cd62cb8b..6baa12877 100644
--- a/qt/ScintillaEditBase/PlatQt.h
+++ b/qt/ScintillaEditBase/PlatQt.h
@@ -31,6 +31,11 @@ inline QColor QColorFromCA(ColourDesired ca)
return QColor(c & 0xff, (c >> 8) & 0xff, (c >> 16) & 0xff);
}
+inline QColor QColorFromColourAlpha(ColourAlpha ca)
+{
+ return QColor(ca.GetRed(), ca.GetGreen(), ca.GetBlue(), ca.GetAlpha());
+}
+
inline QRect QRectFromPRect(PRectangle pr)
{
return QRect(pr.left, pr.top, pr.Width(), pr.Height());
@@ -91,6 +96,7 @@ public:
ColourDesired back) override;
void AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill,
int alphaFill, ColourDesired outline, int alphaOutline, int flags) 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,
diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx
index 83bf54178..81e5b827b 100644
--- a/win32/PlatWin.cxx
+++ b/win32/PlatWin.cxx
@@ -561,6 +561,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 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;
void Copy(PRectangle rc, Point from, Surface &surfaceSource) override;
@@ -853,6 +854,13 @@ void SurfaceGDI::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fil
}
}
+void SurfaceGDI::GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions) {
+ // Would be better to average start and end.
+ const ColourAlpha colourAverage = stops[0].colour.MixedWith(stops[1].colour);
+ AlphaRectangle(rc, 0, colourAverage.GetColour(), colourAverage.GetAlpha(),
+ colourAverage.GetColour(), colourAverage.GetAlpha(), 0);
+}
+
void SurfaceGDI::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) {
if (rc.Width() > 0) {
HDC hMemDC = ::CreateCompatibleDC(hdc);
@@ -1123,6 +1131,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 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;
void Copy(PRectangle rc, Point from, Surface &surfaceSource) override;
@@ -1462,6 +1471,55 @@ void SurfaceD2D::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fil
}
}
+namespace {
+
+D2D_COLOR_F ColorFromColourAlpha(ColourAlpha colour) noexcept {
+ D2D_COLOR_F col;
+ col.r = colour.GetRedComponent();
+ col.g = colour.GetGreenComponent();
+ col.b = colour.GetBlueComponent();
+ col.a = colour.GetAlphaComponent();
+ return col;
+}
+
+}
+
+void SurfaceD2D::GradientRectangle(PRectangle rc, const std::vector<ColourStop> &stops, GradientOptions options) {
+ if (pRenderTarget) {
+ D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES lgbp;
+ lgbp.startPoint = D2D1::Point2F(rc.left, rc.top);
+ switch (options) {
+ case GradientOptions::leftToRight:
+ lgbp.endPoint = D2D1::Point2F(rc.right, rc.top);
+ break;
+ case GradientOptions::topToBottom:
+ default:
+ lgbp.endPoint = D2D1::Point2F(rc.left, rc.bottom);
+ break;
+ }
+
+ std::vector<D2D1_GRADIENT_STOP> gradientStops;
+ for (const ColourStop &stop : stops) {
+ gradientStops.push_back({ stop.position, ColorFromColourAlpha(stop.colour) });
+ }
+ ID2D1GradientStopCollection *pGradientStops = nullptr;
+ HRESULT hr = pRenderTarget->CreateGradientStopCollection(
+ gradientStops.data(), static_cast<UINT32>(gradientStops.size()), &pGradientStops);
+ if (FAILED(hr)) {
+ return;
+ }
+ ID2D1LinearGradientBrush *pBrushLinear = nullptr;
+ hr = pRenderTarget->CreateLinearGradientBrush(
+ lgbp, pGradientStops, &pBrushLinear);
+ if (SUCCEEDED(hr)) {
+ const D2D1_RECT_F rectangle = D2D1::RectF(round(rc.left), rc.top, round(rc.right), rc.bottom);
+ pRenderTarget->FillRectangle(&rectangle, pBrushLinear);
+ pBrushLinear->Release();
+ }
+ pGradientStops->Release();
+ }
+}
+
void SurfaceD2D::DrawRGBAImage(PRectangle rc, int width, int height, const unsigned char *pixelsImage) {
if (pRenderTarget) {
if (rc.Width() > width)