| @@ -384,7 +384,7 @@ void Graphics::strokePath (const Path& path, | |||
| const AffineTransform& transform) const | |||
| { | |||
| Path stroke; | |||
| strokeType.createStrokedPath (stroke, path, transform, context.getScaleFactor()); | |||
| strokeType.createStrokedPath (stroke, path, transform, context.getPhysicalPixelScaleFactor()); | |||
| fillPath (stroke); | |||
| } | |||
| @@ -66,8 +66,7 @@ public: | |||
| */ | |||
| virtual void setOrigin (int x, int y) = 0; | |||
| virtual void addTransform (const AffineTransform&) = 0; | |||
| virtual float getScaleFactor() = 0; | |||
| virtual float getTargetDeviceScaleFactor() = 0; | |||
| virtual float getPhysicalPixelScaleFactor() = 0; | |||
| virtual bool clipToRectangle (const Rectangle<int>&) = 0; | |||
| virtual bool clipToRectangleList (const RectangleList<int>&) = 0; | |||
| @@ -105,8 +105,7 @@ void LowLevelGraphicsPostScriptRenderer::addTransform (const AffineTransform& /* | |||
| jassertfalse; | |||
| } | |||
| float LowLevelGraphicsPostScriptRenderer::getScaleFactor() { return 1.0f; } | |||
| float LowLevelGraphicsPostScriptRenderer::getTargetDeviceScaleFactor() { return 1.0f; } | |||
| float LowLevelGraphicsPostScriptRenderer::getPhysicalPixelScaleFactor() { return 1.0f; } | |||
| bool LowLevelGraphicsPostScriptRenderer::clipToRectangle (const Rectangle<int>& r) | |||
| { | |||
| @@ -49,8 +49,7 @@ public: | |||
| bool isVectorDevice() const override; | |||
| void setOrigin (int x, int y) override; | |||
| void addTransform (const AffineTransform&) override; | |||
| float getScaleFactor() override; | |||
| float getTargetDeviceScaleFactor() override; | |||
| float getPhysicalPixelScaleFactor() override; | |||
| bool clipToRectangle (const Rectangle<int>&) override; | |||
| bool clipToRectangleList (const RectangleList<int>&) override; | |||
| @@ -86,12 +86,9 @@ public: | |||
| } | |||
| } | |||
| float getScaleFactor() const noexcept | |||
| float getPhysicalPixelScaleFactor() const noexcept | |||
| { | |||
| return isOnlyTranslated ? 1.0f | |||
| : (isRotated ? complexTransform.getScaleFactor() | |||
| : jmax (complexTransform.mat00, | |||
| complexTransform.mat11)); | |||
| return isOnlyTranslated ? 1.0f : complexTransform.getScaleFactor(); | |||
| } | |||
| void moveOriginInDeviceSpace (Point<int> delta) noexcept | |||
| @@ -2182,15 +2179,17 @@ public: | |||
| if (clip != nullptr) | |||
| { | |||
| if (transform.isOnlyTranslated) | |||
| { | |||
| fillTargetRect (transform.translated (r), replaceContents); | |||
| } | |||
| else if (! transform.isRotated) | |||
| { | |||
| fillTargetRect (transform.transformed (r), replaceContents); | |||
| } | |||
| else | |||
| { | |||
| jassert (! replaceContents); // not implemented.. | |||
| if (! transform.isRotated) | |||
| fillTargetRect (transform.transformed (r.toFloat())); | |||
| else | |||
| fillRectAsPath (r); | |||
| fillRectAsPath (r); | |||
| } | |||
| } | |||
| } | |||
| @@ -2566,8 +2565,7 @@ public: | |||
| bool isVectorDevice() const override { return false; } | |||
| void setOrigin (int x, int y) override { stack->transform.setOrigin (Point<int> (x, y)); } | |||
| void addTransform (const AffineTransform& t) override { stack->transform.addTransform (t); } | |||
| float getScaleFactor() override { return stack->transform.getScaleFactor(); } | |||
| float getTargetDeviceScaleFactor() override { return stack->transform.getScaleFactor(); } | |||
| float getPhysicalPixelScaleFactor() override { return stack->transform.getPhysicalPixelScaleFactor(); } | |||
| Rectangle<int> getClipBounds() const override { return stack->getClipBounds(); } | |||
| bool isClipEmpty() const override { return stack->clip == nullptr; } | |||
| bool clipRegionIntersects (const Rectangle<int>& r) override { return stack->clipRegionIntersects (r); } | |||
| @@ -37,8 +37,7 @@ public: | |||
| void setOrigin (int x, int y) override; | |||
| void addTransform (const AffineTransform&) override; | |||
| float getScaleFactor() override; | |||
| float getTargetDeviceScaleFactor() override { return targetScale; } | |||
| float getPhysicalPixelScaleFactor() override; | |||
| bool clipToRectangle (const Rectangle<int>&) override; | |||
| bool clipToRectangleList (const RectangleList<int>&) override; | |||
| void excludeClipRectangle (const Rectangle<int>&) override; | |||
| @@ -123,10 +123,10 @@ ImagePixelData::Ptr NativeImageType::create (Image::PixelFormat format, int widt | |||
| } | |||
| //============================================================================== | |||
| CoreGraphicsContext::CoreGraphicsContext (CGContextRef context_, const float flipHeight_, const float targetScale_) | |||
| : context (context_), | |||
| flipHeight (flipHeight_), | |||
| targetScale (targetScale_), | |||
| CoreGraphicsContext::CoreGraphicsContext (CGContextRef c, const float h, const float scale) | |||
| : context (c), | |||
| flipHeight (h), | |||
| targetScale (scale), | |||
| lastClipRectIsValid (false), | |||
| state (new SavedState()) | |||
| { | |||
| @@ -167,12 +167,18 @@ void CoreGraphicsContext::addTransform (const AffineTransform& transform) | |||
| .translated (0, -flipHeight) | |||
| .scaled (1.0f, -1.0f)); | |||
| lastClipRectIsValid = false; | |||
| jassert (getPhysicalPixelScaleFactor() > 0.0f); | |||
| jassert (getPhysicalPixelScaleFactor() > 0.0f); | |||
| } | |||
| float CoreGraphicsContext::getScaleFactor() | |||
| float CoreGraphicsContext::getPhysicalPixelScaleFactor() | |||
| { | |||
| CGAffineTransform t = CGContextGetCTM (context); | |||
| return (float) juce_hypot (t.a + t.c, t.b + t.d); | |||
| const CGAffineTransform t = CGContextGetCTM (context); | |||
| return targetScale * (float) (juce_hypot (t.a, t.c) + juce_hypot (t.b, t.d)) / 2.0f; | |||
| // return targetScale * (float) (t.a + t.d) / 2.0f; | |||
| } | |||
| bool CoreGraphicsContext::clipToRectangle (const Rectangle<int>& r) | |||
| @@ -92,7 +92,7 @@ public: | |||
| currentState->transform = transform.followedBy (currentState->transform); | |||
| } | |||
| float getScaleFactor() | |||
| float getPhysicalPixelScaleFactor() | |||
| { | |||
| return currentState->transform.getScaleFactor(); | |||
| } | |||
| @@ -721,16 +721,21 @@ bool Component::isOpaque() const noexcept | |||
| class StandardCachedComponentImage : public CachedComponentImage | |||
| { | |||
| public: | |||
| StandardCachedComponentImage (Component& c) noexcept : owner (c) {} | |||
| StandardCachedComponentImage (Component& c) noexcept : owner (c), scale (1.0f) {} | |||
| void paint (Graphics& g) override | |||
| { | |||
| const Rectangle<int> bounds (owner.getLocalBounds()); | |||
| scale = g.getInternalContext().getPhysicalPixelScaleFactor(); | |||
| const Rectangle<int> compBounds (owner.getLocalBounds()); | |||
| const Rectangle<int> imageBounds (compBounds * scale); | |||
| if (image.isNull() || image.getBounds() != bounds) | |||
| if (image.isNull() || image.getBounds() != imageBounds) | |||
| { | |||
| image = Image (owner.isOpaque() ? Image::RGB : Image::ARGB, | |||
| jmax (1, bounds.getWidth()), jmax (1, bounds.getHeight()), ! owner.isOpaque()); | |||
| image = Image (owner.isOpaque() ? Image::RGB | |||
| : Image::ARGB, | |||
| jmax (1, imageBounds.getWidth()), | |||
| jmax (1, imageBounds.getHeight()), | |||
| ! owner.isOpaque()); | |||
| validArea.clear(); | |||
| } | |||
| @@ -747,28 +752,31 @@ public: | |||
| if (! owner.isOpaque()) | |||
| { | |||
| lg.setFill (Colours::transparentBlack); | |||
| lg.fillRect (bounds, true); | |||
| lg.fillRect (imageBounds, true); | |||
| lg.setFill (Colours::black); | |||
| } | |||
| lg.addTransform (AffineTransform::scale (scale)); | |||
| owner.paintEntireComponent (imG, true); | |||
| } | |||
| } | |||
| validArea = bounds; | |||
| validArea = imageBounds; | |||
| g.setColour (Colours::black.withAlpha (owner.getAlpha())); | |||
| g.drawImageAt (image, 0, 0); | |||
| g.drawImage (image, 0, 0, compBounds.getWidth(), compBounds.getHeight(), | |||
| 0, 0, imageBounds.getWidth(), imageBounds.getHeight(), false); | |||
| } | |||
| bool invalidateAll() override { validArea.clear(); return true; } | |||
| bool invalidate (const Rectangle<int>& area) override { validArea.subtract (area); return true; } | |||
| bool invalidate (const Rectangle<int>& area) override { validArea.subtract (area * scale); return true; } | |||
| void releaseResources() override { image = Image::null; } | |||
| private: | |||
| Image image; | |||
| RectangleList<int> validArea; | |||
| Component& owner; | |||
| float scale; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StandardCachedComponentImage) | |||
| }; | |||
| @@ -1936,10 +1944,12 @@ void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel) | |||
| if (effect != nullptr) | |||
| { | |||
| const float scale = g.getInternalContext().getTargetDeviceScaleFactor(); | |||
| const float scale = g.getInternalContext().getPhysicalPixelScaleFactor(); | |||
| const Rectangle<int> bounds (getLocalBounds() * scale); | |||
| Image effectImage (flags.opaqueFlag ? Image::RGB : Image::ARGB, | |||
| (int) (scale * getWidth()), (int) (scale * getHeight()), ! flags.opaqueFlag); | |||
| bounds.getWidth(), bounds.getHeight(), ! flags.opaqueFlag); | |||
| { | |||
| Graphics g2 (effectImage); | |||
| g2.addTransform (AffineTransform::scale (scale)); | |||