diff --git a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt
index db1e608e8b..1ec40972b7 100644
--- a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt
+++ b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt
@@ -1937,6 +1937,7 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_graphics/geometry/juce_Rectangle.h"
"../../../../../modules/juce_graphics/geometry/juce_Rectangle_test.cpp"
"../../../../../modules/juce_graphics/geometry/juce_RectangleList.h"
+ "../../../../../modules/juce_graphics/geometry/juce_RectangleList_test.cpp"
"../../../../../modules/juce_graphics/image_formats/jpglib/cderror.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/cdjpeg.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/changes to libjpeg for JUCE.txt"
@@ -4652,6 +4653,7 @@ set_source_files_properties(
"../../../../../modules/juce_graphics/geometry/juce_Rectangle.h"
"../../../../../modules/juce_graphics/geometry/juce_Rectangle_test.cpp"
"../../../../../modules/juce_graphics/geometry/juce_RectangleList.h"
+ "../../../../../modules/juce_graphics/geometry/juce_RectangleList_test.cpp"
"../../../../../modules/juce_graphics/image_formats/jpglib/cderror.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/cdjpeg.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/changes to libjpeg for JUCE.txt"
diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj
index 00a51b3abf..84d092e0e9 100644
--- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj
+++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj
@@ -2247,6 +2247,9 @@
true
+
+ true
+
true
diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters
index ee4b4a2948..802c8e652b 100644
--- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters
+++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters
@@ -3034,6 +3034,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj
index 4c8db8947b..7c10f1ffa2 100644
--- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj
+++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj
@@ -2247,6 +2247,9 @@
true
+
+ true
+
true
diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters
index ecc5704646..fa3173a707 100644
--- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters
+++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters
@@ -3034,6 +3034,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/examples/DemoRunner/Builds/VisualStudio2026/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2026/DemoRunner_App.vcxproj
index 1f98c01d24..3188c63b75 100644
--- a/examples/DemoRunner/Builds/VisualStudio2026/DemoRunner_App.vcxproj
+++ b/examples/DemoRunner/Builds/VisualStudio2026/DemoRunner_App.vcxproj
@@ -2247,6 +2247,9 @@
true
+
+ true
+
true
diff --git a/examples/DemoRunner/Builds/VisualStudio2026/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2026/DemoRunner_App.vcxproj.filters
index d7ffc71052..7beb5aec0f 100644
--- a/examples/DemoRunner/Builds/VisualStudio2026/DemoRunner_App.vcxproj.filters
+++ b/examples/DemoRunner/Builds/VisualStudio2026/DemoRunner_App.vcxproj.filters
@@ -3034,6 +3034,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
index fabdb793a7..5d07f2f9da 100644
--- a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
+++ b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
@@ -1699,6 +1699,7 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_graphics/geometry/juce_Rectangle.h"
"../../../../../modules/juce_graphics/geometry/juce_Rectangle_test.cpp"
"../../../../../modules/juce_graphics/geometry/juce_RectangleList.h"
+ "../../../../../modules/juce_graphics/geometry/juce_RectangleList_test.cpp"
"../../../../../modules/juce_graphics/image_formats/jpglib/cderror.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/cdjpeg.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/changes to libjpeg for JUCE.txt"
@@ -4028,6 +4029,7 @@ set_source_files_properties(
"../../../../../modules/juce_graphics/geometry/juce_Rectangle.h"
"../../../../../modules/juce_graphics/geometry/juce_Rectangle_test.cpp"
"../../../../../modules/juce_graphics/geometry/juce_RectangleList.h"
+ "../../../../../modules/juce_graphics/geometry/juce_RectangleList_test.cpp"
"../../../../../modules/juce_graphics/image_formats/jpglib/cderror.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/cdjpeg.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/changes to libjpeg for JUCE.txt"
diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj
index 5019784f1f..9aef59e921 100644
--- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj
+++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj
@@ -1938,6 +1938,9 @@
true
+
+ true
+
true
diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters
index 37e08551c7..59f23766b8 100644
--- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters
+++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters
@@ -2542,6 +2542,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2026/AudioPerformanceTest_App.vcxproj b/extras/AudioPerformanceTest/Builds/VisualStudio2026/AudioPerformanceTest_App.vcxproj
index 22404f4366..9b55ed2d3f 100644
--- a/extras/AudioPerformanceTest/Builds/VisualStudio2026/AudioPerformanceTest_App.vcxproj
+++ b/extras/AudioPerformanceTest/Builds/VisualStudio2026/AudioPerformanceTest_App.vcxproj
@@ -1938,6 +1938,9 @@
true
+
+ true
+
true
diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2026/AudioPerformanceTest_App.vcxproj.filters b/extras/AudioPerformanceTest/Builds/VisualStudio2026/AudioPerformanceTest_App.vcxproj.filters
index 67d110aca3..e3b446db81 100644
--- a/extras/AudioPerformanceTest/Builds/VisualStudio2026/AudioPerformanceTest_App.vcxproj.filters
+++ b/extras/AudioPerformanceTest/Builds/VisualStudio2026/AudioPerformanceTest_App.vcxproj.filters
@@ -2542,6 +2542,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
index d613909094..63174c95de 100644
--- a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
+++ b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
@@ -1829,6 +1829,7 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_graphics/geometry/juce_Rectangle.h"
"../../../../../modules/juce_graphics/geometry/juce_Rectangle_test.cpp"
"../../../../../modules/juce_graphics/geometry/juce_RectangleList.h"
+ "../../../../../modules/juce_graphics/geometry/juce_RectangleList_test.cpp"
"../../../../../modules/juce_graphics/image_formats/jpglib/cderror.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/cdjpeg.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/changes to libjpeg for JUCE.txt"
@@ -4311,6 +4312,7 @@ set_source_files_properties(
"../../../../../modules/juce_graphics/geometry/juce_Rectangle.h"
"../../../../../modules/juce_graphics/geometry/juce_Rectangle_test.cpp"
"../../../../../modules/juce_graphics/geometry/juce_RectangleList.h"
+ "../../../../../modules/juce_graphics/geometry/juce_RectangleList_test.cpp"
"../../../../../modules/juce_graphics/image_formats/jpglib/cderror.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/cdjpeg.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/changes to libjpeg for JUCE.txt"
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj
index 297fcb3297..42e6666d6a 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj
+++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj
@@ -2072,6 +2072,9 @@
true
+
+ true
+
true
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters
index 77f12b0f98..7172fddd75 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters
+++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters
@@ -2749,6 +2749,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj
index fedc706cf1..0a43275a52 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj
+++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj
@@ -2072,6 +2072,9 @@
true
+
+ true
+
true
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters
index 9101a3de94..763f8e1b4c 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters
+++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters
@@ -2749,6 +2749,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2026/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2026/AudioPluginHost_App.vcxproj
index 14c323dbc0..3df48c8ae3 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2026/AudioPluginHost_App.vcxproj
+++ b/extras/AudioPluginHost/Builds/VisualStudio2026/AudioPluginHost_App.vcxproj
@@ -2072,6 +2072,9 @@
true
+
+ true
+
true
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2026/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2026/AudioPluginHost_App.vcxproj.filters
index b752cf810b..1c1dcf7702 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2026/AudioPluginHost_App.vcxproj.filters
+++ b/extras/AudioPluginHost/Builds/VisualStudio2026/AudioPluginHost_App.vcxproj.filters
@@ -2749,6 +2749,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
index 4989478570..20529e7fb2 100644
--- a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
+++ b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
@@ -1718,6 +1718,7 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_graphics/geometry/juce_Rectangle.h"
"../../../../../modules/juce_graphics/geometry/juce_Rectangle_test.cpp"
"../../../../../modules/juce_graphics/geometry/juce_RectangleList.h"
+ "../../../../../modules/juce_graphics/geometry/juce_RectangleList_test.cpp"
"../../../../../modules/juce_graphics/image_formats/jpglib/cderror.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/cdjpeg.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/changes to libjpeg for JUCE.txt"
@@ -4127,6 +4128,7 @@ set_source_files_properties(
"../../../../../modules/juce_graphics/geometry/juce_Rectangle.h"
"../../../../../modules/juce_graphics/geometry/juce_Rectangle_test.cpp"
"../../../../../modules/juce_graphics/geometry/juce_RectangleList.h"
+ "../../../../../modules/juce_graphics/geometry/juce_RectangleList_test.cpp"
"../../../../../modules/juce_graphics/image_formats/jpglib/cderror.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/cdjpeg.h"
"../../../../../modules/juce_graphics/image_formats/jpglib/changes to libjpeg for JUCE.txt"
diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj
index 9d2f47b275..138716d64c 100644
--- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj
+++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj
@@ -1959,6 +1959,9 @@
true
+
+ true
+
true
diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters
index 62046c2c19..56b118ff4b 100644
--- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters
+++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters
@@ -2596,6 +2596,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2026/NetworkGraphicsDemo_App.vcxproj b/extras/NetworkGraphicsDemo/Builds/VisualStudio2026/NetworkGraphicsDemo_App.vcxproj
index 4ed4523c91..6100cf0493 100644
--- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2026/NetworkGraphicsDemo_App.vcxproj
+++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2026/NetworkGraphicsDemo_App.vcxproj
@@ -1959,6 +1959,9 @@
true
+
+ true
+
true
diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2026/NetworkGraphicsDemo_App.vcxproj.filters b/extras/NetworkGraphicsDemo/Builds/VisualStudio2026/NetworkGraphicsDemo_App.vcxproj.filters
index a54142056e..c0e0783538 100644
--- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2026/NetworkGraphicsDemo_App.vcxproj.filters
+++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2026/NetworkGraphicsDemo_App.vcxproj.filters
@@ -2596,6 +2596,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj
index 97af1ac929..ddb3226564 100644
--- a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj
+++ b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj
@@ -1059,6 +1059,9 @@
true
+
+ true
+
true
diff --git a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters
index 349d7da1e3..b905c3eb80 100644
--- a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters
+++ b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters
@@ -1384,6 +1384,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj
index 3dab692a4c..032e8b26d1 100644
--- a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj
+++ b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj
@@ -1059,6 +1059,9 @@
true
+
+ true
+
true
diff --git a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters
index 30128c60c3..2002ae4ce0 100644
--- a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters
+++ b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters
@@ -1384,6 +1384,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/Projucer/Builds/VisualStudio2026/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2026/Projucer_App.vcxproj
index 2d73a63056..178e108b13 100644
--- a/extras/Projucer/Builds/VisualStudio2026/Projucer_App.vcxproj
+++ b/extras/Projucer/Builds/VisualStudio2026/Projucer_App.vcxproj
@@ -1059,6 +1059,9 @@
true
+
+ true
+
true
diff --git a/extras/Projucer/Builds/VisualStudio2026/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2026/Projucer_App.vcxproj.filters
index 6fef0ee479..429e2dba2a 100644
--- a/extras/Projucer/Builds/VisualStudio2026/Projucer_App.vcxproj.filters
+++ b/extras/Projucer/Builds/VisualStudio2026/Projucer_App.vcxproj.filters
@@ -1384,6 +1384,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj
index 491c7eea61..3e839c5c68 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj
+++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj
@@ -2080,6 +2080,9 @@
true
+
+ true
+
true
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters
index fb4c68e778..1360616679 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters
+++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters
@@ -2797,6 +2797,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj
index 9ea7f226b3..adb0fe094b 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj
+++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj
@@ -2080,6 +2080,9 @@
true
+
+ true
+
true
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters
index 87a646caf9..a566bd31a7 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters
+++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters
@@ -2797,6 +2797,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2026/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2026/UnitTestRunner_ConsoleApp.vcxproj
index f7c7c6f8dc..141b97b51c 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2026/UnitTestRunner_ConsoleApp.vcxproj
+++ b/extras/UnitTestRunner/Builds/VisualStudio2026/UnitTestRunner_ConsoleApp.vcxproj
@@ -2080,6 +2080,9 @@
true
+
+ true
+
true
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2026/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2026/UnitTestRunner_ConsoleApp.vcxproj.filters
index e785cacd21..185fce60f4 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2026/UnitTestRunner_ConsoleApp.vcxproj.filters
+++ b/extras/UnitTestRunner/Builds/VisualStudio2026/UnitTestRunner_ConsoleApp.vcxproj.filters
@@ -2797,6 +2797,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj
index b43317f38c..ccbbc33c5c 100644
--- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj
+++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj
@@ -1958,6 +1958,9 @@
true
+
+ true
+
true
diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj.filters b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj.filters
index 42b89485d3..4f679bddb3 100644
--- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj.filters
+++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj.filters
@@ -2593,6 +2593,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/extras/WindowsDLL/Builds/VisualStudio2026/WindowsDLL_DynamicLibrary.vcxproj b/extras/WindowsDLL/Builds/VisualStudio2026/WindowsDLL_DynamicLibrary.vcxproj
index 28326bf6a5..6f9720166b 100644
--- a/extras/WindowsDLL/Builds/VisualStudio2026/WindowsDLL_DynamicLibrary.vcxproj
+++ b/extras/WindowsDLL/Builds/VisualStudio2026/WindowsDLL_DynamicLibrary.vcxproj
@@ -1958,6 +1958,9 @@
true
+
+ true
+
true
diff --git a/extras/WindowsDLL/Builds/VisualStudio2026/WindowsDLL_DynamicLibrary.vcxproj.filters b/extras/WindowsDLL/Builds/VisualStudio2026/WindowsDLL_DynamicLibrary.vcxproj.filters
index ecba674d05..f50ec19920 100644
--- a/extras/WindowsDLL/Builds/VisualStudio2026/WindowsDLL_DynamicLibrary.vcxproj.filters
+++ b/extras/WindowsDLL/Builds/VisualStudio2026/WindowsDLL_DynamicLibrary.vcxproj.filters
@@ -2593,6 +2593,9 @@
JUCE Modules\juce_graphics\geometry
+
+ JUCE Modules\juce_graphics\geometry
+
JUCE Modules\juce_graphics\image_formats\jpglib
diff --git a/modules/juce_graphics/geometry/juce_RectangleList.h b/modules/juce_graphics/geometry/juce_RectangleList.h
index 3c08392d17..535802d71b 100644
--- a/modules/juce_graphics/geometry/juce_RectangleList.h
+++ b/modules/juce_graphics/geometry/juce_RectangleList.h
@@ -212,111 +212,95 @@ public:
*/
void subtract (const RectangleType rect)
{
+ using PointType = Point;
+
const auto numRects = rects.size();
if (numRects == 0)
return;
- const auto x1 = rect.getX();
- const auto y1 = rect.getY();
- const auto x2 = x1 + rect.getWidth();
- const auto y2 = y1 + rect.getHeight();
+ struct AABB
+ {
+ AABB() = default;
+ AABB (const RectangleType& r) : tl (r.getTopLeft()), br (r.getBottomRight()) {}
+ AABB (PointType a, PointType b) : tl (a), br (b) {}
+ operator RectangleType() const { return RectangleType { tl, br }; }
+
+ bool completelyOutside (const AABB& other) const
+ {
+ return other.br.x <= tl.x || br.x <= other.tl.x || other.br.y <= tl.y || br.y <= other.tl.y;
+ }
+
+ PointType tl, br;
+ };
+
+ Array aabbs;
+ aabbs.resize (rects.size());
+ std::copy (rects.begin(), rects.end(), aabbs.begin());
+ const AABB aabb { rect };
for (int i = numRects; --i >= 0;)
{
- auto& r = rects.getReference (i);
+ auto& rRef = aabbs.getReference (i);;
+ const auto r = rRef;
- const auto rx1 = r.getX();
- const auto ry1 = r.getY();
- const auto rx2 = rx1 + r.getWidth();
- const auto ry2 = ry1 + r.getHeight();
+ if (r.completelyOutside (aabb))
+ continue;
- const auto isNotEqual = [&] (const RectangleType newRect)
+ if (r.tl.x < aabb.tl.x && aabb.tl.x < r.br.x)
{
- // When subtracting tiny slices from relatively large rectangles, the
- // subtraction may have no effect (due to limited-precision floating point
- // maths) and the original rectangle may remain unchanged.
- // We check that any 'new' rectangle has different dimensions to the rectangle
- // being tested before adding it to the rects array.
- // Integer arithmetic is not susceptible to this problem, so there's no need
- // for this additional equality check when working with integral rectangles.
- if constexpr (std::is_floating_point_v)
+ if (aabb.tl.y <= r.tl.y && r.br.y <= aabb.br.y && r.br.x <= aabb.br.x)
{
- return newRect != r;
+ rRef.br.x = aabb.tl.x;
}
else
{
- ignoreUnused (newRect);
- return true;
- }
- };
-
- if (! (rx1 < x2 && x1 < rx2 && ry1 < y2 && y1 < ry2))
- continue;
-
- if (rx1 < x1 && x1 < rx2)
- {
- if (y1 <= ry1 && ry2 <= y2 && rx2 <= x2)
- {
- r.setWidth (x1 - rx1);
- }
- else if (const RectangleType newRect (rx1, ry1, x1 - rx1, ry2 - ry1); isNotEqual (newRect))
- {
- r.setX (x1);
- r.setWidth (rx2 - x1);
-
- rects.insert (++i, newRect);
+ rRef.tl.x = aabb.tl.x;
+ aabbs.insert (++i, { r.tl, { aabb.tl.x, r.br.y } });
++i;
}
}
- else if (rx1 < x2 && x2 < rx2)
+ else if (r.tl.x < aabb.br.x && aabb.br.x < r.br.x)
{
- r.setX (x2);
- r.setWidth (rx2 - x2);
+ rRef.tl.x = aabb.br.x;
- if (ry1 < y1 || y2 < ry2 || rx1 < x1)
+ if (r.tl.y < aabb.tl.y || aabb.br.y < r.br.y || r.tl.x < aabb.tl.x)
{
- if (const RectangleType newRect (rx1, ry1, x2 - rx1, ry2 - ry1); isNotEqual (newRect))
- {
- rects.insert (++i, newRect);
- ++i;
- }
- }
- }
- else if (ry1 < y1 && y1 < ry2)
- {
- if (x1 <= rx1 && rx2 <= x2 && ry2 <= y2)
- {
- r.setHeight (y1 - ry1);
- }
- else if (const RectangleType newRect (rx1, ry1, rx2 - rx1, y1 - ry1); isNotEqual (newRect))
- {
- r.setY (y1);
- r.setHeight (ry2 - y1);
-
- rects.insert (++i, newRect);
+ aabbs.insert (++i, { r.tl, { aabb.br.x, r.br.y } });
++i;
}
}
- else if (ry1 < y2 && y2 < ry2)
+ else if (r.tl.y < aabb.tl.y && aabb.tl.y < r.br.y)
{
- r.setY (y2);
- r.setHeight (ry2 - y2);
-
- if (rx1 < x1 || x2 < rx2 || ry1 < y1)
+ if (aabb.tl.x <= r.tl.x && r.br.x <= aabb.br.x && r.br.y <= aabb.br.y)
{
- if (const RectangleType newRect (rx1, ry1, rx2 - rx1, y2 - ry1); isNotEqual (newRect))
- {
- rects.insert (++i, newRect);
- ++i;
- }
+ rRef.br.y = aabb.tl.y;
+ }
+ else
+ {
+ rRef.tl.y = aabb.tl.y;
+ aabbs.insert (++i, { r.tl, { r.br.x, aabb.tl.y } });
+ ++i;
+ }
+ }
+ else if (r.tl.y < aabb.br.y && aabb.br.y < r.br.y)
+ {
+ rRef.tl.y = aabb.br.y;
+
+ if (r.tl.x < aabb.tl.x || aabb.br.x < r.br.x || r.tl.y < aabb.tl.y)
+ {
+ aabbs.insert (++i, { r.tl, { r.br.x, aabb.br.y } });
+ ++i;
}
}
else
{
- rects.remove (i);
+ aabbs.remove (i);
}
}
+
+ rects.resize (aabbs.size());
+ std::copy (aabbs.begin(), aabbs.end(), rects.begin());
}
/** Removes all areas in another RectangleList from this one.
diff --git a/modules/juce_graphics/geometry/juce_RectangleList_test.cpp b/modules/juce_graphics/geometry/juce_RectangleList_test.cpp
new file mode 100644
index 0000000000..a8ba5b0c77
--- /dev/null
+++ b/modules/juce_graphics/geometry/juce_RectangleList_test.cpp
@@ -0,0 +1,202 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE framework.
+ Copyright (c) Raw Material Software Limited
+
+ JUCE is an open source framework subject to commercial or open source
+ licensing.
+
+ By downloading, installing, or using the JUCE framework, or combining the
+ JUCE framework with any other source code, object code, content or any other
+ copyrightable work, you agree to the terms of the JUCE End User Licence
+ Agreement, and all incorporated terms including the JUCE Privacy Policy and
+ the JUCE Website Terms of Service, as applicable, which will bind you. If you
+ do not agree to the terms of these agreements, we will not license the JUCE
+ framework to you, and you must discontinue the installation or download
+ process and cease use of the JUCE framework.
+
+ JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
+ JUCE Privacy Policy: https://juce.com/juce-privacy-policy
+ JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
+
+ Or:
+
+ You may also use this code under the terms of the AGPLv3:
+ https://www.gnu.org/licenses/agpl-3.0.en.html
+
+ THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
+ WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
+
+ ==============================================================================
+*/
+
+namespace juce
+{
+
+class RectangleListTests : public UnitTest
+{
+public:
+ RectangleListTests() : UnitTest ("RectangleList", UnitTestCategories::graphics) {}
+
+ void runTest() override
+ {
+ beginTest ("Avoid infinite loops when adding rectangles");
+ {
+ const Rectangle rectanglesA[]
+ {
+ { { -9.15555f, 5.06667f }, { 12.f, 5.15556f } },
+ { { -9.11111f, 5.11111f }, { 12.f, 5.2f } },
+ };
+
+ RectangleList a;
+
+ for (const auto& rect : rectanglesA)
+ a.add (rect);
+
+ const std::set> expectedA { { { -9.15555f, 5.06666994f }, { 12.0f, 5.15556f } },
+ { { -9.11111f, 5.15556f }, { 12.0f, 5.2f } } };
+
+ for (const auto& r : expectedA)
+ expect (std::find (a.begin(), a.end(), r) != a.end());
+
+ const Rectangle rectanglesB[]
+ {
+ { 565.15887451171875, 777.1043701171875, 454, 212 },
+ { -1368.379150390625, 175.8321533203125, 2241.439453125, 782.1121826171875 },
+ };
+
+ RectangleList b;
+
+ for (const auto& rect : rectanglesB)
+ b.add (rect);
+
+ const std::set> expectedB { { { 565.15887451171875, 777.1043701171875 }, { 1019.15887451171875, 989.1043701171875 } },
+ { { 565.15887451171875, 175.8321533203125 }, { 873.060302734375, 777.1043701171875 } },
+ { { -1368.379150390625, 175.8321533203125 }, { 565.158935546875, 957.9443359375 } } };
+
+ for (const auto& r : expectedB)
+ expect (std::find (b.begin(), b.end(), r) != b.end());
+ }
+
+ beginTest ("Subtracting overlapping empty rect subdivides existing rects");
+ {
+ RectangleList list;
+ list.add ({ 10, 10, 80, 80 });
+ list.subtract ({ 50, 50, 0, 0 });
+
+ // The overlapping rect gets subdivided on the X axis at the location of the empty rect.
+ const std::set> expected { { 10, 10, 40, 80 },
+ { 50, 10, 40, 80 } };
+
+ for (const auto& r : expected)
+ expect (std::find (list.begin(), list.end(), r) != list.end());
+ }
+
+ beginTest ("Subtracting non-overlapping rects has no effect");
+ {
+ RectangleList list;
+ list.add ({ 10, 10, 80, 80 });
+
+ list.subtract ({ 0, 0, 5, 5 });
+ list.subtract ({ 0, 95, 5, 5 });
+ list.subtract ({ 95, 0, 5, 5 });
+ list.subtract ({ 95, 95, 5, 5 });
+
+ expect (list.getNumRectangles() == 1);
+ expect (*list.begin() == Rectangle { 10, 10, 80, 80 });
+ }
+
+ beginTest ("Subtracting from corner produces two rects");
+ {
+ RectangleList list;
+ list.add ({ 10, 10, 80, 80 });
+
+ list.subtract ({ 0, 0, 50, 50 });
+
+ const std::set> expected { { 50, 10, 40, 80 },
+ { 10, 50, 40, 40 } };
+
+ for (const auto& r : expected)
+ expect (std::find (list.begin(), list.end(), r) != list.end());
+ }
+
+ beginTest ("Subtracting from entire edge shrinks existing rect");
+ {
+ RectangleList list;
+ list.add ({ 10, 10, 80, 80 });
+
+ list.subtract ({ 0, 0, 30, 100 });
+ list.subtract ({ 30, 50, 60, 40 });
+
+ const std::set> expected { { 30, 10, 60, 40 } };
+
+ for (const auto& r : expected)
+ expect (std::find (list.begin(), list.end(), r) != list.end());
+ }
+
+ beginTest ("Subtracting a notch from a vertical edge produces new rects");
+ {
+ RectangleList list;
+ list.add ({ 10, 10, 80, 80 });
+ list.subtract ({ 10, 20, 10, 60 });
+
+ const std::set> expected { { 20, 10, 70, 80 },
+ { 10, 80, 10, 10 },
+ { 10, 10, 10, 10} };
+
+ for (auto r : list)
+ expect (std::find (list.begin(), list.end(), r) != list.end());
+ }
+
+ beginTest ("Subtracting a notch from a horizontal edge produces new rects");
+ {
+ RectangleList list;
+ list.add ({ 10, 10, 80, 80 });
+ list.subtract ({ 20, 10, 60, 10 });
+
+ const std::set> expected { { 80, 10, 10, 80 },
+ { 20, 20, 60, 70 },
+ { 10, 10, 10, 80 } };
+
+ for (auto r : list)
+ expect (std::find (list.begin(), list.end(), r) != list.end());
+ }
+
+ beginTest ("Subtracting a hole from the centre of a rect produces new rects");
+ {
+ RectangleList list;
+ list.add ({ 10, 10, 80, 80 });
+ list.subtract ({ 20, 20, 60, 60 });
+
+ const std::set> expected { { 10, 10, 10, 80 },
+ { 20, 10, 60, 10 },
+ { 20, 80, 60, 10 },
+ { 80, 10, 10, 80 } };
+
+ for (auto r : list)
+ expect (std::find (list.begin(), list.end(), r) != list.end());
+ }
+
+ beginTest ("Subtracting a rect from itself produces an empty list");
+ {
+ RectangleList list;
+ list.add ({ 10, 10, 80, 80 });
+ list.subtract ({ 10, 10, 80, 80 });
+ expect (list.isEmpty());
+ }
+
+ beginTest ("Subtracting a larger rect from a rect list produces an empty list");
+ {
+ RectangleList list;
+ list.add ({ 10, 10, 80, 80 });
+ list.subtract ({ 0, 0, 100, 100 });
+ expect (list.isEmpty());
+ }
+ }
+};
+
+static RectangleListTests rectangleListTests;
+
+} // namespace juce
diff --git a/modules/juce_graphics/juce_graphics.cpp b/modules/juce_graphics/juce_graphics.cpp
index 7af204e8b8..8a0c74864f 100644
--- a/modules/juce_graphics/juce_graphics.cpp
+++ b/modules/juce_graphics/juce_graphics.cpp
@@ -209,6 +209,7 @@ extern "C"
#if JUCE_UNIT_TESTS
#include "geometry/juce_Parallelogram_test.cpp"
#include "geometry/juce_Rectangle_test.cpp"
+ #include "geometry/juce_RectangleList_test.cpp"
#endif
#if JUCE_USE_FREETYPE