| @@ -69,6 +69,8 @@ public: | |||
| virtual void addTransform (const AffineTransform& transform) = 0; | |||
| virtual float getScaleFactor() = 0; | |||
| virtual float getTargetDeviceScaleFactor() { return 1.0f; } | |||
| virtual bool clipToRectangle (const Rectangle<int>& r) = 0; | |||
| virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0; | |||
| virtual void excludeClipRectangle (const Rectangle<int>& r) = 0; | |||
| @@ -51,52 +51,57 @@ void DropShadowEffect::setShadowProperties (const float newRadius, | |||
| opacity = newOpacity; | |||
| } | |||
| void DropShadowEffect::applyEffect (Image& image, Graphics& g, float alpha) | |||
| void DropShadowEffect::drawShadow (Graphics& g, const Image& srcImage, | |||
| float radius, float alpha, int offsetX, int offsetY) | |||
| { | |||
| const int w = image.getWidth(); | |||
| const int h = image.getHeight(); | |||
| const int w = srcImage.getWidth(); | |||
| const int h = srcImage.getHeight(); | |||
| Image shadowImage (Image::SingleChannel, w, h, false); | |||
| { | |||
| const Image::BitmapData srcData (image, Image::BitmapData::readOnly); | |||
| const Image::BitmapData destData (shadowImage, Image::BitmapData::readWrite); | |||
| const Image::BitmapData srcData (srcImage, Image::BitmapData::readOnly); | |||
| const Image::BitmapData destData (shadowImage, Image::BitmapData::readWrite); | |||
| const int filter = roundToInt (63.0f / radius); | |||
| const int radiusMinus1 = roundToInt ((radius - 1.0f) * 63.0f); | |||
| const int filter = roundToInt (63.0f / radius); | |||
| const int radiusMinus1 = roundToInt ((radius - 1.0f) * 63.0f); | |||
| for (int x = w; --x >= 0;) | |||
| { | |||
| int shadowAlpha = 0; | |||
| for (int x = w; --x >= 0;) | |||
| { | |||
| int shadowAlpha = 0; | |||
| const PixelARGB* src = ((const PixelARGB*) srcData.data) + x; | |||
| uint8* shadowPix = destData.data + x; | |||
| const PixelARGB* src = ((const PixelARGB*) srcData.data) + x; | |||
| uint8* shadowPix = destData.data + x; | |||
| for (int y = h; --y >= 0;) | |||
| { | |||
| shadowAlpha = ((shadowAlpha * radiusMinus1 + (src->getAlpha() << 6)) * filter) >> 12; | |||
| for (int y = h; --y >= 0;) | |||
| { | |||
| shadowAlpha = ((shadowAlpha * radiusMinus1 + (src->getAlpha() << 6)) * filter) >> 12; | |||
| *shadowPix = (uint8) shadowAlpha; | |||
| src = addBytesToPointer (src, srcData.lineStride); | |||
| shadowPix += destData.lineStride; | |||
| } | |||
| *shadowPix = (uint8) shadowAlpha; | |||
| src = addBytesToPointer (src, srcData.lineStride); | |||
| shadowPix += destData.lineStride; | |||
| } | |||
| } | |||
| for (int y = h; --y >= 0;) | |||
| for (int y = h; --y >= 0;) | |||
| { | |||
| int shadowAlpha = 0; | |||
| uint8* shadowPix = destData.getLinePointer (y); | |||
| for (int x = w; --x >= 0;) | |||
| { | |||
| int shadowAlpha = 0; | |||
| uint8* shadowPix = destData.getLinePointer (y); | |||
| for (int x = w; --x >= 0;) | |||
| { | |||
| shadowAlpha = ((shadowAlpha * radiusMinus1 + (*shadowPix << 6)) * filter) >> 12; | |||
| *shadowPix++ = (uint8) shadowAlpha; | |||
| } | |||
| shadowAlpha = ((shadowAlpha * radiusMinus1 + (*shadowPix << 6)) * filter) >> 12; | |||
| *shadowPix++ = (uint8) shadowAlpha; | |||
| } | |||
| } | |||
| g.setColour (Colours::black.withAlpha (opacity * alpha)); | |||
| g.setColour (Colours::black.withAlpha (alpha)); | |||
| g.drawImageAt (shadowImage, offsetX, offsetY, true); | |||
| } | |||
| void DropShadowEffect::applyEffect (Image& image, Graphics& g, float scaleFactor, float alpha) | |||
| { | |||
| drawShadow (g, image, radius * scaleFactor, opacity * alpha, | |||
| (int) (offsetX * scaleFactor), (int) (offsetY * scaleFactor)); | |||
| g.setOpacity (alpha); | |||
| g.drawImageAt (image, 0, 0); | |||
| @@ -75,9 +75,12 @@ public: | |||
| int newShadowOffsetY); | |||
| static void drawShadow (Graphics& g, const Image& srcImage, | |||
| float radius, float alpha, int offsetX, int offsetY); | |||
| //============================================================================== | |||
| /** @internal */ | |||
| void applyEffect (Image& sourceImage, Graphics& destContext, float alpha); | |||
| void applyEffect (Image& sourceImage, Graphics& destContext, float scaleFactor, float alpha); | |||
| private: | |||
| @@ -40,11 +40,11 @@ void GlowEffect::setGlowProperties (const float newRadius, | |||
| colour = newColour; | |||
| } | |||
| void GlowEffect::applyEffect (Image& image, Graphics& g, float alpha) | |||
| void GlowEffect::applyEffect (Image& image, Graphics& g, float scaleFactor, float alpha) | |||
| { | |||
| Image temp (image.getFormat(), image.getWidth(), image.getHeight(), true); | |||
| ImageConvolutionKernel blurKernel (roundToInt (radius * 2.0f)); | |||
| ImageConvolutionKernel blurKernel (roundToInt (radius * scaleFactor * 2.0f)); | |||
| blurKernel.createGaussianBlur (radius); | |||
| blurKernel.rescaleAllValues (radius); | |||
| @@ -63,7 +63,7 @@ public: | |||
| //============================================================================== | |||
| /** @internal */ | |||
| void applyEffect (Image& sourceImage, Graphics& destContext, float alpha); | |||
| void applyEffect (Image& sourceImage, Graphics& destContext, float scaleFactor, float alpha); | |||
| private: | |||
| //============================================================================== | |||
| @@ -53,11 +53,15 @@ public: | |||
| its paint() method. The image may or may not have an alpha | |||
| channel, depending on whether the component is opaque. | |||
| @param destContext the graphics context to use to draw the resultant image. | |||
| @param scaleFactor a scale factor that has been applied to the image - e.g. if | |||
| this is 2, then the image is actually scaled-up to twice the | |||
| original resolution | |||
| @param alpha the alpha with which to draw the resultant image to the | |||
| target context | |||
| */ | |||
| virtual void applyEffect (Image& sourceImage, | |||
| Graphics& destContext, | |||
| float scaleFactor, | |||
| float alpha) = 0; | |||
| /** Destructor. */ | |||
| @@ -30,7 +30,7 @@ | |||
| class CoreGraphicsContext : public LowLevelGraphicsContext | |||
| { | |||
| public: | |||
| CoreGraphicsContext (CGContextRef context_, const float flipHeight_); | |||
| CoreGraphicsContext (CGContextRef context_, const float flipHeight_, const float targetScale_); | |||
| ~CoreGraphicsContext(); | |||
| //============================================================================== | |||
| @@ -39,6 +39,7 @@ public: | |||
| void setOrigin (int x, int y); | |||
| void addTransform (const AffineTransform& transform); | |||
| float getScaleFactor(); | |||
| float getTargetDeviceScaleFactor() { return targetScale; } | |||
| bool clipToRectangle (const Rectangle<int>& r); | |||
| bool clipToRectangleList (const RectangleList& clipRegion); | |||
| void excludeClipRectangle (const Rectangle<int>& r); | |||
| @@ -77,6 +78,7 @@ public: | |||
| private: | |||
| CGContextRef context; | |||
| const CGFloat flipHeight; | |||
| float targetScale; | |||
| CGColorSpaceRef rgbColourSpace, greyColourSpace; | |||
| CGFunctionCallbacks gradientCallbacks; | |||
| mutable Rectangle<int> lastClipRect; | |||
| @@ -53,7 +53,7 @@ public: | |||
| LowLevelGraphicsContext* createLowLevelContext() | |||
| { | |||
| return new CoreGraphicsContext (context, height); | |||
| return new CoreGraphicsContext (context, height, 1.0f); | |||
| } | |||
| void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, Image::BitmapData::ReadWriteMode) | |||
| @@ -124,9 +124,10 @@ ImagePixelData* NativeImageType::create (Image::PixelFormat format, int width, i | |||
| } | |||
| //============================================================================== | |||
| CoreGraphicsContext::CoreGraphicsContext (CGContextRef context_, const float flipHeight_) | |||
| CoreGraphicsContext::CoreGraphicsContext (CGContextRef context_, const float flipHeight_, const float targetScale_) | |||
| : context (context_), | |||
| flipHeight (flipHeight_), | |||
| targetScale (targetScale_), | |||
| lastClipRectIsValid (false), | |||
| state (new SavedState()) | |||
| { | |||
| @@ -1946,14 +1946,20 @@ void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel) | |||
| if (effect != nullptr) | |||
| { | |||
| const float scale = g.getInternalContext()->getTargetDeviceScaleFactor(); | |||
| Image effectImage (flags.opaqueFlag ? Image::RGB : Image::ARGB, | |||
| getWidth(), getHeight(), ! flags.opaqueFlag); | |||
| (int) (scale * getWidth()), (int) (scale * getHeight()), ! flags.opaqueFlag); | |||
| { | |||
| Graphics g2 (effectImage); | |||
| g2.addTransform (AffineTransform::scale (scale, scale)); | |||
| paintComponentAndChildren (g2); | |||
| } | |||
| effect->applyEffect (effectImage, g, ignoreAlphaLevel ? 1.0f : getAlpha()); | |||
| g.saveState(); | |||
| g.addTransform (AffineTransform::scale (1.0f / scale, 1.0f / scale)); | |||
| effect->applyEffect (effectImage, g, scale, ignoreAlphaLevel ? 1.0f : getAlpha()); | |||
| g.restoreState(); | |||
| } | |||
| else if (componentTransparency > 0 && ! ignoreAlphaLevel) | |||
| { | |||
| @@ -2533,23 +2533,36 @@ const Rectangle<int> LookAndFeel::getPropertyComponentContentPosition (PropertyC | |||
| } | |||
| //============================================================================== | |||
| void LookAndFeel::drawCallOutBoxBackground (CallOutBox& box, Graphics& g, const Path& path) | |||
| void LookAndFeel::drawCallOutBoxBackground (CallOutBox& box, Graphics& g, | |||
| const Path& path, Image& cachedImage) | |||
| { | |||
| Image content (Image::ARGB, box.getWidth(), box.getHeight(), true); | |||
| if (cachedImage.isNull()) | |||
| { | |||
| Graphics g2 (content); | |||
| const int w = box.getWidth(); | |||
| const int h = box.getHeight(); | |||
| Image renderedPath (Image::ARGB, w, h, true); | |||
| g2.setColour (Colour::greyLevel (0.23f).withAlpha (0.9f)); | |||
| g2.fillPath (path); | |||
| { | |||
| Graphics g2 (renderedPath); | |||
| g2.setColour (Colour::greyLevel (0.23f).withAlpha (0.9f)); | |||
| g2.fillPath (path); | |||
| } | |||
| g2.setColour (Colours::white.withAlpha (0.8f)); | |||
| g2.strokePath (path, PathStrokeType (2.0f)); | |||
| cachedImage = Image (Image::ARGB, w, h, true); | |||
| Graphics g2 (cachedImage); | |||
| DropShadowEffect::drawShadow (g2, renderedPath, 5.0f, 0.4f, 0, 2); | |||
| } | |||
| DropShadowEffect shadow; | |||
| shadow.setShadowProperties (5.0f, 0.4f, 0, 2); | |||
| shadow.applyEffect (content, g, 1.0f); | |||
| g.setColour (Colours::black); | |||
| g.drawImageAt (cachedImage, 0, 0); | |||
| g.setColour (Colour::greyLevel (0.23f).withAlpha (0.9f)); | |||
| g.fillPath (path); | |||
| g.setColour (Colours::white.withAlpha (0.8f)); | |||
| g.strokePath (path, PathStrokeType (2.0f)); | |||
| } | |||
| @@ -611,7 +611,7 @@ public: | |||
| virtual const Rectangle<int> getPropertyComponentContentPosition (PropertyComponent& component); | |||
| //============================================================================== | |||
| virtual void drawCallOutBoxBackground (CallOutBox& box, Graphics& g, const Path& path); | |||
| virtual void drawCallOutBoxBackground (CallOutBox& box, Graphics& g, const Path& path, Image& cachedImage); | |||
| //============================================================================== | |||
| virtual void drawLevelMeter (Graphics& g, int width, int height, float level); | |||
| @@ -901,7 +901,7 @@ void UIViewComponentPeer::drawRect (CGRect r) | |||
| CGContextClearRect (cg, CGContextGetClipBoundingBox (cg)); | |||
| CGContextConcatCTM (cg, CGAffineTransformMake (1, 0, 0, -1, 0, view.bounds.size.height)); | |||
| CoreGraphicsContext g (cg, view.bounds.size.height); | |||
| CoreGraphicsContext g (cg, view.bounds.size.height, [UIScreen mainScreen].scale); | |||
| insideDrawRect = true; | |||
| handlePaint (g); | |||
| @@ -681,7 +681,15 @@ public: | |||
| #if USE_COREGRAPHICS_RENDERING | |||
| if (usingCoreGraphics) | |||
| { | |||
| CoreGraphicsContext context (cg, (float) [view frame].size.height); | |||
| float displayScale = 1.0f; | |||
| #if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7) | |||
| NSScreen* screen = [[view window] screen]; | |||
| if ([screen respondsToSelector: @selector (backingScaleFactor)]) | |||
| displayScale = screen.backingScaleFactor; | |||
| #endif | |||
| CoreGraphicsContext context (cg, (float) [view frame].size.height, displayScale); | |||
| insideDrawRect = true; | |||
| handlePaint (context); | |||
| @@ -65,15 +65,7 @@ void CallOutBox::setArrowSize (const float newSize) | |||
| void CallOutBox::paint (Graphics& g) | |||
| { | |||
| if (background.isNull()) | |||
| { | |||
| background = Image (Image::ARGB, getWidth(), getHeight(), true); | |||
| Graphics g2 (background); | |||
| getLookAndFeel().drawCallOutBoxBackground (*this, g2, outline); | |||
| } | |||
| g.setColour (Colours::black); | |||
| g.drawImageAt (background, 0, 0); | |||
| getLookAndFeel().drawCallOutBoxBackground (*this, g, outline, background); | |||
| } | |||
| void CallOutBox::resized() | |||