From c0f31aa12a2c5ab5104882f085052ba668b813cf Mon Sep 17 00:00:00 2001 From: attila Date: Mon, 5 Sep 2022 11:21:34 +0200 Subject: [PATCH] CoreGraphics: fillAll() fills a larger area to avoid alpha blended edges Alternatively we could disable antialiasing before the fill operation but this could cause neighbouring Components to overlap on the screen even if their coordinates don't. --- .../contexts/juce_GraphicsContext.cpp | 6 ++---- .../contexts/juce_LowLevelGraphicsContext.h | 1 + .../native/juce_mac_CoreGraphicsContext.h | 1 + .../native/juce_mac_CoreGraphicsContext.mm | 20 +++++++++++++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/modules/juce_graphics/contexts/juce_GraphicsContext.cpp b/modules/juce_graphics/contexts/juce_GraphicsContext.cpp index 4cf700771b..640ac3b599 100644 --- a/modules/juce_graphics/contexts/juce_GraphicsContext.cpp +++ b/modules/juce_graphics/contexts/juce_GraphicsContext.cpp @@ -540,18 +540,16 @@ void Graphics::fillRectList (const RectangleList& rects) const void Graphics::fillAll() const { - fillRect (context.getClipBounds()); + context.fillAll(); } void Graphics::fillAll (Colour colourToUse) const { if (! colourToUse.isTransparent()) { - auto clip = context.getClipBounds(); - context.saveState(); context.setFill (colourToUse); - context.fillRect (clip, false); + context.fillAll(); context.restoreState(); } } diff --git a/modules/juce_graphics/contexts/juce_LowLevelGraphicsContext.h b/modules/juce_graphics/contexts/juce_LowLevelGraphicsContext.h index e34a42fe6c..29070743b3 100644 --- a/modules/juce_graphics/contexts/juce_LowLevelGraphicsContext.h +++ b/modules/juce_graphics/contexts/juce_LowLevelGraphicsContext.h @@ -86,6 +86,7 @@ public: virtual void setInterpolationQuality (Graphics::ResamplingQuality) = 0; //============================================================================== + virtual void fillAll() { fillRect (getClipBounds(), false); } virtual void fillRect (const Rectangle&, bool replaceExistingContents) = 0; virtual void fillRect (const Rectangle&) = 0; virtual void fillRectList (const RectangleList&) = 0; diff --git a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h index aa323fa637..0a180f0f6f 100644 --- a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h +++ b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.h @@ -95,6 +95,7 @@ public: void setInterpolationQuality (Graphics::ResamplingQuality) override; //============================================================================== + void fillAll() override; void fillRect (const Rectangle&, bool replaceExistingContents) override; void fillRect (const Rectangle&) override; void fillRectList (const RectangleList&) override; diff --git a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm index 7e78c80442..16edaf22c4 100644 --- a/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm +++ b/modules/juce_graphics/native/juce_mac_CoreGraphicsContext.mm @@ -428,6 +428,26 @@ void CoreGraphicsContext::setInterpolationQuality (Graphics::ResamplingQuality q } //============================================================================== +void CoreGraphicsContext::fillAll() +{ + // The clip rectangle is expanded in order to avoid having alpha blended pixels at the edges. + // The clipping mechanism will take care of cutting off pixels beyond the clip bounds. This is + // a hard cutoff and will ensure that no semi-transparent pixels will remain inside the filled + // area. + const auto clipBounds = getClipBounds(); + + const auto clipBoundsOnDevice = CGContextConvertSizeToDeviceSpace (context.get(), + CGSize { (CGFloat) clipBounds.getWidth(), + (CGFloat) clipBounds.getHeight() }); + + const auto inverseScale = clipBoundsOnDevice.width > (CGFloat) 0.0 + ? (int) (clipBounds.getWidth() / clipBoundsOnDevice.width) + : 0; + const auto expansion = jmax (1, inverseScale); + + fillRect (clipBounds.expanded (expansion), false); +} + void CoreGraphicsContext::fillRect (const Rectangle& r, bool replaceExistingContents) { fillCGRect (CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()), replaceExistingContents);