From d10c5c36e3431badbb598bb89c79fe0aa406bb45 Mon Sep 17 00:00:00 2001 From: reuk Date: Wed, 15 Oct 2025 20:36:55 +0100 Subject: [PATCH] RectangleList: Avoid infinite loops due to numerical precision issues --- .../Builds/Android/app/CMakeLists.txt | 2 + .../VisualStudio2019/DemoRunner_App.vcxproj | 3 + .../DemoRunner_App.vcxproj.filters | 3 + .../VisualStudio2022/DemoRunner_App.vcxproj | 3 + .../DemoRunner_App.vcxproj.filters | 3 + .../VisualStudio2026/DemoRunner_App.vcxproj | 3 + .../DemoRunner_App.vcxproj.filters | 3 + .../Builds/Android/app/CMakeLists.txt | 2 + .../AudioPerformanceTest_App.vcxproj | 3 + .../AudioPerformanceTest_App.vcxproj.filters | 3 + .../AudioPerformanceTest_App.vcxproj | 3 + .../AudioPerformanceTest_App.vcxproj.filters | 3 + .../Builds/Android/app/CMakeLists.txt | 2 + .../AudioPluginHost_App.vcxproj | 3 + .../AudioPluginHost_App.vcxproj.filters | 3 + .../AudioPluginHost_App.vcxproj | 3 + .../AudioPluginHost_App.vcxproj.filters | 3 + .../AudioPluginHost_App.vcxproj | 3 + .../AudioPluginHost_App.vcxproj.filters | 3 + .../Builds/Android/app/CMakeLists.txt | 2 + .../NetworkGraphicsDemo_App.vcxproj | 3 + .../NetworkGraphicsDemo_App.vcxproj.filters | 3 + .../NetworkGraphicsDemo_App.vcxproj | 3 + .../NetworkGraphicsDemo_App.vcxproj.filters | 3 + .../VisualStudio2019/Projucer_App.vcxproj | 3 + .../Projucer_App.vcxproj.filters | 3 + .../VisualStudio2022/Projucer_App.vcxproj | 3 + .../Projucer_App.vcxproj.filters | 3 + .../VisualStudio2026/Projucer_App.vcxproj | 3 + .../Projucer_App.vcxproj.filters | 3 + .../UnitTestRunner_ConsoleApp.vcxproj | 3 + .../UnitTestRunner_ConsoleApp.vcxproj.filters | 3 + .../UnitTestRunner_ConsoleApp.vcxproj | 3 + .../UnitTestRunner_ConsoleApp.vcxproj.filters | 3 + .../UnitTestRunner_ConsoleApp.vcxproj | 3 + .../UnitTestRunner_ConsoleApp.vcxproj.filters | 3 + .../WindowsDLL_DynamicLibrary.vcxproj | 3 + .../WindowsDLL_DynamicLibrary.vcxproj.filters | 3 + .../WindowsDLL_DynamicLibrary.vcxproj | 3 + .../WindowsDLL_DynamicLibrary.vcxproj.filters | 3 + .../geometry/juce_RectangleList.h | 130 +++++------ .../geometry/juce_RectangleList_test.cpp | 202 ++++++++++++++++++ modules/juce_graphics/juce_graphics.cpp | 1 + 43 files changed, 376 insertions(+), 73 deletions(-) create mode 100644 modules/juce_graphics/geometry/juce_RectangleList_test.cpp 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