From 6ca54e8c97a550798a10c615b5be18160b025dc3 Mon Sep 17 00:00:00 2001 From: Matt Gonzalez Date: Fri, 10 May 2024 20:31:30 -0700 Subject: [PATCH] Direct2D: Add debug check for axis-aligned clip layers This is similar to the check performed by the D2D debug layer that will still work with the debug layer disabled. --- .../juce_Direct2DGraphicsContext_windows.cpp | 67 ++++++++++++++++++- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp b/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp index 0fce545030..96adea4cc9 100644 --- a/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp +++ b/modules/juce_graphics/native/juce_Direct2DGraphicsContext_windows.cpp @@ -54,9 +54,70 @@ public: void push (ComSmartPtr context, const D2D1_LAYER_PARAMETERS& layerParameters) { - // Clipping and transparency are all handled by pushing Direct2D layers. The SavedState creates an internal stack - // of Layer objects to keep track of how many layers need to be popped. - // Pass nullptr for the PushLayer layer parameter to allow Direct2D to manage the layers (Windows 8 or later) + // Clipping and transparency are all handled by pushing Direct2D + // layers.The SavedState creates an internal stack of Layer objects to + // keep track of how many layers need to be popped. Pass nullptr for + // the PushLayer layer parameter to allow Direct2D to manage the layers + // (Windows 8 or later) + + #if JUCE_DEBUG + + // Check if this should be an axis-aligned clip layer (per the D2D + // debug layer) + const auto isGeometryAxisAlignedRectangle = [&] + { + auto* geometry = layerParameters.geometricMask; + + if (geometry == nullptr) + return false; + + struct Sink : public ComBaseClassHelper + { + D2D1_POINT_2F lastPoint{}; + bool axisAlignedLines = true; + UINT32 lineCount = 0; + + STDMETHOD (Close)() override { return S_OK; } + STDMETHOD_ (void, SetFillMode) (D2D1_FILL_MODE) override {} + STDMETHOD_ (void, SetSegmentFlags) (D2D1_PATH_SEGMENT) override {} + STDMETHOD_ (void, EndFigure) (D2D1_FIGURE_END) override {} + + STDMETHOD_ (void, BeginFigure) (D2D1_POINT_2F p, D2D1_FIGURE_BEGIN) override { lastPoint = p; } + + STDMETHOD_ (void, AddLines) (const D2D1_POINT_2F* points, UINT32 count) override + { + for (UINT32 i = 0; i < count; ++i) + { + auto p = points[i]; + + axisAlignedLines &= (approximatelyEqual (p.x, lastPoint.x) || approximatelyEqual (p.y, lastPoint.y)); + lastPoint = p; + } + + lineCount += count; + } + + STDMETHOD_ (void, AddBeziers) (const D2D1_BEZIER_SEGMENT*, UINT32) override + { + axisAlignedLines = false; + } + }; + + Sink sink; + geometry->Simplify (D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, + D2D1::Matrix3x2F::Identity(), + 1.0f, + &sink); + + // Check for 3 lines; the BeginFigure counts as 1 line + return sink.axisAlignedLines && sink.lineCount == 3; + }(); + + jassert (layerParameters.opacity != 1.0f + || layerParameters.opacityBrush + || ! isGeometryAxisAlignedRectangle); + #endif + context->PushLayer (layerParameters, nullptr); pushedLayers.emplace_back (popLayerFlag); }