aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNeil <nyamatongwe@gmail.com>2021-09-15 09:36:45 +1000
committerNeil <nyamatongwe@gmail.com>2021-09-15 09:36:45 +1000
commitd4a5d7d6955982496ba523a439fc98276a28e2d8 (patch)
treef9cd5e2a57e247dc59f47404cfea8469cc74b35c
parentda71ace9e135d3494fafa7d67483ff1c217faa04 (diff)
downloadscintilla-mirror-d4a5d7d6955982496ba523a439fc98276a28e2d8.tar.gz
Move colour mixing implementations into implementation file.
Avoids some warnings but drops constexpr. Use MixedWith in PlatWin for GDI instead of local implementation. Add unit tests for Geometry.
-rw-r--r--src/Geometry.cxx24
-rw-r--r--src/Geometry.h20
-rw-r--r--test/unit/UnitTester.vcxproj1
-rw-r--r--test/unit/makefile1
-rw-r--r--test/unit/test.mak1
-rw-r--r--test/unit/testGeometry.cxx233
-rw-r--r--win32/PlatWin.cxx14
7 files changed, 263 insertions, 31 deletions
diff --git a/src/Geometry.cxx b/src/Geometry.cxx
index afdc5d161..97e99d431 100644
--- a/src/Geometry.cxx
+++ b/src/Geometry.cxx
@@ -12,6 +12,14 @@
#include "Geometry.h"
+namespace {
+
+constexpr unsigned int Mixed(unsigned char a, unsigned char b, double proportion) noexcept {
+ return static_cast<unsigned int>(a + proportion * (b - a));
+}
+
+}
+
namespace Scintilla::Internal {
PRectangle Clamp(PRectangle rc, Edge edge, XYPOSITION position) noexcept {
@@ -95,4 +103,20 @@ PRectangle PixelAlignOutside(const PRectangle &rc, int pixelDivisions) noexcept
std::floor(rc.bottom * pixelDivisions) / pixelDivisions);
}
+ColourRGBA ColourRGBA::MixedWith(ColourRGBA 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 ColourRGBA(red, green, blue, alpha);
+}
+
+ColourRGBA ColourRGBA::MixedWith(ColourRGBA other, double proportion) const noexcept {
+ return ColourRGBA(
+ Mixed(GetRed(), other.GetRed(), proportion),
+ Mixed(GetGreen(), other.GetGreen(), proportion),
+ Mixed(GetBlue(), other.GetBlue(), proportion),
+ Mixed(GetAlpha(), other.GetAlpha(), proportion));
+}
+
}
diff --git a/src/Geometry.h b/src/Geometry.h
index 28241c5a9..5a9b3e291 100644
--- a/src/Geometry.h
+++ b/src/Geometry.h
@@ -161,9 +161,6 @@ PRectangle PixelAlignOutside(const PRectangle &rc, int pixelDivisions) noexcept;
constexpr const float componentMaximum = 255.0f;
class ColourRGBA {
int co;
- constexpr static unsigned int Mixed(unsigned char a, unsigned char b, double proportion) noexcept {
- return static_cast<unsigned int>(a + proportion * (b - a));
- }
public:
constexpr explicit ColourRGBA(int co_ = 0) noexcept : co(co_) {
}
@@ -236,21 +233,8 @@ public:
return GetAlpha() == 0xff;
}
- constexpr ColourRGBA MixedWith(ColourRGBA 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 ColourRGBA(red, green, blue, alpha);
- }
-
- constexpr ColourRGBA MixedWith(ColourRGBA other, double proportion) const noexcept {
- return ColourRGBA(
- Mixed(GetRed(), other.GetRed(), proportion),
- Mixed(GetGreen(), other.GetGreen(), proportion),
- Mixed(GetBlue(), other.GetBlue(), proportion),
- Mixed(GetAlpha(), other.GetAlpha(), proportion));
- }
+ ColourRGBA MixedWith(ColourRGBA other) const noexcept;
+ ColourRGBA MixedWith(ColourRGBA other, double proportion) const noexcept;
};
/**
diff --git a/test/unit/UnitTester.vcxproj b/test/unit/UnitTester.vcxproj
index 2e130ec3d..8d41cf383 100644
--- a/test/unit/UnitTester.vcxproj
+++ b/test/unit/UnitTester.vcxproj
@@ -158,6 +158,7 @@
<ClCompile Include="..\..\src\ContractionState.cxx" />
<ClCompile Include="..\..\src\Decoration.cxx" />
<ClCompile Include="..\..\src\Document.cxx" />
+ <ClCompile Include="..\..\src\Geometry.cxx" />
<ClCompile Include="..\..\src\PerLine.cxx" />
<ClCompile Include="..\..\src\RESearch.cxx" />
<ClCompile Include="..\..\src\RunStyles.cxx" />
diff --git a/test/unit/makefile b/test/unit/makefile
index fad312708..572ea1443 100644
--- a/test/unit/makefile
+++ b/test/unit/makefile
@@ -61,6 +61,7 @@ TESTEDSRC=\
../../src/ContractionState.cxx \
../../src/Decoration.cxx \
../../src/Document.cxx \
+ ../../src/Geometry.cxx \
../../src/PerLine.cxx \
../../src/RESearch.cxx \
../../src/RunStyles.cxx \
diff --git a/test/unit/test.mak b/test/unit/test.mak
index 9e1c9acf4..f75cfdbd3 100644
--- a/test/unit/test.mak
+++ b/test/unit/test.mak
@@ -20,6 +20,7 @@ TESTEDSRC=\
../../src/ContractionState.cxx \
../../src/Decoration.cxx \
../../src/Document.cxx \
+ ../../src/Geometry.cxx \
../../src/PerLine.cxx \
../../src/RESearch.cxx \
../../src/RunStyles.cxx \
diff --git a/test/unit/testGeometry.cxx b/test/unit/testGeometry.cxx
new file mode 100644
index 000000000..1dca8903c
--- /dev/null
+++ b/test/unit/testGeometry.cxx
@@ -0,0 +1,233 @@
+/** @file testDocument.cxx
+ ** Unit Tests for Scintilla internal data structures
+ **/
+
+#include <cstdint>
+
+#include "Geometry.h"
+
+#include "catch.hpp"
+
+using namespace Scintilla;
+using namespace Scintilla::Internal;
+
+// Test Geometry.
+
+TEST_CASE("Point") {
+
+ SECTION("Point") {
+ constexpr Point pt(1.0, 2.0);
+ REQUIRE(pt.x == 1.0);
+ REQUIRE(pt.y == 2.0);
+
+ constexpr Point pti = Point::FromInts(1, 2);
+ REQUIRE(pt == pti);
+
+ constexpr Point pt2 = pt + pt;
+ REQUIRE(pt != pt2);
+
+ constexpr Point ptBack = pt2 - pt;
+ REQUIRE(pt == ptBack);
+ }
+
+}
+
+TEST_CASE("Interval") {
+
+ SECTION("Interval") {
+ constexpr Interval interval { 1.0, 2.0 };
+ REQUIRE(interval.left == 1.0);
+ REQUIRE(interval.right == 2.0);
+ REQUIRE(interval.Width() == 1.0);
+ REQUIRE(!interval.Empty());
+
+ constexpr Interval empty { 4.0, 4.0 };
+ REQUIRE(empty.Empty());
+ REQUIRE(empty.Width() == 0.0);
+ REQUIRE(!(interval == empty));
+ REQUIRE(!(interval.Intersects(empty)));
+
+ constexpr Interval inside { 1.7, 1.8 };
+ REQUIRE(interval.Intersects(inside));
+ constexpr Interval straddles { 1.7, 2.8 };
+ REQUIRE(interval.Intersects(straddles));
+ }
+
+ SECTION("Interval") {
+ constexpr Interval interval1{ 1.0, 3.0 };
+ constexpr Interval interval2{ 2.0, 4.0 };
+ REQUIRE(Intersection(interval1, interval2) == Interval{ 2.0, 3.0 });
+ }
+}
+
+TEST_CASE("PRectangle") {
+
+ SECTION("PRectangle") {
+ constexpr PRectangle rc(1.0, 2.0, 3.0, 4.0);
+ REQUIRE(rc.left == 1.0);
+ REQUIRE(rc.top == 2.0);
+ REQUIRE(rc.right == 3.0);
+ REQUIRE(rc.bottom == 4.0);
+ REQUIRE(rc.Width() == 2.0);
+ REQUIRE(rc.Height() == 2.0);
+ REQUIRE(!rc.Empty());
+
+ constexpr PRectangle rci = PRectangle::FromInts(1, 2, 3, 4);
+ REQUIRE(rc == rci);
+
+ constexpr PRectangle rcEmpty;
+ REQUIRE(rcEmpty.Empty());
+ }
+
+ SECTION("Contains") {
+ constexpr PRectangle rc(1.0, 2.0, 3.0, 4.0);
+ constexpr Point pt(1.5, 2.5);
+ REQUIRE(rc.Contains(pt));
+ REQUIRE(rc.ContainsWholePixel(pt));
+ constexpr Point ptNearEdge(2.9, 2.5);
+ REQUIRE(rc.Contains(ptNearEdge));
+ REQUIRE(!rc.ContainsWholePixel(ptNearEdge));
+ constexpr Point ptOutside(1.5, 20.5);
+ REQUIRE(!rc.Contains(ptOutside));
+ REQUIRE(!rc.ContainsWholePixel(ptOutside));
+
+ constexpr PRectangle rcInside(1.5, 2.0, 2.5, 4.0);
+ REQUIRE(rc.Contains(rcInside));
+ REQUIRE(rc.Intersects(rcInside));
+
+ constexpr PRectangle rcIntersects(1.5, 2.0, 3.5, 4.0);
+ REQUIRE(!rc.Contains(rcIntersects));
+ REQUIRE(rc.Intersects(rcIntersects));
+
+ constexpr PRectangle rcSeparate(11.0, 12.0, 13.0, 14.0);
+ REQUIRE(!rc.Contains(rcSeparate));
+ REQUIRE(!rc.Intersects(rcSeparate));
+
+ constexpr Point ptCentre = rc.Centre();
+ REQUIRE(ptCentre == Point(2.0, 3.0));
+ }
+
+ SECTION("Move") {
+ PRectangle rc(1.0, 2.0, 3.0, 4.0);
+ rc.Move(1.0, 10.0);
+ REQUIRE(rc == PRectangle(2.0, 12.0, 4.0, 14.0));
+ }
+
+ SECTION("Inset") {
+ constexpr PRectangle rc(1.0, 2.0, 3.0, 4.0);
+ constexpr PRectangle rcInset = rc.Inset(0.5);
+ REQUIRE(rcInset == PRectangle(1.5, 2.5, 2.5, 3.5));
+
+ constexpr PRectangle rcInsetPt = rc.Inset(Point(0.25, 0.5));
+ REQUIRE(rcInsetPt == PRectangle(1.25, 2.5, 2.75, 3.5));
+ }
+
+ SECTION("Clamp") {
+ constexpr PRectangle rc(1.0, 2.0, 3.0, 4.0);
+
+ const PRectangle cutBottom = Clamp(rc, Edge::bottom, 3.5);
+ REQUIRE(cutBottom == PRectangle(1.0, 2.0, 3.0, 3.5));
+
+ const PRectangle justBottom = Side(rc, Edge::bottom, 0.5);
+ REQUIRE(justBottom == PRectangle(1.0, 3.5, 3.0, 4.0));
+
+ constexpr PRectangle rcInset = rc.Inset(0.5);
+ REQUIRE(rcInset == PRectangle(1.5, 2.5, 2.5, 3.5));
+
+ constexpr PRectangle rcInsetPt = rc.Inset(Point(0.25, 0.5));
+ REQUIRE(rcInsetPt == PRectangle(1.25, 2.5, 2.75, 3.5));
+
+ const Interval bounds = HorizontalBounds(rcInsetPt);
+ REQUIRE(bounds == Interval{ 1.25, 2.75 });
+
+ const PRectangle applyBounds = Intersection(rc, bounds);
+ REQUIRE(applyBounds == PRectangle(1.25, 2.0, 2.75, 4.0));
+ }
+
+ SECTION("PixelAlign") {
+ // Whole pixels
+ REQUIRE(PixelAlign(1.0, 1) == 1.0);
+ REQUIRE(PixelAlignFloor(1.0, 1) == 1.0);
+
+ REQUIRE(PixelAlign(1.25, 1) == 1.0);
+ REQUIRE(PixelAlignFloor(1.25, 1) == 1.0);
+
+ REQUIRE(PixelAlign(1.5, 1) == 2.0);
+ REQUIRE(PixelAlignFloor(1.5, 1) == 1.0);
+
+ REQUIRE(PixelAlign(1.75, 1) == 2.0);
+ REQUIRE(PixelAlignFloor(1.75, 1) == 1.0);
+
+ // Half pixels
+ REQUIRE(PixelAlign(1.0, 2) == 1.0);
+ REQUIRE(PixelAlignFloor(1.0, 2) == 1.0);
+
+ REQUIRE(PixelAlign(1.25, 2) == 1.5);
+ REQUIRE(PixelAlignFloor(1.25, 2) == 1.0);
+
+ REQUIRE(PixelAlign(1.5, 2) == 1.5);
+ REQUIRE(PixelAlignFloor(1.5, 2) == 1.5);
+
+ REQUIRE(PixelAlign(1.75, 2) == 2.0);
+ REQUIRE(PixelAlignFloor(1.75, 2) == 1.5);
+
+ REQUIRE(PixelAlign(Point(1.75, 1.25), 2) == Point(2.0, 1.5));
+ REQUIRE(PixelAlign(Point(1.5, 1.0), 2) == Point(1.5, 1.0));
+
+ // x->round, y->floored
+ REQUIRE(PixelAlign(PRectangle(1.0, 1.25, 1.5, 1.75), 2) == PRectangle(1.0, 1.0, 1.5, 1.5));
+
+ // x->outside(floor left, ceil right), y->floored
+ REQUIRE(PixelAlignOutside(PRectangle(1.1, 1.25, 1.6, 1.75), 2) == PRectangle(1.0, 1.0, 2.0, 1.5));
+ }
+
+}
+
+TEST_CASE("ColourRGBA") {
+
+ SECTION("ColourRGBA") {
+ constexpr ColourRGBA colour(0x10203040);
+ constexpr ColourRGBA colourFromRGB(0x40, 0x30, 0x20, 0x10);
+
+ REQUIRE(colour == colourFromRGB);
+ REQUIRE(colour.GetRed() == 0x40);
+ REQUIRE(colour.GetGreen() == 0x30);
+ REQUIRE(colour.GetBlue() == 0x20);
+ REQUIRE(colour.GetAlpha() == 0x10);
+ REQUIRE(!colour.IsOpaque());
+ REQUIRE(colour.AsInteger() == 0x10203040);
+
+ REQUIRE(ColourRGBA(colour, 0x80) == ColourRGBA(0x40, 0x30, 0x20, 0x80));
+ REQUIRE(ColourRGBA::FromRGB(0x203040) == ColourRGBA(0x40, 0x30, 0x20, 0xff));
+ REQUIRE(ColourRGBA::FromIpRGB(0x203040) == ColourRGBA(0x40, 0x30, 0x20, 0xff));
+
+ constexpr ColourRGBA colour01(0x00ff00ff);
+ REQUIRE(colour01.GetRedComponent() == 1.0);
+ REQUIRE(colour01.GetGreenComponent() == 0.0);
+ REQUIRE(colour01.GetBlueComponent() == 1.0);
+ REQUIRE(colour01.GetAlphaComponent() == 0.0);
+
+ // Opaque colours
+ constexpr ColourRGBA colourRGB(0xff203040);
+ REQUIRE(colourRGB.IsOpaque());
+ constexpr ColourRGBA colourOpaque(0x40, 0x30, 0x20, 0xff);
+ REQUIRE(colourRGB == colourOpaque);
+
+ REQUIRE(colourRGB.OpaqueRGB() == 0x203040);
+ REQUIRE(colourRGB.WithoutAlpha() == ColourRGBA(0x40, 0x30, 0x20, 0));
+ }
+
+ SECTION("Mixing") {
+ constexpr ColourRGBA colourMin(0x10, 0x20, 0x30, 0x40);
+ constexpr ColourRGBA colourMax(0x30, 0x60, 0x90, 0xC0);
+
+ constexpr ColourRGBA colourMid(0x20, 0x40, 0x60, 0x80);
+ REQUIRE(colourMin.MixedWith(colourMax) == colourMid);
+ REQUIRE(colourMin.MixedWith(colourMax, 0.5) == colourMid);
+
+ // 3/4 between min and max
+ constexpr ColourRGBA colour75(0x28, 0x50, 0x78, 0xA0);
+ REQUIRE(colourMin.MixedWith(colourMax, 0.75) == colour75);
+ }
+
+}
diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx
index 3e966b4d3..c4f08b798 100644
--- a/win32/PlatWin.cxx
+++ b/win32/PlatWin.cxx
@@ -865,18 +865,6 @@ void DIBSection::SetSymmetric(LONG x, LONG y, DWORD value) noexcept {
SetPixel(xSymmetric, ySymmetric, value);
}
-constexpr unsigned int Proportional(unsigned char a, unsigned char b, XYPOSITION t) noexcept {
- return static_cast<unsigned int>(a + t * (b - a));
-}
-
-ColourRGBA Proportional(ColourRGBA a, ColourRGBA b, XYPOSITION t) noexcept {
- return ColourRGBA(
- Proportional(a.GetRed(), b.GetRed(), t),
- Proportional(a.GetGreen(), b.GetGreen(), t),
- Proportional(a.GetBlue(), b.GetBlue(), t),
- Proportional(a.GetAlpha(), b.GetAlpha(), t));
-}
-
ColourRGBA GradientValue(const std::vector<ColourStop> &stops, XYPOSITION proportion) noexcept {
for (size_t stop = 0; stop < stops.size() - 1; stop++) {
// Loop through each pair of stops
@@ -885,7 +873,7 @@ ColourRGBA GradientValue(const std::vector<ColourStop> &stops, XYPOSITION propor
if ((proportion >= positionStart) && (proportion <= positionEnd)) {
const XYPOSITION proportionInPair = (proportion - positionStart) /
(positionEnd - positionStart);
- return Proportional(stops[stop].colour, stops[stop + 1].colour, proportionInPair);
+ return stops[stop].colour.MixedWith(stops[stop + 1].colour, proportionInPair);
}
}
// Loop should always find a value