@@ -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() | |||