| @@ -2168,42 +2168,6 @@ | |||
| <Filter | |||
| Name="graphics" | |||
| > | |||
| <Filter | |||
| Name="brushes" | |||
| > | |||
| <File | |||
| RelativePath="..\..\..\src\gui\graphics\brushes\juce_Brush.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\gui\graphics\brushes\juce_Brush.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\gui\graphics\brushes\juce_GradientBrush.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\gui\graphics\brushes\juce_GradientBrush.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\gui\graphics\brushes\juce_ImageBrush.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\gui\graphics\brushes\juce_ImageBrush.h" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\gui\graphics\brushes\juce_SolidColourBrush.cpp" | |||
| > | |||
| </File> | |||
| <File | |||
| RelativePath="..\..\..\src\gui\graphics\brushes\juce_SolidColourBrush.h" | |||
| > | |||
| </File> | |||
| </Filter> | |||
| <Filter | |||
| Name="colour" | |||
| > | |||
| @@ -130,20 +130,18 @@ public: | |||
| } | |||
| else if (type == 2 || type == 3) | |||
| { | |||
| GradientBrush gb (Colours::blue.withAlpha ((float) opacitySlider->getValue()), | |||
| getWidth() * 0.5f, getHeight() * 0.5f, | |||
| Colours::red.withAlpha ((float) opacitySlider->getValue()), | |||
| getWidth() * 0.6f, getHeight() * 0.7f, | |||
| type == 3); | |||
| ColourGradient gradient (Colours::blue.withAlpha ((float) opacitySlider->getValue()), | |||
| getWidth() * 0.5f, getHeight() * 0.5f, | |||
| Colours::red.withAlpha ((float) opacitySlider->getValue()), | |||
| getWidth() * 0.6f, getHeight() * 0.7f, | |||
| type == 3); | |||
| g.setBrush (&gb); | |||
| g.setGradientFill (gradient); | |||
| g.fillPath (shape, getTransform()); | |||
| } | |||
| else if (type == 8) | |||
| { | |||
| ImageBrush ib (image, 100, 100, (float) opacitySlider->getValue()); | |||
| g.setBrush (&ib); | |||
| g.setTiledImageFill (*image, 100, 100, (float) opacitySlider->getValue()); | |||
| g.fillPath (shape, getTransform()); | |||
| } | |||
| else if (type == 4 || type == 5) | |||
| @@ -179,16 +177,16 @@ public: | |||
| } | |||
| else if (type == 7) | |||
| { | |||
| GradientBrush gb (Colours::blue.withAlpha ((float) opacitySlider->getValue()), | |||
| getWidth() * 0.5f, getHeight() * 0.5f, | |||
| Colours::red.withAlpha ((float) opacitySlider->getValue()), | |||
| getWidth() * 0.6f, getHeight() * 0.7f, | |||
| false); | |||
| g.setBrush (&gb); | |||
| if (image != 0) | |||
| { | |||
| ColourGradient gradient (Colours::blue.withAlpha ((float) opacitySlider->getValue()), | |||
| getWidth() * 0.5f, getHeight() * 0.5f, | |||
| Colours::red.withAlpha ((float) opacitySlider->getValue()), | |||
| getWidth() * 0.6f, getHeight() * 0.7f, | |||
| false); | |||
| g.setGradientFill (gradient); | |||
| g.drawImageTransformed (image, | |||
| 0, 0, image->getWidth(), image->getHeight(), | |||
| AffineTransform::translation (-0.5f * image->getWidth(), -0.5f * image->getHeight()) | |||
| @@ -198,11 +196,10 @@ public: | |||
| } | |||
| else if (type == 9) | |||
| { | |||
| ImageBrush ib (image, 100, 100, (float) opacitySlider->getValue()); | |||
| g.setBrush (&ib); | |||
| if (image != 0) | |||
| { | |||
| g.setTiledImageFill (*image, 100, 100, (float) opacitySlider->getValue()); | |||
| g.drawImageTransformed (image, | |||
| 0, 0, image->getWidth(), image->getHeight(), | |||
| AffineTransform::translation (-0.5f * image->getWidth(), | |||
| @@ -110,15 +110,14 @@ void FillType::reset() | |||
| } | |||
| //============================================================================== | |||
| Brush* FillType::createBrush (JucerDocument* const document, | |||
| const Rectangle& parentArea) | |||
| void FillType::setFillType (Graphics& g, JucerDocument* const document, const Rectangle& parentArea) | |||
| { | |||
| if (mode == solidColour) | |||
| { | |||
| ImageCache::release (image); | |||
| image = 0; | |||
| return new SolidColourBrush (colour); | |||
| g.setColour (colour); | |||
| } | |||
| else if (mode == imageBrush) | |||
| { | |||
| @@ -126,7 +125,7 @@ Brush* FillType::createBrush (JucerDocument* const document, | |||
| Rectangle r (imageAnchor.getRectangle (parentArea, document->getComponentLayout())); | |||
| return new ImageBrush (image, r.getX(), r.getY(), (float) imageOpacity); | |||
| g.setTiledImageFill (*image, r.getX(), r.getY(), (float) imageOpacity); | |||
| } | |||
| else | |||
| { | |||
| @@ -136,9 +135,9 @@ Brush* FillType::createBrush (JucerDocument* const document, | |||
| Rectangle r1 (gradPos1.getRectangle (parentArea, document->getComponentLayout())); | |||
| Rectangle r2 (gradPos2.getRectangle (parentArea, document->getComponentLayout())); | |||
| return new GradientBrush (gradCol1, (float) r1.getX(), (float) r1.getY(), | |||
| gradCol2, (float) r2.getX(), (float) r2.getY(), | |||
| mode == radialGradient); | |||
| g.setGradientFill (ColourGradient (gradCol1, (float) r1.getX(), (float) r1.getY(), | |||
| gradCol2, (float) r2.getX(), (float) r2.getY(), | |||
| mode == radialGradient)); | |||
| } | |||
| } | |||
| @@ -46,7 +46,7 @@ public: | |||
| bool operator!= (const FillType& other) const throw(); | |||
| //============================================================================== | |||
| Brush* createBrush (JucerDocument* const document, const Rectangle& parentArea); | |||
| void setFillType (Graphics& g, JucerDocument* const document, const Rectangle& parentArea); | |||
| void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) const; | |||
| @@ -45,23 +45,17 @@ public: | |||
| void draw (Graphics& g, const ComponentLayout* layout, const Rectangle& parentArea) | |||
| { | |||
| Brush* const brush = fillType.createBrush (getDocument(), parentArea); | |||
| g.setBrush (brush); | |||
| fillType.setFillType (g, getDocument(), parentArea); | |||
| Rectangle r (position.getRectangle (parentArea, layout)); | |||
| g.fillEllipse ((float) r.getX(), (float) r.getY(), (float) r.getWidth(), (float) r.getHeight()); | |||
| delete brush; | |||
| if (isStrokePresent) | |||
| { | |||
| Brush* const brush = strokeType.fill.createBrush (getDocument(), parentArea); | |||
| g.setBrush (brush); | |||
| strokeType.fill.setFillType (g, getDocument(), parentArea); | |||
| g.drawEllipse ((float) r.getX(), (float) r.getY(), (float) r.getWidth(), (float) r.getHeight(), | |||
| getStrokeType().stroke.getStrokeThickness()); | |||
| delete brush; | |||
| } | |||
| } | |||
| @@ -242,24 +242,16 @@ static void drawArrow (Graphics& g, float x1, float y1, float x2, float y2) | |||
| void PaintElementPath::draw (Graphics& g, const ComponentLayout* layout, const Rectangle& parentArea) | |||
| { | |||
| Brush* const brush = fillType.createBrush (getDocument(), parentArea); | |||
| g.setBrush (brush); | |||
| updateStoredPath (layout, parentArea); | |||
| path.setUsingNonZeroWinding (nonZeroWinding); | |||
| g.fillPath (path); | |||
| delete brush; | |||
| fillType.setFillType (g, getDocument(), parentArea); | |||
| g.fillPath (path); | |||
| if (isStrokePresent) | |||
| { | |||
| Brush* const brush = strokeType.fill.createBrush (getDocument(), parentArea); | |||
| g.setBrush (brush); | |||
| strokeType.fill.setFillType (g, getDocument(), parentArea); | |||
| g.strokePath (path, getStrokeType().stroke); | |||
| delete brush; | |||
| } | |||
| } | |||
| @@ -60,23 +60,17 @@ public: | |||
| Component parentComponent; | |||
| parentComponent.setBounds (parentArea); | |||
| Brush* const brush = fillType.createBrush (getDocument(), parentArea); | |||
| g.setBrush (brush); | |||
| fillType.setFillType (g, getDocument(), parentArea); | |||
| const Rectangle r (position.getRectangle (parentArea, layout)); | |||
| g.fillRect (r); | |||
| delete brush; | |||
| if (isStrokePresent) | |||
| { | |||
| Brush* const brush = strokeType.fill.createBrush (getDocument(), parentArea); | |||
| g.setBrush (brush); | |||
| strokeType.fill.setFillType (g, getDocument(), parentArea); | |||
| g.drawRect (r.getX(), r.getY(), r.getWidth(), r.getHeight(), | |||
| roundDoubleToInt (getStrokeType().stroke.getStrokeThickness())); | |||
| delete brush; | |||
| } | |||
| } | |||
| @@ -47,25 +47,18 @@ public: | |||
| //============================================================================== | |||
| void draw (Graphics& g, const ComponentLayout* layout, const Rectangle& parentArea) | |||
| { | |||
| Brush* const brush = fillType.createBrush (getDocument(), parentArea); | |||
| g.setBrush (brush); | |||
| double x, y, w, h; | |||
| position.getRectangleDouble (x, y, w, h, parentArea, layout); | |||
| fillType.setFillType (g, getDocument(), parentArea); | |||
| g.fillRoundedRectangle ((float) x, (float) y, (float) w, (float) h, (float) cornerSize); | |||
| delete brush; | |||
| if (isStrokePresent) | |||
| { | |||
| Brush* const brush = strokeType.fill.createBrush (getDocument(), parentArea); | |||
| g.setBrush (brush); | |||
| strokeType.fill.setFillType (g, getDocument(), parentArea); | |||
| g.drawRoundedRectangle ((float) x, (float) y, (float) w, (float) h, (float) cornerSize, | |||
| getStrokeType().stroke.getStrokeThickness()); | |||
| delete brush; | |||
| } | |||
| } | |||
| @@ -57,8 +57,7 @@ public: | |||
| //============================================================================== | |||
| void draw (Graphics& g, const ComponentLayout* layout, const Rectangle& parentArea) | |||
| { | |||
| Brush* const brush = fillType.createBrush (getDocument(), parentArea); | |||
| g.setBrush (brush); | |||
| fillType.setFillType (g, getDocument(), parentArea); | |||
| font = FontPropertyComponent::applyNameToFont (typefaceName, font); | |||
| g.setFont (font); | |||
| @@ -67,8 +66,6 @@ public: | |||
| g.drawText (replaceStringTranslations (text, owner->getDocument()), | |||
| r.getX(), r.getY(), r.getWidth(), r.getHeight(), | |||
| justification, true); | |||
| delete brush; | |||
| } | |||
| void getEditableProperties (Array <PropertyComponent*>& properties) | |||
| @@ -1,70 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-9 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../core/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "juce_Brush.h" | |||
| #include "../contexts/juce_Graphics.h" | |||
| #include "../contexts/juce_EdgeTable.h" | |||
| //============================================================================== | |||
| Brush::Brush() throw() | |||
| { | |||
| } | |||
| Brush::~Brush() throw() | |||
| { | |||
| } | |||
| void Brush::paintVerticalLine (LowLevelGraphicsContext& context, | |||
| int x, float y1, float y2) throw() | |||
| { | |||
| Path p; | |||
| p.addRectangle ((float) x, y1, 1.0f, y2 - y1); | |||
| paintPath (context, p, AffineTransform::identity); | |||
| } | |||
| void Brush::paintHorizontalLine (LowLevelGraphicsContext& context, | |||
| int y, float x1, float x2) throw() | |||
| { | |||
| Path p; | |||
| p.addRectangle (x1, (float) y, x2 - x1, 1.0f); | |||
| paintPath (context, p, AffineTransform::identity); | |||
| } | |||
| void Brush::paintLine (LowLevelGraphicsContext& context, | |||
| float x1, float y1, float x2, float y2) throw() | |||
| { | |||
| Path p; | |||
| p.addLineSegment (x1, y1, x2, y2, 1.0f); | |||
| paintPath (context, p, AffineTransform::identity); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -1,100 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-9 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_BRUSH_JUCEHEADER__ | |||
| #define __JUCE_BRUSH_JUCEHEADER__ | |||
| class Path; | |||
| class AffineTransform; | |||
| class LowLevelGraphicsContext; | |||
| class Image; | |||
| class Graphics; | |||
| //============================================================================== | |||
| /** | |||
| A brush is used to fill areas with colours, patterns, or images. | |||
| The Graphics class has an idea of a current brush which it uses to render | |||
| shapes, rectangles, lines, text, etc. | |||
| This is the base class - there are subclasses for useful types of fill pattern, | |||
| and applications can define their own brushes too. | |||
| @see Graphics::setBrush, SolidColourBrush, GradientBrush, ImageBrush | |||
| */ | |||
| class JUCE_API Brush | |||
| { | |||
| protected: | |||
| //============================================================================== | |||
| /** Creates a Brush. | |||
| (Nothing much happens in the base class). | |||
| */ | |||
| Brush() throw(); | |||
| public: | |||
| /** Destructor. */ | |||
| virtual ~Brush() throw(); | |||
| /** Creates a copy of whatever class of Brush this is. */ | |||
| virtual Brush* createCopy() const throw() = 0; | |||
| /** Does whatever is relevent to transform the geometry of this brush. */ | |||
| virtual void applyTransform (const AffineTransform& transform) throw() = 0; | |||
| /** Does whatever is relevent to change the opacity of this brush. */ | |||
| virtual void multiplyOpacity (const float multiple) throw() = 0; | |||
| /** Must return true if this brush won't draw any pixels. */ | |||
| virtual bool isInvisible() const throw() = 0; | |||
| //============================================================================== | |||
| virtual void paintPath (LowLevelGraphicsContext& context, | |||
| const Path& path, const AffineTransform& transform) throw() = 0; | |||
| virtual void paintRectangle (LowLevelGraphicsContext& context, | |||
| int x, int y, int w, int h) throw() = 0; | |||
| virtual void paintAlphaChannel (LowLevelGraphicsContext& context, | |||
| const Image& alphaChannelImage, int imageX, int imageY, | |||
| int x, int y, int w, int h) throw() = 0; | |||
| virtual void paintVerticalLine (LowLevelGraphicsContext& context, | |||
| int x, float y1, float y2) throw(); | |||
| virtual void paintHorizontalLine (LowLevelGraphicsContext& context, | |||
| int y, float x1, float x2) throw(); | |||
| virtual void paintLine (LowLevelGraphicsContext& context, | |||
| float x1, float y1, float x2, float y2) throw(); | |||
| private: | |||
| //============================================================================== | |||
| Brush (const Brush&); | |||
| const Brush& operator= (const Brush&); | |||
| }; | |||
| #endif // __JUCE_BRUSH_JUCEHEADER__ | |||
| @@ -1,108 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-9 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../core/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "juce_GradientBrush.h" | |||
| #include "../contexts/juce_LowLevelGraphicsContext.h" | |||
| //============================================================================== | |||
| GradientBrush::GradientBrush (const Colour& colour1, | |||
| const float x1, | |||
| const float y1, | |||
| const Colour& colour2, | |||
| const float x2, | |||
| const float y2, | |||
| const bool isRadial) throw() | |||
| : gradient (colour1, x1, y1, | |||
| colour2, x2, y2, | |||
| isRadial) | |||
| { | |||
| } | |||
| GradientBrush::GradientBrush (const ColourGradient& gradient_) throw() | |||
| : gradient (gradient_) | |||
| { | |||
| } | |||
| GradientBrush::~GradientBrush() throw() | |||
| { | |||
| } | |||
| Brush* GradientBrush::createCopy() const throw() | |||
| { | |||
| return new GradientBrush (gradient); | |||
| } | |||
| void GradientBrush::applyTransform (const AffineTransform& transform) throw() | |||
| { | |||
| gradient.transform = gradient.transform.followedBy (transform); | |||
| } | |||
| void GradientBrush::multiplyOpacity (const float multiple) throw() | |||
| { | |||
| gradient.multiplyOpacity (multiple); | |||
| } | |||
| bool GradientBrush::isInvisible() const throw() | |||
| { | |||
| return gradient.isInvisible(); | |||
| } | |||
| //============================================================================== | |||
| void GradientBrush::paintPath (LowLevelGraphicsContext& context, | |||
| const Path& path, const AffineTransform& transform) throw() | |||
| { | |||
| context.setGradient (gradient); | |||
| context.fillPath (path, transform); | |||
| } | |||
| void GradientBrush::paintRectangle (LowLevelGraphicsContext& context, | |||
| int x, int y, int w, int h) throw() | |||
| { | |||
| context.setGradient (gradient); | |||
| context.fillRect (x, y, w, h, false); | |||
| } | |||
| void GradientBrush::paintAlphaChannel (LowLevelGraphicsContext& context, | |||
| const Image& alphaChannelImage, int imageX, int imageY, | |||
| int x, int y, int w, int h) throw() | |||
| { | |||
| context.saveState(); | |||
| if (context.reduceClipRegion (x, y, w, h)) | |||
| { | |||
| context.setGradient (gradient); | |||
| context.fillAlphaChannel (alphaChannelImage, imageX, imageY); | |||
| } | |||
| context.restoreState(); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -1,113 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-9 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_GRADIENTBRUSH_JUCEHEADER__ | |||
| #define __JUCE_GRADIENTBRUSH_JUCEHEADER__ | |||
| #include "juce_Brush.h" | |||
| #include "../colour/juce_ColourGradient.h" | |||
| //============================================================================== | |||
| /** | |||
| A Brush that fills areas with a colour gradient. | |||
| The gradient can either be linear or circular. | |||
| @see Brush, Graphics::setBrush, SolidColourBrush, ImageBrush | |||
| */ | |||
| class JUCE_API GradientBrush : public Brush | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Creates a gradient brush, ready for use in Graphics::setBrush(). | |||
| (x1, y1) is the location relative to the origin of the Graphics context, | |||
| at which the colour should be colour1. Likewise for (x2, y2) and colour2. | |||
| If isRadial is true, the colours form a circular gradient with (x1, y1) at | |||
| its centre. | |||
| The alpha transparencies of the colours are used, so the brush | |||
| need not be completely opaque. Note that this means that if you | |||
| blend from transparent to a solid colour, the RGB of the transparent | |||
| colour will become visible in parts of the gradient. e.g. blending | |||
| from Colour::transparentBlack to Colours::white will produce a | |||
| grey colour, but Colour::transparentWhite to Colours::white will be | |||
| white all the way across. | |||
| @see ColourGradient | |||
| */ | |||
| GradientBrush (const Colour& colour1, | |||
| const float x1, | |||
| const float y1, | |||
| const Colour& colour2, | |||
| const float x2, | |||
| const float y2, | |||
| const bool isRadial) throw(); | |||
| /** Creates a gradient brush from a ColourGradient object. | |||
| */ | |||
| GradientBrush (const ColourGradient& gradient) throw(); | |||
| /** Destructor. */ | |||
| ~GradientBrush() throw(); | |||
| //============================================================================== | |||
| /** Returns the current gradient information */ | |||
| const ColourGradient& getGradient() const throw() { return gradient; } | |||
| //============================================================================== | |||
| Brush* createCopy() const throw(); | |||
| void applyTransform (const AffineTransform& transform) throw(); | |||
| void multiplyOpacity (const float multiple) throw(); | |||
| bool isInvisible() const throw(); | |||
| void paintPath (LowLevelGraphicsContext& context, | |||
| const Path& path, const AffineTransform& transform) throw(); | |||
| void paintRectangle (LowLevelGraphicsContext& context, | |||
| int x, int y, int w, int h) throw(); | |||
| void paintAlphaChannel (LowLevelGraphicsContext& context, | |||
| const Image& alphaChannelImage, int imageX, int imageY, | |||
| int x, int y, int w, int h) throw(); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| protected: | |||
| ColourGradient gradient; | |||
| private: | |||
| GradientBrush (const GradientBrush&); | |||
| const GradientBrush& operator= (const GradientBrush&); | |||
| }; | |||
| #endif // __JUCE_GRADIENTBRUSH_JUCEHEADER__ | |||
| @@ -1,224 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-9 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../core/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "juce_ImageBrush.h" | |||
| #include "../contexts/juce_LowLevelGraphicsContext.h" | |||
| //============================================================================== | |||
| ImageBrush::ImageBrush (Image* const image_, | |||
| const int anchorX_, | |||
| const int anchorY_, | |||
| const float opacity_) throw() | |||
| : image (image_), | |||
| anchorX (anchorX_), | |||
| anchorY (anchorY_), | |||
| opacity (opacity_) | |||
| { | |||
| jassert (image != 0); // not much point creating a brush without an image, is there? | |||
| if (image != 0) | |||
| { | |||
| if (image->getWidth() == 0 || image->getHeight() == 0) | |||
| { | |||
| jassertfalse // you've passed in an empty image - not exactly brilliant for tiling. | |||
| image = 0; | |||
| } | |||
| } | |||
| } | |||
| ImageBrush::~ImageBrush() throw() | |||
| { | |||
| } | |||
| Brush* ImageBrush::createCopy() const throw() | |||
| { | |||
| return new ImageBrush (image, anchorX, anchorY, opacity); | |||
| } | |||
| void ImageBrush::multiplyOpacity (const float multiple) throw() | |||
| { | |||
| opacity *= multiple; | |||
| } | |||
| bool ImageBrush::isInvisible() const throw() | |||
| { | |||
| return opacity == 0.0f; | |||
| } | |||
| void ImageBrush::applyTransform (const AffineTransform& /*transform*/) throw() | |||
| { | |||
| //xxx should probably be smarter and warp the image | |||
| } | |||
| void ImageBrush::getStartXY (int& x, int& y) const throw() | |||
| { | |||
| x -= anchorX; | |||
| y -= anchorY; | |||
| const int iw = image->getWidth(); | |||
| const int ih = image->getHeight(); | |||
| if (x < 0) | |||
| x = ((x / iw) - 1) * iw; | |||
| else | |||
| x = (x / iw) * iw; | |||
| if (y < 0) | |||
| y = ((y / ih) - 1) * ih; | |||
| else | |||
| y = (y / ih) * ih; | |||
| x += anchorX; | |||
| y += anchorY; | |||
| } | |||
| //============================================================================== | |||
| void ImageBrush::paintRectangle (LowLevelGraphicsContext& context, | |||
| int x, int y, int w, int h) throw() | |||
| { | |||
| context.saveState(); | |||
| if (image != 0 && context.reduceClipRegion (x, y, w, h)) | |||
| { | |||
| const int right = x + w; | |||
| const int bottom = y + h; | |||
| const int iw = image->getWidth(); | |||
| const int ih = image->getHeight(); | |||
| int startX = x; | |||
| getStartXY (startX, y); | |||
| while (y < bottom) | |||
| { | |||
| x = startX; | |||
| while (x < right) | |||
| { | |||
| context.setOpacity (opacity); | |||
| context.blendImage (*image, x, y, iw, ih, 0, 0); | |||
| x += iw; | |||
| } | |||
| y += ih; | |||
| } | |||
| } | |||
| context.restoreState(); | |||
| } | |||
| void ImageBrush::paintPath (LowLevelGraphicsContext& context, | |||
| const Path& path, const AffineTransform& transform) throw() | |||
| { | |||
| if (image != 0) | |||
| { | |||
| Rectangle clip (context.getClipBounds()); | |||
| context.setOpacity (opacity); | |||
| { | |||
| float x, y, w, h; | |||
| path.getBoundsTransformed (transform, x, y, w, h); | |||
| clip = clip.getIntersection (Rectangle ((int) floorf (x), | |||
| (int) floorf (y), | |||
| 2 + (int) floorf (w), | |||
| 2 + (int) floorf (h))); | |||
| } | |||
| int x = clip.getX(); | |||
| int y = clip.getY(); | |||
| const int right = clip.getRight(); | |||
| const int bottom = clip.getBottom(); | |||
| const int iw = image->getWidth(); | |||
| const int ih = image->getHeight(); | |||
| int startX = x; | |||
| getStartXY (startX, y); | |||
| while (y < bottom) | |||
| { | |||
| x = startX; | |||
| while (x < right) | |||
| { | |||
| context.fillPathWithImage (path, transform, *image, x, y); | |||
| x += iw; | |||
| } | |||
| y += ih; | |||
| } | |||
| } | |||
| } | |||
| void ImageBrush::paintAlphaChannel (LowLevelGraphicsContext& context, | |||
| const Image& alphaChannelImage, int imageX, int imageY, | |||
| int x, int y, int w, int h) throw() | |||
| { | |||
| context.saveState(); | |||
| if (image != 0 && context.reduceClipRegion (x, y, w, h)) | |||
| { | |||
| context.setOpacity (opacity); | |||
| const Rectangle clip (context.getClipBounds()); | |||
| x = clip.getX(); | |||
| y = clip.getY(); | |||
| const int right = clip.getRight(); | |||
| const int bottom = clip.getBottom(); | |||
| const int iw = image->getWidth(); | |||
| const int ih = image->getHeight(); | |||
| int startX = x; | |||
| getStartXY (startX, y); | |||
| while (y < bottom) | |||
| { | |||
| x = startX; | |||
| while (x < right) | |||
| { | |||
| context.fillAlphaChannelWithImage (alphaChannelImage, | |||
| imageX, imageY, *image, | |||
| x, y); | |||
| x += iw; | |||
| } | |||
| y += ih; | |||
| } | |||
| } | |||
| context.restoreState(); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -1,104 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-9 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_IMAGEBRUSH_JUCEHEADER__ | |||
| #define __JUCE_IMAGEBRUSH_JUCEHEADER__ | |||
| #include "juce_Brush.h" | |||
| #include "../imaging/juce_Image.h" | |||
| //============================================================================== | |||
| /** | |||
| A Brush that fills areas with tiled repetitions of an image. | |||
| @see Brush, Graphics::setBrush, SolidColourBrush, GradientBrush | |||
| */ | |||
| class JUCE_API ImageBrush : public Brush | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /* Creates an image brush, ready for use in Graphics::setBrush(). | |||
| (x, y) is an anchor point for the top-left of the image | |||
| A reference to the image passed in will be kept, so don't delete | |||
| it within the lifetime of this object | |||
| */ | |||
| ImageBrush (Image* const image, | |||
| const int anchorX, | |||
| const int anchorY, | |||
| const float opacity) throw(); | |||
| /** Destructor. */ | |||
| ~ImageBrush() throw(); | |||
| //============================================================================== | |||
| /** Returns the image currently being used. */ | |||
| Image* getImage() const throw() { return image; } | |||
| /** Returns the current anchor X position. */ | |||
| int getAnchorX() const throw() { return anchorX; } | |||
| /** Returns the current anchor Y position. */ | |||
| int getAnchorY() const throw() { return anchorY; } | |||
| /** Returns the current opacity. */ | |||
| float getOpacity() const throw() { return opacity; } | |||
| //============================================================================== | |||
| Brush* createCopy() const throw(); | |||
| void applyTransform (const AffineTransform& transform) throw(); | |||
| void multiplyOpacity (const float multiple) throw(); | |||
| bool isInvisible() const throw(); | |||
| void paintPath (LowLevelGraphicsContext& context, | |||
| const Path& path, const AffineTransform& transform) throw(); | |||
| void paintRectangle (LowLevelGraphicsContext& context, | |||
| int x, int y, int w, int h) throw(); | |||
| void paintAlphaChannel (LowLevelGraphicsContext& context, | |||
| const Image& alphaChannelImage, int imageX, int imageY, | |||
| int x, int y, int w, int h) throw(); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| protected: | |||
| Image* image; | |||
| int anchorX, anchorY; | |||
| float opacity; | |||
| private: | |||
| ImageBrush (const ImageBrush&); | |||
| const ImageBrush& operator= (const ImageBrush&); | |||
| void getStartXY (int& x, int& y) const throw(); | |||
| }; | |||
| #endif // __JUCE_IMAGEBRUSH_JUCEHEADER__ | |||
| @@ -1,123 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-9 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../../../core/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "juce_SolidColourBrush.h" | |||
| #include "../contexts/juce_LowLevelGraphicsContext.h" | |||
| //============================================================================== | |||
| SolidColourBrush::SolidColourBrush() throw() | |||
| : colour (0xff000000) | |||
| { | |||
| } | |||
| SolidColourBrush::SolidColourBrush (const Colour& colour_) throw() | |||
| : colour (colour_) | |||
| { | |||
| } | |||
| SolidColourBrush::~SolidColourBrush() throw() | |||
| { | |||
| } | |||
| Brush* SolidColourBrush::createCopy() const throw() | |||
| { | |||
| return new SolidColourBrush (colour); | |||
| } | |||
| void SolidColourBrush::applyTransform (const AffineTransform& /*transform*/) throw() | |||
| { | |||
| } | |||
| void SolidColourBrush::multiplyOpacity (const float multiple) throw() | |||
| { | |||
| colour = colour.withMultipliedAlpha (multiple); | |||
| } | |||
| bool SolidColourBrush::isInvisible() const throw() | |||
| { | |||
| return colour.isTransparent(); | |||
| } | |||
| void SolidColourBrush::paintPath (LowLevelGraphicsContext& context, | |||
| const Path& path, const AffineTransform& transform) throw() | |||
| { | |||
| context.setColour (colour); | |||
| context.fillPath (path, transform); | |||
| } | |||
| void SolidColourBrush::paintRectangle (LowLevelGraphicsContext& context, | |||
| int x, int y, int w, int h) throw() | |||
| { | |||
| context.setColour (colour); | |||
| context.fillRect (x, y, w, h, false); | |||
| } | |||
| void SolidColourBrush::paintAlphaChannel (LowLevelGraphicsContext& context, | |||
| const Image& alphaChannelImage, int imageX, int imageY, | |||
| int x, int y, int w, int h) throw() | |||
| { | |||
| if (! colour.isTransparent()) | |||
| { | |||
| context.saveState(); | |||
| if (context.reduceClipRegion (x, y, w, h)) | |||
| { | |||
| context.setColour (colour); | |||
| context.fillAlphaChannel (alphaChannelImage, imageX, imageY); | |||
| } | |||
| context.restoreState(); | |||
| } | |||
| } | |||
| void SolidColourBrush::paintVerticalLine (LowLevelGraphicsContext& context, | |||
| int x, float y1, float y2) throw() | |||
| { | |||
| context.setColour (colour); | |||
| context.drawVerticalLine (x, y1, y2); | |||
| } | |||
| void SolidColourBrush::paintHorizontalLine (LowLevelGraphicsContext& context, | |||
| int y, float x1, float x2) throw() | |||
| { | |||
| context.setColour (colour); | |||
| context.drawHorizontalLine (y, x1, x2); | |||
| } | |||
| void SolidColourBrush::paintLine (LowLevelGraphicsContext& context, | |||
| float x1, float y1, float x2, float y2) throw() | |||
| { | |||
| context.setColour (colour); | |||
| context.drawLine (x1, y1, x2, y2); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -1,108 +0,0 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-9 by Raw Material Software Ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||
| Public License (Version 2), as published by the Free Software Foundation. | |||
| A copy of the license is included in the JUCE distribution, or can be found | |||
| online at www.gnu.org/licenses. | |||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||
| ------------------------------------------------------------------------------ | |||
| To release a closed-source product which uses JUCE, commercial licenses are | |||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||
| ============================================================================== | |||
| */ | |||
| #ifndef __JUCE_SOLIDCOLOURBRUSH_JUCEHEADER__ | |||
| #define __JUCE_SOLIDCOLOURBRUSH_JUCEHEADER__ | |||
| #include "juce_Brush.h" | |||
| #include "../colour/juce_Colour.h" | |||
| //============================================================================== | |||
| /** | |||
| A Brush that fills its area with a solid (or semi-transparent) colour. | |||
| An application won't normally need to use this class directly, as drawing | |||
| with solid colours is taken care of automatically by the Graphics class | |||
| (it actually uses one of these brushes internally when you set the colour | |||
| with the Graphics::setColour() method). | |||
| @see Brush, Graphics::setBrush, GradientBrush, ImageBrush | |||
| */ | |||
| class JUCE_API SolidColourBrush : public Brush | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| /** Creates a SolidColourBrush to draw with the given colour. | |||
| The colour can be changed later with the setColour() method. | |||
| */ | |||
| SolidColourBrush (const Colour& colour) throw(); | |||
| /** Creates a SolidColourBrush set to black. | |||
| The colour can be changed later with the setColour() method. | |||
| */ | |||
| SolidColourBrush() throw(); | |||
| /** Destructor. */ | |||
| ~SolidColourBrush() throw(); | |||
| //============================================================================== | |||
| /** Returns the colour currently being used. */ | |||
| const Colour& getColour() const throw() { return colour; } | |||
| /** Sets the colour to use for drawing. */ | |||
| void setColour (const Colour& newColour) throw() { colour = newColour; } | |||
| //============================================================================== | |||
| Brush* createCopy() const throw(); | |||
| void applyTransform (const AffineTransform& transform) throw(); | |||
| bool isInvisible() const throw(); | |||
| void multiplyOpacity (const float multiple) throw(); | |||
| void paintPath (LowLevelGraphicsContext& context, | |||
| const Path& path, const AffineTransform& transform) throw(); | |||
| void paintRectangle (LowLevelGraphicsContext& context, | |||
| int x, int y, int w, int h) throw(); | |||
| void paintAlphaChannel (LowLevelGraphicsContext& context, | |||
| const Image& alphaChannelImage, int imageX, int imageY, | |||
| int x, int y, int w, int h) throw(); | |||
| void paintVerticalLine (LowLevelGraphicsContext& context, | |||
| int x, float y1, float y2) throw(); | |||
| void paintHorizontalLine (LowLevelGraphicsContext& context, | |||
| int y, float x1, float x2) throw(); | |||
| void paintLine (LowLevelGraphicsContext& context, | |||
| float x1, float y1, float x2, float y2) throw(); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| Colour colour; | |||
| SolidColourBrush (const SolidColourBrush&); | |||
| const SolidColourBrush& operator= (const SolidColourBrush&); | |||
| }; | |||
| #endif // __JUCE_SOLIDCOLOURBRUSH_JUCEHEADER__ | |||
| @@ -301,12 +301,18 @@ const Colour Colour::overlaidWith (const Colour& src) const throw() | |||
| const Colour Colour::interpolatedWith (const Colour& other, float proportionOfOther) const throw() | |||
| { | |||
| const int amount = jlimit (0, 256, (int) (proportionOfOther * 256.0f)); | |||
| if (proportionOfOther <= 0) | |||
| return *this; | |||
| if (proportionOfOther >= 1.0f) | |||
| return other; | |||
| PixelARGB c1 (getPixelARGB()); | |||
| const PixelARGB c2 (other.getPixelARGB()); | |||
| c1.tween (c2, roundFloatToInt (proportionOfOther * 255.0f)); | |||
| c1.unpremultiply(); | |||
| return Colour ((uint8) (getRed() + (((other.getRed() - getRed()) * amount) >> 8)), | |||
| (uint8) (getGreen() + (((other.getGreen() - getGreen()) * amount) >> 8)), | |||
| (uint8) (getBlue() + (((other.getBlue() - getBlue()) * amount) >> 8)), | |||
| (uint8) (getAlpha() + (((other.getAlpha() - getAlpha()) * amount) >> 8))); | |||
| return Colour (c1.getARGB()); | |||
| } | |||
| //============================================================================== | |||
| @@ -49,7 +49,8 @@ EdgeTable::EdgeTable (const Rectangle& bounds_, | |||
| const Path& path, const AffineTransform& transform) throw() | |||
| : bounds (bounds_), | |||
| maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine), | |||
| lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1) | |||
| lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1), | |||
| needToCheckEmptinesss (true) | |||
| { | |||
| table = (int*) juce_malloc ((bounds.getHeight() + 1) * lineStrideElements * sizeof (int)); | |||
| int* t = table; | |||
| @@ -167,7 +168,8 @@ EdgeTable::EdgeTable (const Rectangle& bounds_, | |||
| EdgeTable::EdgeTable (const Rectangle& rectangleToAdd) throw() | |||
| : bounds (rectangleToAdd), | |||
| maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine), | |||
| lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1) | |||
| lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1), | |||
| needToCheckEmptinesss (true) | |||
| { | |||
| table = (int*) juce_malloc (jmax (1, bounds.getHeight()) * lineStrideElements * sizeof (int)); | |||
| *table = 0; | |||
| @@ -190,7 +192,8 @@ EdgeTable::EdgeTable (const Rectangle& rectangleToAdd) throw() | |||
| EdgeTable::EdgeTable (const float x, const float y, const float w, const float h) throw() | |||
| : bounds (Rectangle ((int) floorf (x), roundFloatToInt (y * 256.0f) >> 8, 2 + (int) w, 2 + (int) h)), | |||
| maxEdgesPerLine (juce_edgeTableDefaultEdgesPerLine), | |||
| lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1) | |||
| lineStrideElements ((juce_edgeTableDefaultEdgesPerLine << 1) + 1), | |||
| needToCheckEmptinesss (true) | |||
| { | |||
| jassert (w > 0 && h > 0); | |||
| table = (int*) juce_malloc (jmax (1, bounds.getHeight()) * lineStrideElements * sizeof (int)); | |||
| @@ -274,6 +277,7 @@ const EdgeTable& EdgeTable::operator= (const EdgeTable& other) throw() | |||
| bounds = other.bounds; | |||
| maxEdgesPerLine = other.maxEdgesPerLine; | |||
| lineStrideElements = other.lineStrideElements; | |||
| needToCheckEmptinesss = other.needToCheckEmptinesss; | |||
| const int tableSize = jmax (1, bounds.getHeight()) * lineStrideElements * sizeof (int); | |||
| table = (int*) juce_malloc (tableSize); | |||
| @@ -358,6 +362,27 @@ void EdgeTable::addEdgePoint (const int x, const int y, const int winding) throw | |||
| line[0]++; | |||
| } | |||
| void EdgeTable::translate (float dx, int dy) throw() | |||
| { | |||
| bounds.setPosition (bounds.getX() + (int) floorf (dx), bounds.getY() + dy); | |||
| int* lineStart = table; | |||
| const int intDx = (int) (dx * 256.0f); | |||
| for (int i = bounds.getHeight(); --i >= 0;) | |||
| { | |||
| int* line = lineStart; | |||
| lineStart += lineStrideElements; | |||
| int num = *line++; | |||
| while (--num >= 0) | |||
| { | |||
| *line += intDx; | |||
| line += 2; | |||
| } | |||
| } | |||
| } | |||
| void EdgeTable::intersectWithEdgeTableLine (const int y, const int* otherLine) throw() | |||
| { | |||
| jassert (y >= 0 && y < bounds.getHeight()); | |||
| @@ -482,6 +507,7 @@ void EdgeTable::clipToRectangle (const Rectangle& r) throw() | |||
| if (clipped.isEmpty()) | |||
| { | |||
| needToCheckEmptinesss = false; | |||
| bounds.setHeight (0); | |||
| } | |||
| else | |||
| @@ -505,6 +531,8 @@ void EdgeTable::clipToRectangle (const Rectangle& r) throw() | |||
| for (int i = top; i < bottom; ++i) | |||
| intersectWithEdgeTableLine (i, rectLine); | |||
| } | |||
| needToCheckEmptinesss = true; | |||
| } | |||
| } | |||
| @@ -523,6 +551,8 @@ void EdgeTable::excludeRectangle (const Rectangle& r) throw() | |||
| for (int i = top; i < bottom; ++i) | |||
| intersectWithEdgeTableLine (i, rectLine); | |||
| needToCheckEmptinesss = true; | |||
| } | |||
| } | |||
| @@ -532,6 +562,7 @@ void EdgeTable::clipToEdgeTable (const EdgeTable& other) | |||
| if (clipped.isEmpty()) | |||
| { | |||
| needToCheckEmptinesss = false; | |||
| bounds.setHeight (0); | |||
| } | |||
| else | |||
| @@ -555,109 +586,74 @@ void EdgeTable::clipToEdgeTable (const EdgeTable& other) | |||
| intersectWithEdgeTableLine (i, otherLine); | |||
| otherLine += other.lineStrideElements; | |||
| } | |||
| needToCheckEmptinesss = true; | |||
| } | |||
| } | |||
| void EdgeTable::clipToImageAlpha (const Image& image, int x, int y) throw() | |||
| void EdgeTable::clipLineToMask (int x, int y, uint8* mask, int maskStride, int numPixels) throw() | |||
| { | |||
| const Rectangle clipped (bounds.getIntersection (Rectangle (x, y, image.getWidth(), image.getHeight()))); | |||
| y -= bounds.getY(); | |||
| if (clipped.isEmpty()) | |||
| { | |||
| bounds.setHeight (0); | |||
| } | |||
| else | |||
| { | |||
| if (! image.hasAlphaChannel()) | |||
| { | |||
| clipToRectangle (clipped); | |||
| return; | |||
| } | |||
| const int top = clipped.getY() - bounds.getY(); | |||
| const int bottom = clipped.getBottom() - bounds.getY(); | |||
| if (bottom < bounds.getHeight()) | |||
| bounds.setHeight (bottom); | |||
| if (y < 0 || y >= bounds.getHeight()) | |||
| return; | |||
| if (clipped.getRight() < bounds.getRight()) | |||
| bounds.setRight (clipped.getRight()); | |||
| needToCheckEmptinesss = true; | |||
| for (int i = top; --i >= 0;) | |||
| table [lineStrideElements * i] = 0; | |||
| int imageX = clipped.getX() - x; | |||
| int imageY = clipped.getY() - y; | |||
| if (numPixels <= 0) | |||
| { | |||
| table [lineStrideElements * y] = 0; | |||
| return; | |||
| } | |||
| int* temp = (int*) alloca ((clipped.getWidth() * 2 + 4) * sizeof (int)); | |||
| int* tempLine = (int*) alloca ((numPixels * 2 + 4) * sizeof (int)); | |||
| int destIndex = 0, lastLevel = 0; | |||
| Image::BitmapData srcData (image, imageX, imageY, clipped.getWidth(), clipped.getHeight()); | |||
| while (--numPixels >= 0) | |||
| { | |||
| const int alpha = *mask; | |||
| mask += maskStride; | |||
| for (int i = 0; i < clipped.getHeight(); ++i) | |||
| if (alpha != lastLevel) | |||
| { | |||
| int destIndex = 0, lastLevel = 0; | |||
| const uint8* pixels = srcData.getLinePointer (i); | |||
| if (image.getFormat() == Image::ARGB) | |||
| { | |||
| for (int px = 0; px < clipped.getWidth(); ++px) | |||
| { | |||
| const int alpha = ((const PixelARGB*) pixels)->getAlpha(); | |||
| pixels += srcData.pixelStride; | |||
| if (alpha != lastLevel) | |||
| { | |||
| temp[++destIndex] = (clipped.getX() + px) << 8; | |||
| temp[++destIndex] = alpha; | |||
| lastLevel = alpha; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| jassert (image.getFormat() == Image::SingleChannel); | |||
| tempLine[++destIndex] = (x << 8); | |||
| tempLine[++destIndex] = alpha; | |||
| lastLevel = alpha; | |||
| } | |||
| for (int px = 0; px < clipped.getWidth(); ++px) | |||
| { | |||
| const int alpha = *pixels; | |||
| pixels += srcData.pixelStride; | |||
| if (alpha != lastLevel) | |||
| { | |||
| temp[++destIndex] = (clipped.getX() + px) << 8; | |||
| temp[++destIndex] = alpha; | |||
| lastLevel = alpha; | |||
| } | |||
| } | |||
| } | |||
| ++x; | |||
| } | |||
| if (lastLevel > 0) | |||
| { | |||
| temp[++destIndex] = clipped.getRight() << 8; | |||
| temp[++destIndex] = 0; | |||
| } | |||
| if (lastLevel > 0) | |||
| { | |||
| tempLine[++destIndex] = (x << 8); | |||
| tempLine[++destIndex] = 0; | |||
| } | |||
| temp[0] = destIndex >> 1; | |||
| tempLine[0] = destIndex >> 1; | |||
| intersectWithEdgeTableLine (top + i, temp); | |||
| ++y; | |||
| } | |||
| } | |||
| intersectWithEdgeTableLine (y, tempLine); | |||
| } | |||
| bool EdgeTable::isEmpty() const throw() | |||
| bool EdgeTable::isEmpty() throw() | |||
| { | |||
| int* t = table; | |||
| for (int i = bounds.getHeight(); --i >= 0;) | |||
| if (needToCheckEmptinesss) | |||
| { | |||
| if (t[0] > 1) | |||
| return false; | |||
| needToCheckEmptinesss = false; | |||
| int* t = table; | |||
| t += lineStrideElements; | |||
| for (int i = bounds.getHeight(); --i >= 0;) | |||
| { | |||
| if (t[0] > 1) | |||
| return false; | |||
| t += lineStrideElements; | |||
| } | |||
| bounds.setHeight (0); | |||
| } | |||
| return true; | |||
| return bounds.getHeight() == 0; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -78,9 +78,10 @@ public: | |||
| void clipToRectangle (const Rectangle& r) throw(); | |||
| void excludeRectangle (const Rectangle& r) throw(); | |||
| void clipToEdgeTable (const EdgeTable& other); | |||
| void clipToImageAlpha (const Image& image, int x, int y) throw(); | |||
| bool isEmpty() const throw(); | |||
| void clipLineToMask (int x, int y, uint8* mask, int maskStride, int numPixels) throw(); | |||
| bool isEmpty() throw(); | |||
| const Rectangle& getMaximumBounds() const throw() { return bounds; } | |||
| void translate (float dx, int dy) throw(); | |||
| /** Reduces the amount of space the table has allocated. | |||
| @@ -192,6 +193,7 @@ private: | |||
| int* table; | |||
| Rectangle bounds; | |||
| int maxEdgesPerLine, lineStrideElements; | |||
| bool needToCheckEmptinesss; | |||
| void addEdgePoint (const int x, const int y, const int winding) throw(); | |||
| void remapTableForNumEdges (const int newNumEdgesPerLine) throw(); | |||
| @@ -31,8 +31,6 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "../fonts/juce_GlyphArrangement.h" | |||
| #include "../geometry/juce_PathStrokeType.h" | |||
| #include "juce_LowLevelGraphicsContext.h" | |||
| #include "../brushes/juce_GradientBrush.h" | |||
| #include "../brushes/juce_ImageBrush.h" | |||
| static const Graphics::ResamplingQuality defaultQuality = Graphics::mediumResamplingQuality; | |||
| @@ -65,7 +63,6 @@ LowLevelGraphicsContext::~LowLevelGraphicsContext() | |||
| Graphics::Graphics (Image& imageToDrawOnto) throw() | |||
| : context (imageToDrawOnto.createLowLevelContext()), | |||
| ownsContext (true), | |||
| state (new GraphicsState()), | |||
| saveStatePending (false) | |||
| { | |||
| resetToDefaultState(); | |||
| @@ -74,7 +71,6 @@ Graphics::Graphics (Image& imageToDrawOnto) throw() | |||
| Graphics::Graphics (LowLevelGraphicsContext* const internalContext) throw() | |||
| : context (internalContext), | |||
| ownsContext (false), | |||
| state (new GraphicsState()), | |||
| saveStatePending (false) | |||
| { | |||
| resetToDefaultState(); | |||
| @@ -82,8 +78,6 @@ Graphics::Graphics (LowLevelGraphicsContext* const internalContext) throw() | |||
| Graphics::~Graphics() throw() | |||
| { | |||
| delete state; | |||
| if (ownsContext) | |||
| delete context; | |||
| } | |||
| @@ -106,20 +100,20 @@ bool Graphics::reduceClipRegion (const int x, const int y, | |||
| const int w, const int h) throw() | |||
| { | |||
| saveStateIfPending(); | |||
| return context->reduceClipRegion (x, y, w, h); | |||
| return context->clipToRectangle (Rectangle (x, y, w, h)); | |||
| } | |||
| bool Graphics::reduceClipRegion (const RectangleList& clipRegion) throw() | |||
| { | |||
| saveStateIfPending(); | |||
| return context->reduceClipRegion (clipRegion); | |||
| return context->clipToRectangleList (clipRegion); | |||
| } | |||
| void Graphics::excludeClipRegion (const int x, const int y, | |||
| const int w, const int h) throw() | |||
| { | |||
| saveStateIfPending(); | |||
| context->excludeClipRegion (x, y, w, h); | |||
| context->excludeClipRectangle (Rectangle (x, y, w, h)); | |||
| } | |||
| bool Graphics::isClipEmpty() const throw() | |||
| @@ -141,29 +135,9 @@ void Graphics::saveState() throw() | |||
| void Graphics::restoreState() throw() | |||
| { | |||
| if (saveStatePending) | |||
| { | |||
| saveStatePending = false; | |||
| } | |||
| else | |||
| { | |||
| const int stackSize = stateStack.size(); | |||
| if (stackSize > 0) | |||
| { | |||
| context->restoreState(); | |||
| delete state; | |||
| state = stateStack.getUnchecked (stackSize - 1); | |||
| stateStack.removeLast (1, false); | |||
| } | |||
| else | |||
| { | |||
| // Trying to call restoreState() more times than you've called saveState() ! | |||
| // Be careful to correctly match each saveState() with exactly one call to restoreState(). | |||
| jassertfalse | |||
| } | |||
| } | |||
| context->restoreState(); | |||
| } | |||
| void Graphics::saveStateIfPending() throw() | |||
| @@ -171,9 +145,7 @@ void Graphics::saveStateIfPending() throw() | |||
| if (saveStatePending) | |||
| { | |||
| saveStatePending = false; | |||
| context->saveState(); | |||
| stateStack.add (new GraphicsState (*state)); | |||
| } | |||
| } | |||
| @@ -187,15 +159,13 @@ void Graphics::setOrigin (const int newOriginX, | |||
| bool Graphics::clipRegionIntersects (const int x, const int y, | |||
| const int w, const int h) const throw() | |||
| { | |||
| return context->clipRegionIntersects (x, y, w, h); | |||
| return context->clipRegionIntersects (Rectangle (x, y, w, h)); | |||
| } | |||
| //============================================================================== | |||
| void Graphics::setColour (const Colour& newColour) throw() | |||
| { | |||
| saveStateIfPending(); | |||
| deleteAndZero (state->brush); | |||
| context->setColour (newColour); | |||
| } | |||
| @@ -205,75 +175,26 @@ void Graphics::setOpacity (const float newOpacity) throw() | |||
| context->setOpacity (newOpacity); | |||
| } | |||
| void Graphics::setBrush (const Brush* const newBrush) throw() | |||
| { | |||
| saveStateIfPending(); | |||
| delete state->brush; | |||
| state->brush = 0; | |||
| if (newBrush != 0) | |||
| { | |||
| const SolidColourBrush* cb = dynamic_cast <const SolidColourBrush*> (newBrush); | |||
| if (cb != 0) | |||
| { | |||
| setColour (cb->getColour()); | |||
| } | |||
| else | |||
| { | |||
| const GradientBrush* gb = dynamic_cast <const GradientBrush*> (newBrush); | |||
| if (gb != 0) | |||
| { | |||
| setGradientFill (gb->getGradient()); | |||
| } | |||
| else | |||
| { | |||
| state->brush = newBrush->createCopy(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| void Graphics::setGradientFill (const ColourGradient& gradient) throw() | |||
| { | |||
| saveStateIfPending(); | |||
| deleteAndZero (state->brush); | |||
| context->setGradient (gradient); | |||
| } | |||
| void Graphics::setTiledImageFill (Image& imageToUse, | |||
| void Graphics::setTiledImageFill (const Image& imageToUse, | |||
| const int anchorX, | |||
| const int anchorY, | |||
| const float opacity) throw() | |||
| { | |||
| saveStateIfPending(); | |||
| delete state->brush; | |||
| state->brush = new ImageBrush (&imageToUse, anchorX, anchorY, opacity); | |||
| } | |||
| //============================================================================== | |||
| Graphics::GraphicsState::GraphicsState() throw() | |||
| : brush (0) | |||
| { | |||
| } | |||
| Graphics::GraphicsState::GraphicsState (const GraphicsState& other) throw() | |||
| : brush (other.brush != 0 ? other.brush->createCopy() : 0), | |||
| font (other.font) | |||
| { | |||
| } | |||
| Graphics::GraphicsState::~GraphicsState() throw() | |||
| { | |||
| delete brush; | |||
| context->setTiledFill (imageToUse, anchorX, anchorY); | |||
| context->setOpacity (opacity); | |||
| } | |||
| //============================================================================== | |||
| void Graphics::setFont (const Font& newFont) throw() | |||
| { | |||
| saveStateIfPending(); | |||
| state->font = newFont; | |||
| context->setFont (newFont); | |||
| } | |||
| @@ -281,8 +202,9 @@ void Graphics::setFont (const float newFontHeight, | |||
| const int newFontStyleFlags) throw() | |||
| { | |||
| saveStateIfPending(); | |||
| state->font.setSizeAndStyle (newFontHeight, newFontStyleFlags, 1.0f, 0); | |||
| context->setFont (state->font); | |||
| Font f (context->getFont()); | |||
| f.setSizeAndStyle (newFontHeight, newFontStyleFlags, 1.0f, 0); | |||
| context->setFont (f); | |||
| } | |||
| //============================================================================== | |||
| @@ -294,7 +216,7 @@ void Graphics::drawSingleLineText (const String& text, | |||
| && startX < context->getClipBounds().getRight()) | |||
| { | |||
| GlyphArrangement arr; | |||
| arr.addLineOfText (state->font, text, (float) startX, (float) baselineY); | |||
| arr.addLineOfText (context->getFont(), text, (float) startX, (float) baselineY); | |||
| arr.draw (*this); | |||
| } | |||
| } | |||
| @@ -305,7 +227,7 @@ void Graphics::drawTextAsPath (const String& text, | |||
| if (text.isNotEmpty()) | |||
| { | |||
| GlyphArrangement arr; | |||
| arr.addLineOfText (state->font, text, 0.0f, 0.0f); | |||
| arr.addLineOfText (context->getFont(), text, 0.0f, 0.0f); | |||
| arr.draw (*this, transform); | |||
| } | |||
| } | |||
| @@ -319,7 +241,7 @@ void Graphics::drawMultiLineText (const String& text, | |||
| && startX < context->getClipBounds().getRight()) | |||
| { | |||
| GlyphArrangement arr; | |||
| arr.addJustifiedText (state->font, text, | |||
| arr.addJustifiedText (context->getFont(), text, | |||
| (float) startX, (float) baselineY, (float) maximumLineWidth, | |||
| Justification::left); | |||
| arr.draw (*this); | |||
| @@ -334,11 +256,11 @@ void Graphics::drawText (const String& text, | |||
| const Justification& justificationType, | |||
| const bool useEllipsesIfTooBig) const throw() | |||
| { | |||
| if (text.isNotEmpty() && context->clipRegionIntersects (x, y, width, height)) | |||
| if (text.isNotEmpty() && context->clipRegionIntersects (Rectangle (x, y, width, height))) | |||
| { | |||
| GlyphArrangement arr; | |||
| arr.addCurtailedLineOfText (state->font, text, | |||
| arr.addCurtailedLineOfText (context->getFont(), text, | |||
| 0.0f, 0.0f, (float)width, | |||
| useEllipsesIfTooBig); | |||
| @@ -361,11 +283,11 @@ void Graphics::drawFittedText (const String& text, | |||
| { | |||
| if (text.isNotEmpty() | |||
| && width > 0 && height > 0 | |||
| && context->clipRegionIntersects (x, y, width, height)) | |||
| && context->clipRegionIntersects (Rectangle (x, y, width, height))) | |||
| { | |||
| GlyphArrangement arr; | |||
| arr.addFittedText (state->font, text, | |||
| arr.addFittedText (context->getFont(), text, | |||
| (float) x, (float) y, | |||
| (float) width, (float) height, | |||
| justification, | |||
| @@ -385,18 +307,12 @@ void Graphics::fillRect (int x, | |||
| // passing in a silly number can cause maths problems in rendering! | |||
| ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (x, y, width, height); | |||
| if (state->brush == 0) | |||
| context->fillRect (x, y, width, height, false); | |||
| else | |||
| state->brush->paintRectangle (*context, x, y, width, height); | |||
| context->fillRect (Rectangle (x, y, width, height), false); | |||
| } | |||
| void Graphics::fillRect (const Rectangle& r) const throw() | |||
| { | |||
| fillRect (r.getX(), | |||
| r.getY(), | |||
| r.getWidth(), | |||
| r.getHeight()); | |||
| context->fillRect (r, false); | |||
| } | |||
| void Graphics::fillRect (const float x, | |||
| @@ -414,13 +330,7 @@ void Graphics::fillRect (const float x, | |||
| void Graphics::setPixel (int x, int y) const throw() | |||
| { | |||
| if (context->clipRegionIntersects (x, y, 1, 1)) | |||
| { | |||
| if (state->brush == 0) | |||
| context->fillRect (x, y, 1, 1, false); | |||
| else | |||
| state->brush->paintRectangle (*context, x, y, 1, 1); | |||
| } | |||
| context->fillRect (Rectangle (x, y, 1, 1), false); | |||
| } | |||
| void Graphics::fillAll() const throw() | |||
| @@ -436,7 +346,7 @@ void Graphics::fillAll (const Colour& colourToUse) const throw() | |||
| context->saveState(); | |||
| context->setColour (colourToUse); | |||
| context->fillRect (clip.getX(), clip.getY(), clip.getWidth(), clip.getHeight(), false); | |||
| context->fillRect (clip, false); | |||
| context->restoreState(); | |||
| } | |||
| } | |||
| @@ -447,24 +357,16 @@ void Graphics::fillPath (const Path& path, | |||
| const AffineTransform& transform) const throw() | |||
| { | |||
| if ((! context->isClipEmpty()) && ! path.isEmpty()) | |||
| { | |||
| if (state->brush == 0) | |||
| context->fillPath (path, transform); | |||
| else | |||
| state->brush->paintPath (*context, path, transform); | |||
| } | |||
| context->fillPath (path, transform); | |||
| } | |||
| void Graphics::strokePath (const Path& path, | |||
| const PathStrokeType& strokeType, | |||
| const AffineTransform& transform) const throw() | |||
| { | |||
| // if ((! state->colour.isTransparent()) || state->brush != 0) | |||
| { | |||
| Path stroke; | |||
| strokeType.createStrokedPath (stroke, path, transform); | |||
| fillPath (stroke); | |||
| } | |||
| Path stroke; | |||
| strokeType.createStrokedPath (stroke, path, transform); | |||
| fillPath (stroke); | |||
| } | |||
| //============================================================================== | |||
| @@ -477,21 +379,10 @@ void Graphics::drawRect (const int x, | |||
| // passing in a silly number can cause maths problems in rendering! | |||
| ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (x, y, width, height); | |||
| if (state->brush == 0) | |||
| { | |||
| context->fillRect (x, y, width, lineThickness, false); | |||
| context->fillRect (x, y + lineThickness, lineThickness, height - lineThickness * 2, false); | |||
| context->fillRect (x + width - lineThickness, y + lineThickness, lineThickness, height - lineThickness * 2, false); | |||
| context->fillRect (x, y + height - lineThickness, width, lineThickness, false); | |||
| } | |||
| else | |||
| { | |||
| Brush& b = *(state->brush); | |||
| b.paintRectangle (*context, x, y, width, lineThickness); | |||
| b.paintRectangle (*context, x, y + lineThickness, lineThickness, height - lineThickness * 2); | |||
| b.paintRectangle (*context, x + width - lineThickness, y + lineThickness, lineThickness, height - lineThickness * 2); | |||
| b.paintRectangle (*context, x, y + height - lineThickness, width, lineThickness); | |||
| } | |||
| context->fillRect (Rectangle (x, y, width, lineThickness), false); | |||
| context->fillRect (Rectangle (x, y + lineThickness, lineThickness, height - lineThickness * 2), false); | |||
| context->fillRect (Rectangle (x + width - lineThickness, y + lineThickness, lineThickness, height - lineThickness * 2), false); | |||
| context->fillRect (Rectangle (x, y + height - lineThickness, width, lineThickness), false); | |||
| } | |||
| void Graphics::drawRect (const float x, | |||
| @@ -545,13 +436,13 @@ void Graphics::drawBevel (const int x, | |||
| : oldOpacity; | |||
| context->setColour (topLeftColour.withMultipliedAlpha (op)); | |||
| context->fillRect (x + i, y + i, width - i * 2, 1, false); | |||
| context->fillRect (Rectangle (x + i, y + i, width - i * 2, 1), false); | |||
| context->setColour (topLeftColour.withMultipliedAlpha (op * 0.75f)); | |||
| context->fillRect (x + i, y + i + 1, 1, height - i * 2 - 2, false); | |||
| context->fillRect (Rectangle (x + i, y + i + 1, 1, height - i * 2 - 2), false); | |||
| context->setColour (bottomRightColour.withMultipliedAlpha (op)); | |||
| context->fillRect (x + i, y + height - i - 1, width - i * 2, 1, false); | |||
| context->fillRect (Rectangle (x + i, y + height - i - 1, width - i * 2, 1), false); | |||
| context->setColour (bottomRightColour.withMultipliedAlpha (op * 0.75f)); | |||
| context->fillRect (x + width - i - 1, y + i + 1, 1, height - i * 2 - 2, false); | |||
| context->fillRect (Rectangle (x + width - i - 1, y + i + 1, 1, height - i * 2 - 2), false); | |||
| } | |||
| context->restoreState(); | |||
| @@ -667,7 +558,7 @@ void Graphics::fillCheckerBoard (int x, int y, | |||
| if (colour1 == colour2) | |||
| { | |||
| context->setColour (colour1); | |||
| context->fillRect (x, y, width, height, false); | |||
| context->fillRect (Rectangle (x, y, width, height), false); | |||
| } | |||
| else | |||
| { | |||
| @@ -684,9 +575,7 @@ void Graphics::fillCheckerBoard (int x, int y, | |||
| for (int xx = x; xx < right; xx += checkWidth) | |||
| { | |||
| context->setColour (((cx++ & 1) == 0) ? colour1 : colour2); | |||
| context->fillRect (xx, y, | |||
| jmin (checkWidth, right - xx), | |||
| jmin (checkHeight, bottom - y), | |||
| context->fillRect (Rectangle (xx, y, jmin (checkWidth, right - xx), jmin (checkHeight, bottom - y)), | |||
| false); | |||
| } | |||
| @@ -702,30 +591,17 @@ void Graphics::fillCheckerBoard (int x, int y, | |||
| //============================================================================== | |||
| void Graphics::drawVerticalLine (const int x, float top, float bottom) const throw() | |||
| { | |||
| if (state->brush == 0) | |||
| context->drawVerticalLine (x, top, bottom); | |||
| else | |||
| state->brush->paintVerticalLine (*context, x, top, bottom); | |||
| context->drawVerticalLine (x, top, bottom); | |||
| } | |||
| void Graphics::drawHorizontalLine (const int y, float left, float right) const throw() | |||
| { | |||
| if (state->brush == 0) | |||
| context->drawHorizontalLine (y, left, right); | |||
| else | |||
| state->brush->paintHorizontalLine (*context, y, left, right); | |||
| context->drawHorizontalLine (y, left, right); | |||
| } | |||
| void Graphics::drawLine (float x1, float y1, | |||
| float x2, float y2) const throw() | |||
| void Graphics::drawLine (float x1, float y1, float x2, float y2) const throw() | |||
| { | |||
| if (! context->isClipEmpty()) | |||
| { | |||
| if (state->brush == 0) | |||
| context->drawLine (x1, y1, x2, y2); | |||
| else | |||
| state->brush->paintLine (*context, x1, y1, x2, y2); | |||
| } | |||
| context->drawLine (x1, y1, x2, y2); | |||
| } | |||
| void Graphics::drawLine (const float startX, | |||
| @@ -864,126 +740,14 @@ void Graphics::drawImage (const Image* const imageToDraw, | |||
| ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (dx, dy, dw, dh); | |||
| ASSERT_COORDS_ARE_SENSIBLE_NUMBERS (sx, sy, sw, sh); | |||
| if (imageToDraw == 0 || ! context->clipRegionIntersects (dx, dy, dw, dh)) | |||
| if (! context->clipRegionIntersects (Rectangle (dx, dy, dw, dh))) | |||
| return; | |||
| if (sw == dw && sh == dh) | |||
| { | |||
| if (sx < 0) | |||
| { | |||
| dx -= sx; | |||
| dw += sx; | |||
| sw += sx; | |||
| sx = 0; | |||
| } | |||
| if (sx + sw > imageToDraw->getWidth()) | |||
| { | |||
| const int amount = sx + sw - imageToDraw->getWidth(); | |||
| dw -= amount; | |||
| sw -= amount; | |||
| } | |||
| if (sy < 0) | |||
| { | |||
| dy -= sy; | |||
| dh += sy; | |||
| sh += sy; | |||
| sy = 0; | |||
| } | |||
| if (sy + sh > imageToDraw->getHeight()) | |||
| { | |||
| const int amount = sy + sh - imageToDraw->getHeight(); | |||
| dh -= amount; | |||
| sh -= amount; | |||
| } | |||
| if (dw <= 0 || dh <= 0 || sw <= 0 || sh <= 0) | |||
| return; | |||
| if (fillAlphaChannelWithCurrentBrush) | |||
| { | |||
| if (state->brush == 0) | |||
| { | |||
| context->saveState(); | |||
| if (context->reduceClipRegion (dx, dy, dw, dh)) | |||
| context->fillAlphaChannel (*imageToDraw, dx - sx, dy - sy); | |||
| context->restoreState(); | |||
| } | |||
| else | |||
| { | |||
| state->brush->paintAlphaChannel (*context, *imageToDraw, | |||
| dx - sx, dy - sy, | |||
| dx, dy, dw, dh); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| context->blendImage (*imageToDraw, | |||
| dx, dy, dw, dh, sx, sy); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if (dw <= 0 || dh <= 0 || sw <= 0 || sh <= 0) | |||
| return; | |||
| if (fillAlphaChannelWithCurrentBrush) | |||
| { | |||
| if (imageToDraw->isRGB()) | |||
| { | |||
| fillRect (dx, dy, dw, dh); | |||
| } | |||
| else | |||
| { | |||
| int tx = dx; | |||
| int ty = dy; | |||
| int tw = dw; | |||
| int th = dh; | |||
| if (context->getClipBounds().intersectRectangle (tx, ty, tw, th)) | |||
| { | |||
| Image temp (imageToDraw->getFormat(), tw, th, true); | |||
| Graphics g (temp); | |||
| //xxx g.setImageResamplingQuality (state->quality); | |||
| g.setOrigin (dx - tx, dy - ty); | |||
| g.drawImage (imageToDraw, | |||
| 0, 0, dw, dh, | |||
| sx, sy, sw, sh, | |||
| false); | |||
| if (state->brush == 0) | |||
| { | |||
| context->saveState(); | |||
| if (context->reduceClipRegion (tx, ty, tw, th)) | |||
| context->fillAlphaChannel (temp, tx, ty); | |||
| context->restoreState(); | |||
| } | |||
| else | |||
| { | |||
| state->brush->paintAlphaChannel (*context, temp, tx, ty, tx, ty, tw, th); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| context->blendImageWarping (*imageToDraw, | |||
| sx, sy, sw, sh, | |||
| AffineTransform::translation ((float) -sx, | |||
| (float) -sy) | |||
| .scaled (dw / (float) sw, | |||
| dh / (float) sh) | |||
| .translated ((float) dx, | |||
| (float) dy)); | |||
| } | |||
| } | |||
| drawImageTransformed (imageToDraw, sx, sy, sw, sh, | |||
| AffineTransform::translation ((float) -sx, (float) -sy) | |||
| .scaled (dw / (float) sw, dh / (float) sh) | |||
| .translated ((float) dx, (float) dy), | |||
| fillAlphaChannelWithCurrentBrush); | |||
| } | |||
| void Graphics::drawImageTransformed (const Image* const imageToDraw, | |||
| @@ -994,72 +758,96 @@ void Graphics::drawImageTransformed (const Image* const imageToDraw, | |||
| const AffineTransform& transform, | |||
| const bool fillAlphaChannelWithCurrentBrush) const throw() | |||
| { | |||
| if (imageToDraw != 0 | |||
| && (! context->isClipEmpty()) | |||
| && ! transform.isSingularity()) | |||
| if (imageToDraw != 0 && ! context->isClipEmpty()) | |||
| { | |||
| if (transform.isIdentity()) | |||
| const Rectangle srcClip (Rectangle (sourceClipX, sourceClipY, sourceClipWidth, sourceClipHeight)); | |||
| if (fillAlphaChannelWithCurrentBrush) | |||
| { | |||
| drawImage (imageToDraw, | |||
| sourceClipX, sourceClipY, sourceClipWidth, sourceClipHeight, | |||
| sourceClipX, sourceClipY, sourceClipWidth, sourceClipHeight, | |||
| fillAlphaChannelWithCurrentBrush); | |||
| context->saveState(); | |||
| context->clipToImageAlpha (*imageToDraw, srcClip, transform); | |||
| fillAll(); | |||
| context->restoreState(); | |||
| } | |||
| else if (fillAlphaChannelWithCurrentBrush) | |||
| else | |||
| { | |||
| Path p; | |||
| p.addRectangle ((float) sourceClipX, (float) sourceClipY, | |||
| (float) sourceClipWidth, (float) sourceClipHeight); | |||
| context->drawImage (*imageToDraw, srcClip, transform, false); | |||
| } | |||
| } | |||
| } | |||
| p.applyTransform (transform); | |||
| //============================================================================== | |||
| Graphics::FillType::FillType() throw() | |||
| : colour (0xff000000), gradient (0), | |||
| image (0), imageX (0), imageY (0) | |||
| { | |||
| } | |||
| float dx, dy, dw, dh; | |||
| p.getBounds (dx, dy, dw, dh); | |||
| int tx = (int) dx; | |||
| int ty = (int) dy; | |||
| int tw = roundFloatToInt (dw) + 2; | |||
| int th = roundFloatToInt (dh) + 2; | |||
| Graphics::FillType::FillType (const Colour& colour_) throw() | |||
| : colour (colour_), gradient (0), | |||
| image (0), imageX (0), imageY (0) | |||
| { | |||
| } | |||
| if (context->getClipBounds().intersectRectangle (tx, ty, tw, th)) | |||
| { | |||
| Image temp (imageToDraw->getFormat(), tw, th, true); | |||
| Graphics g (temp); | |||
| //xxx g.setImageResamplingQuality (state->quality); | |||
| g.drawImageTransformed (imageToDraw, | |||
| sourceClipX, | |||
| sourceClipY, | |||
| sourceClipWidth, | |||
| sourceClipHeight, | |||
| transform.translated ((float) -tx, (float) -ty), | |||
| false); | |||
| if (state->brush == 0) | |||
| { | |||
| context->saveState(); | |||
| Graphics::FillType::FillType (const ColourGradient& gradient) throw() | |||
| : colour (0xff000000), gradient (new ColourGradient (gradient)), | |||
| image (0), imageX (0), imageY (0) | |||
| { | |||
| } | |||
| if (context->reduceClipRegion (tx, ty, tw, th)) | |||
| context->fillAlphaChannel (temp, tx, ty); | |||
| Graphics::FillType::FillType (Image* const image_, const int x, const int y) throw() | |||
| : colour (0xff000000), gradient (0), | |||
| image (image_), imageX (x), imageY (y) | |||
| { | |||
| } | |||
| context->restoreState(); | |||
| } | |||
| else | |||
| { | |||
| state->brush->paintAlphaChannel (*context, temp, tx, ty, tx, ty, tw, th); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| context->blendImageWarping (*imageToDraw, | |||
| sourceClipX, | |||
| sourceClipY, | |||
| sourceClipWidth, | |||
| sourceClipHeight, | |||
| transform); | |||
| } | |||
| Graphics::FillType::FillType (const FillType& other) throw() | |||
| : colour (other.colour), | |||
| gradient (other.gradient != 0 ? new ColourGradient (*other.gradient) : 0), | |||
| image (other.image), imageX (other.imageX), imageY (other.imageY) | |||
| { | |||
| } | |||
| const Graphics::FillType& Graphics::FillType::operator= (const FillType& other) throw() | |||
| { | |||
| if (this != &other) | |||
| { | |||
| colour = other.colour; | |||
| delete gradient; | |||
| gradient = (other.gradient != 0 ? new ColourGradient (*other.gradient) : 0); | |||
| image = other.image; | |||
| imageX = other.imageX; | |||
| imageY = other.imageY; | |||
| } | |||
| return *this; | |||
| } | |||
| Graphics::FillType::~FillType() throw() | |||
| { | |||
| delete gradient; | |||
| } | |||
| void Graphics::FillType::setColour (const Colour& newColour) throw() | |||
| { | |||
| deleteAndZero (gradient); | |||
| colour = newColour; | |||
| } | |||
| void Graphics::FillType::setGradient (const ColourGradient& newGradient) throw() | |||
| { | |||
| if (gradient != 0) | |||
| *gradient = newGradient; | |||
| else | |||
| gradient = new ColourGradient (newGradient); | |||
| } | |||
| void Graphics::FillType::setTiledImage (const Image& image_, const int imageX_, const int imageY_) throw() | |||
| { | |||
| deleteAndZero (gradient); | |||
| image = &image_; | |||
| imageX = imageX_; | |||
| imageY = imageY_; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -32,7 +32,6 @@ | |||
| #include "../geometry/juce_Line.h" | |||
| #include "../colour/juce_Colours.h" | |||
| #include "../colour/juce_ColourGradient.h" | |||
| #include "../brushes/juce_SolidColourBrush.h" | |||
| #include "juce_RectanglePlacement.h" | |||
| class LowLevelGraphicsContext; | |||
| class Image; | |||
| @@ -79,7 +78,7 @@ public: | |||
| If a brush is being used when this method is called, the brush will be deselected, | |||
| and any subsequent drawing will be done with a solid colour brush instead. | |||
| @see setOpacity, setBrush | |||
| @see setOpacity | |||
| */ | |||
| void setColour (const Colour& newColour) throw(); | |||
| @@ -94,18 +93,6 @@ public: | |||
| */ | |||
| void setOpacity (const float newOpacity) throw(); | |||
| /** Changes the current brush to use for drawing. | |||
| If a null pointer is passed in, the context will revert to using a solid | |||
| colour for drawing (using the last colour set by setColour()). | |||
| If a brush is passed in, a copy of it will be used for subsequent drawing | |||
| operations until setColour() or setBrush() is called. | |||
| @see SolidColourBrush, GradientBrush, ImageBrush, Brush | |||
| */ | |||
| void setBrush (const Brush* const newBrush) throw(); | |||
| /** Sets the context to use a gradient for its fill pattern. | |||
| */ | |||
| void setGradientFill (const ColourGradient& gradient) throw(); | |||
| @@ -114,7 +101,7 @@ public: | |||
| Make sure that you don't delete this image while it's still being used by | |||
| this context! | |||
| */ | |||
| void setTiledImageFill (Image& imageToUse, | |||
| void setTiledImageFill (const Image& imageToUse, | |||
| const int anchorX, | |||
| const int anchorY, | |||
| const float opacity) throw(); | |||
| @@ -698,12 +685,13 @@ public: | |||
| LowLevelGraphicsContext* getInternalContext() const throw() { return context; } | |||
| //============================================================================== | |||
| /*class FillType | |||
| class FillType | |||
| { | |||
| public: | |||
| FillType() throw(); | |||
| FillType (const Colour& colour) throw(); | |||
| FillType (const ColourGradient& gradient) throw(); | |||
| FillType (Image* image, int x, int y) throw(); | |||
| FillType (Image* const image, const int x, const int y) throw(); | |||
| FillType (const FillType& other) throw(); | |||
| const FillType& operator= (const FillType& other) throw(); | |||
| ~FillType() throw(); | |||
| @@ -714,35 +702,22 @@ public: | |||
| void setColour (const Colour& newColour) throw(); | |||
| void setGradient (const ColourGradient& newGradient) throw(); | |||
| void setTiledImage (Image* image, const int imageX, const int imageY) throw(); | |||
| void setTiledImage (const Image& image, const int imageX, const int imageY) throw(); | |||
| Colour colour; | |||
| ColourGradient* gradient; | |||
| Image* image; | |||
| const Image* image; | |||
| int imageX, imageY; | |||
| juce_UseDebuggingNewOperator | |||
| };*/ | |||
| }; | |||
| private: | |||
| //============================================================================== | |||
| LowLevelGraphicsContext* const context; | |||
| const bool ownsContext; | |||
| struct GraphicsState | |||
| { | |||
| GraphicsState() throw(); | |||
| GraphicsState (const GraphicsState&) throw(); | |||
| ~GraphicsState() throw(); | |||
| Brush* brush; | |||
| Font font; | |||
| }; | |||
| GraphicsState* state; | |||
| OwnedArray <GraphicsState> stateStack; | |||
| bool saveStatePending; | |||
| void saveStateIfPending() throw(); | |||
| const Graphics& operator= (const Graphics& other); | |||
| @@ -66,57 +66,40 @@ public: | |||
| */ | |||
| virtual void setOrigin (int x, int y) = 0; | |||
| /** Cliping co-ords are relative to the origin. */ | |||
| virtual bool reduceClipRegion (int x, int y, int w, int h) = 0; | |||
| virtual bool clipToRectangle (const Rectangle& r) = 0; | |||
| virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0; | |||
| virtual void excludeClipRectangle (const Rectangle& r) = 0; | |||
| virtual void clipToPath (const Path& path, const AffineTransform& transform) = 0; | |||
| virtual void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform) = 0; | |||
| /** Cliping co-ords are relative to the origin. */ | |||
| virtual bool reduceClipRegion (const RectangleList& clipRegion) = 0; | |||
| //virtual bool clipToPath (const Path& path) = 0; | |||
| //virtual bool clipToImageAlpha (Image& image, int imageX, int imageY) = 0; | |||
| /** Cliping co-ords are relative to the origin. */ | |||
| virtual void excludeClipRegion (int x, int y, int w, int h) = 0; | |||
| virtual bool clipRegionIntersects (const Rectangle& r) = 0; | |||
| virtual const Rectangle getClipBounds() const = 0; | |||
| virtual bool isClipEmpty() const = 0; | |||
| virtual void saveState() = 0; | |||
| virtual void restoreState() = 0; | |||
| virtual bool clipRegionIntersects (int x, int y, int w, int h) = 0; | |||
| virtual const Rectangle getClipBounds() const = 0; | |||
| virtual bool isClipEmpty() const = 0; | |||
| //============================================================================== | |||
| virtual void setColour (const Colour& colour) = 0; | |||
| virtual void setGradient (const ColourGradient& gradient) = 0; | |||
| virtual void setTiledFill (const Image& image, int x, int y) = 0; | |||
| virtual void setOpacity (float opacity) = 0; | |||
| virtual void setInterpolationQuality (Graphics::ResamplingQuality quality) = 0; | |||
| //============================================================================== | |||
| virtual void fillRect (int x, int y, int w, int h, const bool replaceExistingContents) = 0; | |||
| virtual void fillRect (const Rectangle& r, const bool replaceExistingContents) = 0; | |||
| virtual void fillPath (const Path& path, const AffineTransform& transform) = 0; | |||
| virtual void fillPathWithImage (const Path& path, const AffineTransform& transform, | |||
| const Image& image, int imageX, int imageY) = 0; | |||
| virtual void fillAlphaChannel (const Image& alphaImage, int alphaImageX, int alphaImageY) = 0; | |||
| virtual void fillAlphaChannelWithImage (const Image& alphaImage, int alphaImageX, int alphaImageY, | |||
| const Image& fillerImage, int fillerImageX, int fillerImageY) = 0; | |||
| //============================================================================== | |||
| virtual void blendImage (const Image& sourceImage, | |||
| int destX, int destY, int destW, int destH, int sourceX, int sourceY) = 0; | |||
| virtual void blendImageWarping (const Image& sourceImage, | |||
| int srcClipX, int srcClipY, int srcClipW, int srcClipH, | |||
| const AffineTransform& transform) = 0; | |||
| virtual void drawImage (const Image& sourceImage, const Rectangle& srcClip, | |||
| const AffineTransform& transform, const bool fillEntireClipAsTiles) = 0; | |||
| //============================================================================== | |||
| virtual void drawLine (double x1, double y1, double x2, double y2) = 0; | |||
| virtual void drawVerticalLine (const int x, double top, double bottom) = 0; | |||
| virtual void drawHorizontalLine (const int y, double left, double right) = 0; | |||
| virtual void setFont (const Font& newFont) = 0; | |||
| virtual void drawGlyph (int glyphNumber, float x, float y) = 0; | |||
| virtual const Font getFont() = 0; | |||
| virtual void drawGlyph (int glyphNumber, const AffineTransform& transform) = 0; | |||
| }; | |||
| @@ -613,7 +613,10 @@ void LowLevelGraphicsPostScriptRenderer::drawGlyph (int glyphNumber, float x, fl | |||
| void LowLevelGraphicsPostScriptRenderer::drawGlyph (int glyphNumber, const AffineTransform& transform) | |||
| { | |||
| font.renderGlyphIndirectly (*this, glyphNumber, transform); | |||
| Path p; | |||
| font.getTypeface()->getOutlineForGlyph (glyphNumber, p); | |||
| fillPath (p, AffineTransform::scale (font.getHeight() * font.getHorizontalScale(), font.getHeight()).followedBy (transform)); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -49,45 +49,35 @@ public: | |||
| //============================================================================== | |||
| void setOrigin (int x, int y); | |||
| bool reduceClipRegion (int x, int y, int w, int h); | |||
| bool reduceClipRegion (const RectangleList& clipRegion); | |||
| void excludeClipRegion (int x, int y, int w, int h); | |||
| bool clipToRectangle (const Rectangle& r); | |||
| bool clipToRectangleList (const RectangleList& clipRegion); | |||
| void excludeClipRectangle (const Rectangle& r); | |||
| void clipToPath (const Path& path, const AffineTransform& transform); | |||
| void clipToImage (Image& image, int imageX, int imageY); | |||
| void saveState(); | |||
| void restoreState(); | |||
| void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform); | |||
| bool clipRegionIntersects (int x, int y, int w, int h); | |||
| bool clipRegionIntersects (const Rectangle& r); | |||
| const Rectangle getClipBounds() const; | |||
| bool isClipEmpty() const; | |||
| void saveState(); | |||
| void restoreState(); | |||
| //============================================================================== | |||
| void setColour (const Colour& colour); | |||
| void setGradient (const ColourGradient& gradient); | |||
| void setTiledFill (const Image& image, int x, int y); | |||
| void setOpacity (float opacity); | |||
| void setInterpolationQuality (Graphics::ResamplingQuality quality); | |||
| //============================================================================== | |||
| void fillRect (int x, int y, int w, int h, const bool replaceExistingContents); | |||
| void fillAll (const bool replaceContents); | |||
| void fillRect (const Rectangle& r, const bool replaceExistingContents); | |||
| void fillPath (const Path& path, const AffineTransform& transform); | |||
| void fillPathWithImage (const Path& path, const AffineTransform& transform, | |||
| const Image& image, int imageX, int imageY); | |||
| void fillAlphaChannel (const Image& alphaImage, int imageX, int imageY); | |||
| void fillAlphaChannelWithImage (const Image& alphaImage, int alphaImageX, int alphaImageY, | |||
| const Image& fillerImage, int fillerImageX, int fillerImageY); | |||
| //============================================================================== | |||
| void blendImage (const Image& sourceImage, int destX, int destY, int destW, int destH, | |||
| int sourceX, int sourceY); | |||
| void blendImageWarping (const Image& sourceImage, int srcClipX, int srcClipY, int srcClipW, int srcClipH, | |||
| const AffineTransform& transform); | |||
| void drawImage (const Image& sourceImage, const Rectangle& srcClip, | |||
| const AffineTransform& transform, const bool fillEntireClipAsTiles); | |||
| //============================================================================== | |||
| void drawLine (double x1, double y1, double x2, double y2); | |||
| void drawVerticalLine (const int x, double top, double bottom); | |||
| @@ -95,6 +85,7 @@ public: | |||
| //============================================================================== | |||
| void setFont (const Font& newFont); | |||
| const Font getFont(); | |||
| void drawGlyph (int glyphNumber, float x, float y); | |||
| void drawGlyph (int glyphNumber, const AffineTransform& transform); | |||
| @@ -108,33 +99,6 @@ protected: | |||
| LLGCSavedState* currentState; | |||
| OwnedArray <LLGCSavedState> stateStack; | |||
| /* void drawVertical (const int x, const double top, const double bottom); | |||
| void drawHorizontal (const int y, const double top, const double bottom); | |||
| void clippedFillRectWithColour (const Rectangle& clipRect, int x, int y, int w, int h, const Colour& colour, const bool replaceExistingContents); | |||
| void clippedFillPath (int clipX, int clipY, int clipW, int clipH, const Path& path, const AffineTransform& transform); | |||
| void clippedFillPathWithImage (int clipX, int clipY, int clipW, int clipH, const Path& path, const AffineTransform& transform, | |||
| const Image& image, int imageX, int imageY, float alpha); | |||
| void clippedFillAlphaChannel (int clipX, int clipY, int clipW, int clipH, const Image& alphaImage, int alphaImageX, int alphaImageY); | |||
| void clippedFillAlphaChannelWithImage (int clipX, int clipY, int clipW, int clipH, const Image& alphaImage, int alphaImageX, int alphaImageY, | |||
| const Image& fillerImage, int fillerImageX, int fillerImageY, const float opacity); | |||
| //============================================================================== | |||
| void clippedBlendImage (int clipX, int clipY, int clipW, int clipH, const Image& sourceImage, | |||
| int destX, int destY, int destW, int destH, int sourceX, int sourceY); | |||
| void clippedBlendImageWarping (int clipX, int clipY, int clipW, int clipH, const Image& sourceImage, | |||
| int srcClipX, int srcClipY, int srcClipW, int srcClipH, | |||
| const AffineTransform& transform); | |||
| //============================================================================== | |||
| void clippedDrawLine (int clipX, int clipY, int clipW, int clipH, double x1, double y1, double x2, double y2); | |||
| void clippedDrawVerticalLine (int clipX, int clipY, int clipW, int clipH, const int x, double top, double bottom); | |||
| void clippedDrawHorizontalLine (int clipX, int clipY, int clipW, int clipH, const int x, double top, double bottom);*/ | |||
| LowLevelGraphicsSoftwareRenderer (const LowLevelGraphicsSoftwareRenderer& other); | |||
| const LowLevelGraphicsSoftwareRenderer& operator= (const LowLevelGraphicsSoftwareRenderer&); | |||
| }; | |||
| @@ -433,190 +433,4 @@ Typeface* Font::getTypeface() const throw() | |||
| } | |||
| //============================================================================== | |||
| class FontGlyphAlphaMap | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| FontGlyphAlphaMap() throw() | |||
| : glyph (0), lastAccessCount (0) | |||
| { | |||
| bitmap[0] = bitmap[1] = 0; | |||
| } | |||
| ~FontGlyphAlphaMap() throw() | |||
| { | |||
| delete bitmap[0]; | |||
| delete bitmap[1]; | |||
| } | |||
| void draw (LowLevelGraphicsContext& g, float x, const float y) const throw() | |||
| { | |||
| if (bitmap[0] != 0) | |||
| { | |||
| const float xFloor = floorf (x); | |||
| const int bitmapToUse = ((x - xFloor) >= 0.5f && bitmap[1] != 0) ? 1 : 0; | |||
| g.fillAlphaChannel (*bitmap [bitmapToUse], | |||
| xOrigin [bitmapToUse] + (int) xFloor, | |||
| yOrigin [bitmapToUse] + roundFloatToInt(y)); | |||
| } | |||
| } | |||
| void generate (const Font& font_, const int glyph_) throw() | |||
| { | |||
| font = font_; | |||
| glyph = glyph_; | |||
| deleteAndZero (bitmap[0]); | |||
| deleteAndZero (bitmap[1]); | |||
| Path glyphPath; | |||
| font.getTypeface()->getOutlineForGlyph (glyph_, glyphPath); | |||
| if (! glyphPath.isEmpty()) | |||
| { | |||
| const float fontHeight = font.getHeight(); | |||
| const float fontHScale = fontHeight * font.getHorizontalScale(); | |||
| AffineTransform transform (AffineTransform::scale (fontHScale, fontHeight)); | |||
| Rectangle clip (-2048, -2048, 4096, 4096), pos; | |||
| bitmap[0] = glyphPath.createMaskBitmap (transform, clip, pos); | |||
| xOrigin[0] = pos.getX(); | |||
| yOrigin[0] = pos.getY(); | |||
| if (fontHScale < 30.0f) | |||
| { | |||
| bitmap[1] = glyphPath.createMaskBitmap (transform.translated (0.5f, 0.0f), clip, pos); | |||
| xOrigin[1] = pos.getX(); | |||
| yOrigin[1] = pos.getY(); | |||
| } | |||
| } | |||
| } | |||
| int glyph, lastAccessCount; | |||
| Font font; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| Image* bitmap[2]; | |||
| int xOrigin[2], yOrigin[2]; | |||
| FontGlyphAlphaMap (const FontGlyphAlphaMap&); | |||
| const FontGlyphAlphaMap& operator= (const FontGlyphAlphaMap&); | |||
| }; | |||
| //============================================================================== | |||
| class GlyphCache : private DeletedAtShutdown | |||
| { | |||
| public: | |||
| GlyphCache() throw() | |||
| : accessCounter (0) | |||
| { | |||
| setCacheSize (120); | |||
| } | |||
| ~GlyphCache() throw() | |||
| { | |||
| clearSingletonInstance(); | |||
| } | |||
| juce_DeclareSingleton_SingleThreaded_Minimal (GlyphCache); | |||
| //============================================================================== | |||
| void drawGlyph (LowLevelGraphicsContext& g, const Font& font, int glyphNumber, float x, float y) throw() | |||
| { | |||
| ++accessCounter; | |||
| int oldestCounter = INT_MAX; | |||
| FontGlyphAlphaMap* oldest = 0; | |||
| for (int i = glyphs.size(); --i >= 0;) | |||
| { | |||
| FontGlyphAlphaMap* const glyph = glyphs.getUnchecked (i); | |||
| if (glyph->glyph == glyphNumber | |||
| && glyph->font == font) | |||
| { | |||
| ++hits; | |||
| glyph->lastAccessCount = accessCounter; | |||
| glyph->draw (g, x, y); | |||
| return; | |||
| } | |||
| if (glyph->lastAccessCount <= oldestCounter) | |||
| { | |||
| oldestCounter = glyph->lastAccessCount; | |||
| oldest = glyph; | |||
| } | |||
| } | |||
| ++misses; | |||
| if (hits + misses > (glyphs.size() << 4)) | |||
| { | |||
| if (misses * 2 > hits) | |||
| setCacheSize (glyphs.size() + 32); | |||
| hits = 0; | |||
| misses = 0; | |||
| oldest = glyphs.getUnchecked (0); | |||
| } | |||
| jassert (oldest != 0); | |||
| oldest->lastAccessCount = accessCounter; | |||
| oldest->generate (font, glyphNumber); | |||
| oldest->draw (g, x, y); | |||
| } | |||
| void setCacheSize (int num) throw() | |||
| { | |||
| if (glyphs.size() != num) | |||
| { | |||
| glyphs.clear(); | |||
| while (--num >= 0) | |||
| glyphs.add (new FontGlyphAlphaMap()); | |||
| hits = 0; | |||
| misses = 0; | |||
| } | |||
| } | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| OwnedArray <FontGlyphAlphaMap> glyphs; | |||
| int accessCounter, hits, misses; | |||
| GlyphCache (const GlyphCache&); | |||
| const GlyphCache& operator= (const GlyphCache&); | |||
| }; | |||
| juce_ImplementSingleton_SingleThreaded (GlyphCache); | |||
| //============================================================================== | |||
| void Font::renderGlyphIndirectly (LowLevelGraphicsContext& g, int glyphNumber, float x, float y) | |||
| { | |||
| if (font->height < 80.0f) | |||
| GlyphCache::getInstance()->drawGlyph (g, *this, glyphNumber, x, y); | |||
| else | |||
| renderGlyphIndirectly (g, glyphNumber, AffineTransform::translation (x, y)); | |||
| } | |||
| void Font::renderGlyphIndirectly (LowLevelGraphicsContext& g, int glyphNumber, const AffineTransform& transform) | |||
| { | |||
| Path p; | |||
| getTypeface()->getOutlineForGlyph (glyphNumber, p); | |||
| g.fillPath (p, AffineTransform::scale (font->height * font->horizontalScale, font->height) | |||
| .followedBy (transform)); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -307,24 +307,6 @@ public: | |||
| */ | |||
| void getGlyphPositions (const String& text, Array <int>& glyphs, Array <float>& xOffsets) const throw(); | |||
| //============================================================================== | |||
| /** Renders a glyph in a context without using methods other than the context's glyph-rendering | |||
| methods. | |||
| For smaller fonts, this uses an internal cache of glyph images to speed things up, and renders | |||
| them using the context's image blending methods. For larger fonts, it gets the glyph's path | |||
| from the typeface and renders it as a shape. | |||
| This method is primarily called by graphics contexts as a way of drawing a glyph if they can't do | |||
| it by native means. | |||
| */ | |||
| void renderGlyphIndirectly (LowLevelGraphicsContext& g, int glyphNumber, float x, float y); | |||
| /** Renders a transformed glyph using path-filling techniques rather than calling a context's | |||
| actual glyph-rendering methods. | |||
| */ | |||
| void renderGlyphIndirectly (LowLevelGraphicsContext& g, int glyphNumber, const AffineTransform& transform); | |||
| //============================================================================== | |||
| /** Returns the typeface used by this font. | |||
| @@ -45,7 +45,7 @@ void PositionedGlyph::draw (const Graphics& g) const throw() | |||
| if (! isWhitespace()) | |||
| { | |||
| g.getInternalContext()->setFont (font); | |||
| g.getInternalContext()->drawGlyph (glyph, x, y); | |||
| g.getInternalContext()->drawGlyph (glyph, AffineTransform::translation (x, y)); | |||
| } | |||
| } | |||
| @@ -323,11 +323,40 @@ const Point Path::getCurrentPosition() const | |||
| void Path::addRectangle (const float x, const float y, | |||
| const float w, const float h) throw() | |||
| { | |||
| startNewSubPath (x, y + h); | |||
| lineTo (x, y); | |||
| lineTo (x + w, y); | |||
| lineTo (x + w, y + h); | |||
| closeSubPath(); | |||
| float x1 = x, y1 = y, x2 = x + w, y2 = y + h; | |||
| if (w < 0) | |||
| swapVariables (x1, x2); | |||
| if (h < 0) | |||
| swapVariables (y1, y2); | |||
| ensureAllocatedSize (numElements + 13); | |||
| elements [numElements++] = moveMarker; | |||
| elements [numElements++] = x1; | |||
| elements [numElements++] = y2; | |||
| elements [numElements++] = lineMarker; | |||
| elements [numElements++] = x1; | |||
| elements [numElements++] = y1; | |||
| elements [numElements++] = lineMarker; | |||
| elements [numElements++] = x2; | |||
| elements [numElements++] = y1; | |||
| elements [numElements++] = lineMarker; | |||
| elements [numElements++] = x2; | |||
| elements [numElements++] = y2; | |||
| elements [numElements++] = closeSubPathMarker; | |||
| pathXMin = jmin (pathXMin, x1); | |||
| pathXMax = jmax (pathXMax, x2); | |||
| pathYMin = jmin (pathYMin, y1); | |||
| pathYMax = jmax (pathYMax, y2); | |||
| } | |||
| void Path::addRectangle (const Rectangle& rectangle) throw() | |||
| { | |||
| addRectangle ((float) rectangle.getX(), (float) rectangle.getY(), | |||
| (float) rectangle.getWidth(), (float) rectangle.getHeight()); | |||
| } | |||
| void Path::addRoundedRectangle (const float x, const float y, | |||
| @@ -1549,70 +1578,5 @@ bool Path::Iterator::next() | |||
| return false; | |||
| } | |||
| //============================================================================== | |||
| class MaskBitmapRenderer | |||
| { | |||
| public: | |||
| MaskBitmapRenderer (const Image::BitmapData& destData_) throw() | |||
| : destData (destData_) | |||
| { | |||
| } | |||
| forcedinline void setEdgeTableYPos (const int y) throw() | |||
| { | |||
| lineStart = destData.getLinePointer (y); | |||
| } | |||
| forcedinline void handleEdgeTablePixel (const int x, const int alphaLevel) const throw() | |||
| { | |||
| lineStart [x] = (uint8) alphaLevel; | |||
| } | |||
| forcedinline void handleEdgeTableLine (const int x, int width, const int alphaLevel) const throw() | |||
| { | |||
| uint8* d = lineStart + x; | |||
| while (--width >= 0) | |||
| *d++ = (uint8) alphaLevel; | |||
| } | |||
| private: | |||
| const Image::BitmapData& destData; | |||
| uint8* lineStart; | |||
| MaskBitmapRenderer (const MaskBitmapRenderer&); | |||
| const MaskBitmapRenderer& operator= (const MaskBitmapRenderer&); | |||
| }; | |||
| Image* Path::createMaskBitmap (const AffineTransform& transform, | |||
| const Rectangle& clipRegion, | |||
| Rectangle& imagePosition) const throw() | |||
| { | |||
| if (isEmpty()) | |||
| return 0; | |||
| float px, py, pw, ph; | |||
| getBoundsTransformed (transform, px, py, pw, ph); | |||
| imagePosition = clipRegion.getIntersection (Rectangle ((int) floorf (px), (int) floorf (py), | |||
| roundFloatToInt (pw) + 2, roundFloatToInt (ph) + 2)); | |||
| if (imagePosition.isEmpty()) | |||
| return 0; | |||
| Image* im = Image::createNativeImage (Image::SingleChannel, imagePosition.getWidth(), imagePosition.getHeight(), true); | |||
| EdgeTable edgeTable (Rectangle (0, 0, imagePosition.getWidth(), imagePosition.getHeight()), | |||
| *this, transform.translated ((float) -imagePosition.getX(), (float) -imagePosition.getY())); | |||
| const Image::BitmapData destData (*im, 0, 0, imagePosition.getWidth(), imagePosition.getHeight(), true); | |||
| jassert (destData.pixelStride == 1); | |||
| MaskBitmapRenderer renderer (destData); | |||
| edgeTable.iterate (renderer); | |||
| return im; | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -221,6 +221,15 @@ public: | |||
| void addRectangle (const float x, const float y, | |||
| const float w, const float h) throw(); | |||
| /** Adds a rectangle to the path. | |||
| The rectangle is added as a new sub-path. (Any currently open paths will be | |||
| left open). | |||
| @see addRoundedRectangle, addTriangle | |||
| */ | |||
| void addRectangle (const Rectangle& rectangle) throw(); | |||
| /** Adds a rectangle with rounded corners to the path. | |||
| The rectangle is added as a new sub-path. (Any currently open paths will be | |||
| @@ -616,21 +625,6 @@ public: | |||
| */ | |||
| void restoreFromString (const String& stringVersion); | |||
| //============================================================================== | |||
| /** Creates a single-channel bitmap containing a mask of this path. | |||
| The smallest bitmap that contains the path will be created, and on return, the | |||
| imagePosition rectangle indicates the position of the newly created image, relative | |||
| to the path's origin. | |||
| Only the intersection of the path's bounds with the specified clipRegion rectangle | |||
| will be rendered. | |||
| If the path is empty or doesn't intersect the clip region, this may return 0. | |||
| */ | |||
| Image* createMaskBitmap (const AffineTransform& transform, | |||
| const Rectangle& clipRegion, | |||
| Rectangle& imagePosition) const throw(); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| @@ -284,10 +284,6 @@ | |||
| #include "gui/components/windows/juce_ThreadWithProgressWindow.cpp" | |||
| #include "gui/components/windows/juce_TooltipWindow.cpp" | |||
| #include "gui/components/windows/juce_TopLevelWindow.cpp" | |||
| #include "gui/graphics/brushes/juce_Brush.cpp" | |||
| #include "gui/graphics/brushes/juce_GradientBrush.cpp" | |||
| #include "gui/graphics/brushes/juce_ImageBrush.cpp" | |||
| #include "gui/graphics/brushes/juce_SolidColourBrush.cpp" | |||
| #include "gui/graphics/colour/juce_Colour.cpp" | |||
| #include "gui/graphics/colour/juce_ColourGradient.cpp" | |||
| #include "gui/graphics/colour/juce_Colours.cpp" | |||
| @@ -185,12 +185,6 @@ | |||
| #ifndef __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ | |||
| #include "audio/audio_file_formats/juce_AiffAudioFormat.h" | |||
| #endif | |||
| #ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__ | |||
| #include "audio/audio_file_formats/juce_AudioCDBurner.h" | |||
| #endif | |||
| #ifndef __JUCE_AUDIOCDREADER_JUCEHEADER__ | |||
| #include "audio/audio_file_formats/juce_AudioCDReader.h" | |||
| #endif | |||
| #ifndef __JUCE_AUDIOFORMAT_JUCEHEADER__ | |||
| #include "audio/audio_file_formats/juce_AudioFormat.h" | |||
| #endif | |||
| @@ -215,14 +209,20 @@ | |||
| #ifndef __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ | |||
| #include "audio/audio_file_formats/juce_FlacAudioFormat.h" | |||
| #endif | |||
| #ifndef __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ | |||
| #include "audio/audio_file_formats/juce_WavAudioFormat.h" | |||
| #endif | |||
| #ifndef __JUCE_AUDIOCDREADER_JUCEHEADER__ | |||
| #include "audio/audio_file_formats/juce_AudioCDReader.h" | |||
| #endif | |||
| #ifndef __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ | |||
| #include "audio/audio_file_formats/juce_OggVorbisAudioFormat.h" | |||
| #endif | |||
| #ifndef __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ | |||
| #include "audio/audio_file_formats/juce_QuickTimeAudioFormat.h" | |||
| #endif | |||
| #ifndef __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ | |||
| #include "audio/audio_file_formats/juce_WavAudioFormat.h" | |||
| #ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__ | |||
| #include "audio/audio_file_formats/juce_AudioCDBurner.h" | |||
| #endif | |||
| #ifndef __JUCE_ACTIONBROADCASTER_JUCEHEADER__ | |||
| #include "events/juce_ActionBroadcaster.h" | |||
| @@ -269,21 +269,6 @@ | |||
| #ifndef __JUCE_TIMER_JUCEHEADER__ | |||
| #include "events/juce_Timer.h" | |||
| #endif | |||
| #ifndef __JUCE_BRUSH_JUCEHEADER__ | |||
| #include "gui/graphics/brushes/juce_Brush.h" | |||
| #endif | |||
| #ifndef __JUCE_GRADIENTBRUSH_JUCEHEADER__ | |||
| #include "gui/graphics/brushes/juce_GradientBrush.h" | |||
| #endif | |||
| #ifndef __JUCE_IMAGEBRUSH_JUCEHEADER__ | |||
| #include "gui/graphics/brushes/juce_ImageBrush.h" | |||
| #endif | |||
| #ifndef __JUCE_SOLIDCOLOURBRUSH_JUCEHEADER__ | |||
| #include "gui/graphics/brushes/juce_SolidColourBrush.h" | |||
| #endif | |||
| #ifndef __JUCE_PIXELFORMATS_JUCEHEADER__ | |||
| #include "gui/graphics/colour/juce_PixelFormats.h" | |||
| #endif | |||
| #ifndef __JUCE_COLOUR_JUCEHEADER__ | |||
| #include "gui/graphics/colour/juce_Colour.h" | |||
| #endif | |||
| @@ -293,41 +278,44 @@ | |||
| #ifndef __JUCE_COLOURGRADIENT_JUCEHEADER__ | |||
| #include "gui/graphics/colour/juce_ColourGradient.h" | |||
| #endif | |||
| #ifndef __JUCE_FONT_JUCEHEADER__ | |||
| #include "gui/graphics/fonts/juce_Font.h" | |||
| #ifndef __JUCE_PIXELFORMATS_JUCEHEADER__ | |||
| #include "gui/graphics/colour/juce_PixelFormats.h" | |||
| #endif | |||
| #ifndef __JUCE_TYPEFACE_JUCEHEADER__ | |||
| #include "gui/graphics/fonts/juce_Typeface.h" | |||
| #endif | |||
| #ifndef __JUCE_TEXTLAYOUT_JUCEHEADER__ | |||
| #include "gui/graphics/fonts/juce_TextLayout.h" | |||
| #endif | |||
| #ifndef __JUCE_TYPEFACE_JUCEHEADER__ | |||
| #include "gui/graphics/fonts/juce_Typeface.h" | |||
| #ifndef __JUCE_FONT_JUCEHEADER__ | |||
| #include "gui/graphics/fonts/juce_Font.h" | |||
| #endif | |||
| #ifndef __JUCE_GLYPHARRANGEMENT_JUCEHEADER__ | |||
| #include "gui/graphics/fonts/juce_GlyphArrangement.h" | |||
| #endif | |||
| #ifndef __JUCE_EDGETABLE_JUCEHEADER__ | |||
| #include "gui/graphics/contexts/juce_EdgeTable.h" | |||
| #ifndef __JUCE_GRAPHICS_JUCEHEADER__ | |||
| #include "gui/graphics/contexts/juce_Graphics.h" | |||
| #endif | |||
| #ifndef __JUCE_JUSTIFICATION_JUCEHEADER__ | |||
| #include "gui/graphics/contexts/juce_Justification.h" | |||
| #endif | |||
| #ifndef __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ | |||
| #include "gui/graphics/contexts/juce_RectanglePlacement.h" | |||
| #endif | |||
| #ifndef __JUCE_EDGETABLE_JUCEHEADER__ | |||
| #include "gui/graphics/contexts/juce_EdgeTable.h" | |||
| #endif | |||
| #ifndef __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__ | |||
| #include "gui/graphics/contexts/juce_LowLevelGraphicsContext.h" | |||
| #endif | |||
| #ifndef __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__ | |||
| #include "gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h" | |||
| #endif | |||
| #ifndef __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ | |||
| #include "gui/graphics/contexts/juce_RectanglePlacement.h" | |||
| #endif | |||
| #ifndef __JUCE_GRAPHICS_JUCEHEADER__ | |||
| #include "gui/graphics/contexts/juce_Graphics.h" | |||
| #endif | |||
| #ifndef __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__ | |||
| #include "gui/graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.h" | |||
| #endif | |||
| #ifndef __JUCE_AFFINETRANSFORM_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_AffineTransform.h" | |||
| #ifndef __JUCE_PATH_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_Path.h" | |||
| #endif | |||
| #ifndef __JUCE_BORDERSIZE_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_BorderSize.h" | |||
| @@ -335,36 +323,36 @@ | |||
| #ifndef __JUCE_LINE_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_Line.h" | |||
| #endif | |||
| #ifndef __JUCE_PATH_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_Path.h" | |||
| #ifndef __JUCE_POINT_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_Point.h" | |||
| #endif | |||
| #ifndef __JUCE_PATHITERATOR_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_PathIterator.h" | |||
| #ifndef __JUCE_RECTANGLE_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_Rectangle.h" | |||
| #endif | |||
| #ifndef __JUCE_PATHSTROKETYPE_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_PathStrokeType.h" | |||
| #endif | |||
| #ifndef __JUCE_POINT_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_Point.h" | |||
| #endif | |||
| #ifndef __JUCE_POSITIONEDRECTANGLE_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_PositionedRectangle.h" | |||
| #endif | |||
| #ifndef __JUCE_RECTANGLE_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_Rectangle.h" | |||
| #endif | |||
| #ifndef __JUCE_RECTANGLELIST_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_RectangleList.h" | |||
| #endif | |||
| #ifndef __JUCE_PATHITERATOR_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_PathIterator.h" | |||
| #endif | |||
| #ifndef __JUCE_AFFINETRANSFORM_JUCEHEADER__ | |||
| #include "gui/graphics/geometry/juce_AffineTransform.h" | |||
| #endif | |||
| #ifndef __JUCE_CAMERADEVICE_JUCEHEADER__ | |||
| #include "gui/graphics/imaging/juce_CameraDevice.h" | |||
| #endif | |||
| #ifndef __JUCE_IMAGE_JUCEHEADER__ | |||
| #include "gui/graphics/imaging/juce_Image.h" | |||
| #endif | |||
| #ifndef __JUCE_IMAGECACHE_JUCEHEADER__ | |||
| #include "gui/graphics/imaging/juce_ImageCache.h" | |||
| #endif | |||
| #ifndef __JUCE_IMAGE_JUCEHEADER__ | |||
| #include "gui/graphics/imaging/juce_Image.h" | |||
| #endif | |||
| #ifndef __JUCE_IMAGEFILEFORMAT_JUCEHEADER__ | |||
| #include "gui/graphics/imaging/juce_ImageFileFormat.h" | |||
| #endif | |||
| @@ -380,12 +368,12 @@ | |||
| #ifndef __JUCE_DRAWABLEIMAGE_JUCEHEADER__ | |||
| #include "gui/graphics/drawables/juce_DrawableImage.h" | |||
| #endif | |||
| #ifndef __JUCE_DRAWABLEPATH_JUCEHEADER__ | |||
| #include "gui/graphics/drawables/juce_DrawablePath.h" | |||
| #endif | |||
| #ifndef __JUCE_DRAWABLETEXT_JUCEHEADER__ | |||
| #include "gui/graphics/drawables/juce_DrawableText.h" | |||
| #endif | |||
| #ifndef __JUCE_DRAWABLEPATH_JUCEHEADER__ | |||
| #include "gui/graphics/drawables/juce_DrawablePath.h" | |||
| #endif | |||
| #ifndef __JUCE_COMPONENT_JUCEHEADER__ | |||
| #include "gui/components/juce_Component.h" | |||
| #endif | |||
| @@ -458,12 +446,12 @@ | |||
| #ifndef __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/code_editor/juce_CodeEditorComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_CODEDOCUMENT_JUCEHEADER__ | |||
| #include "gui/components/code_editor/juce_CodeDocument.h" | |||
| #endif | |||
| #ifndef __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__ | |||
| #include "gui/components/code_editor/juce_CPlusPlusCodeTokeniser.h" | |||
| #endif | |||
| #ifndef __JUCE_CODEDOCUMENT_JUCEHEADER__ | |||
| #include "gui/components/code_editor/juce_CodeDocument.h" | |||
| #endif | |||
| #ifndef __JUCE_CODETOKENISER_JUCEHEADER__ | |||
| #include "gui/components/code_editor/juce_CodeTokeniser.h" | |||
| #endif | |||
| @@ -545,12 +533,12 @@ | |||
| #ifndef __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__ | |||
| #include "gui/components/controls/juce_ToolbarItemPalette.h" | |||
| #endif | |||
| #ifndef __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/controls/juce_ToolbarItemComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_TREEVIEW_JUCEHEADER__ | |||
| #include "gui/components/controls/juce_TreeView.h" | |||
| #endif | |||
| #ifndef __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/controls/juce_ToolbarItemComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/properties/juce_BooleanPropertyComponent.h" | |||
| #endif | |||
| @@ -560,12 +548,12 @@ | |||
| #ifndef __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/properties/juce_ChoicePropertyComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_PROPERTYCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/properties/juce_PropertyComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_PROPERTYPANEL_JUCEHEADER__ | |||
| #include "gui/components/properties/juce_PropertyPanel.h" | |||
| #endif | |||
| #ifndef __JUCE_PROPERTYCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/properties/juce_PropertyComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/properties/juce_SliderPropertyComponent.h" | |||
| #endif | |||
| @@ -629,33 +617,33 @@ | |||
| #ifndef __JUCE_FILECHOOSER_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_FileChooser.h" | |||
| #endif | |||
| #ifndef __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_FileChooserDialogBox.h" | |||
| #endif | |||
| #ifndef __JUCE_FILEFILTER_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_FileFilter.h" | |||
| #endif | |||
| #ifndef __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_FileChooserDialogBox.h" | |||
| #endif | |||
| #ifndef __JUCE_FILELISTCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_FileListComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_FilePreviewComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_FileSearchPathListComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_FILETREECOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_FileTreeComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_FileSearchPathListComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_FILENAMECOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_FilenameComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_ImagePreviewComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_WILDCARDFILEFILTER_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_WildcardFileFilter.h" | |||
| #endif | |||
| #ifndef __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/filebrowser/juce_ImagePreviewComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_ALERTWINDOW_JUCEHEADER__ | |||
| #include "gui/components/windows/juce_AlertWindow.h" | |||
| #endif | |||
| @@ -716,12 +704,12 @@ | |||
| #ifndef __JUCE_PREFERENCESPANEL_JUCEHEADER__ | |||
| #include "gui/components/special/juce_PreferencesPanel.h" | |||
| #endif | |||
| #ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/special/juce_SystemTrayIconComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/special/juce_WebBrowserComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/special/juce_SystemTrayIconComponent.h" | |||
| #endif | |||
| #ifndef __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__ | |||
| #include "gui/components/special/juce_QuickTimeMovieComponent.h" | |||
| #endif | |||
| @@ -41,8 +41,8 @@ | |||
| #ifndef __JUCE_LOGGER_JUCEHEADER__ | |||
| #include "core/juce_Logger.h" | |||
| #endif | |||
| #ifndef __JUCE_MATHSFUNCTIONS_JUCEHEADER__ | |||
| #include "core/juce_MathsFunctions.h" | |||
| #ifndef __JUCE_PLATFORMUTILITIES_JUCEHEADER__ | |||
| #include "core/juce_PlatformUtilities.h" | |||
| #endif | |||
| #ifndef __JUCE_MEMORY_JUCEHEADER__ | |||
| #include "core/juce_Memory.h" | |||
| @@ -53,8 +53,8 @@ | |||
| #ifndef __JUCE_PLATFORMDEFS_JUCEHEADER__ | |||
| #include "core/juce_PlatformDefs.h" | |||
| #endif | |||
| #ifndef __JUCE_PLATFORMUTILITIES_JUCEHEADER__ | |||
| #include "core/juce_PlatformUtilities.h" | |||
| #ifndef __JUCE_SINGLETON_JUCEHEADER__ | |||
| #include "core/juce_Singleton.h" | |||
| #endif | |||
| #ifndef __JUCE_RANDOM_JUCEHEADER__ | |||
| #include "core/juce_Random.h" | |||
| @@ -62,24 +62,24 @@ | |||
| #ifndef __JUCE_RELATIVETIME_JUCEHEADER__ | |||
| #include "core/juce_RelativeTime.h" | |||
| #endif | |||
| #ifndef __JUCE_SINGLETON_JUCEHEADER__ | |||
| #include "core/juce_Singleton.h" | |||
| #endif | |||
| #ifndef __JUCE_STANDARDHEADER_JUCEHEADER__ | |||
| #include "core/juce_StandardHeader.h" | |||
| #endif | |||
| #ifndef __JUCE_SYSTEMSTATS_JUCEHEADER__ | |||
| #include "core/juce_SystemStats.h" | |||
| #endif | |||
| #ifndef __JUCE_TARGETPLATFORM_JUCEHEADER__ | |||
| #include "core/juce_TargetPlatform.h" | |||
| #endif | |||
| #ifndef __JUCE_TIME_JUCEHEADER__ | |||
| #include "core/juce_Time.h" | |||
| #endif | |||
| #ifndef __JUCE_UUID_JUCEHEADER__ | |||
| #include "core/juce_Uuid.h" | |||
| #endif | |||
| #ifndef __JUCE_STANDARDHEADER_JUCEHEADER__ | |||
| #include "core/juce_StandardHeader.h" | |||
| #endif | |||
| #ifndef __JUCE_MATHSFUNCTIONS_JUCEHEADER__ | |||
| #include "core/juce_MathsFunctions.h" | |||
| #endif | |||
| #ifndef __JUCE_TARGETPLATFORM_JUCEHEADER__ | |||
| #include "core/juce_TargetPlatform.h" | |||
| #endif | |||
| #ifndef __JUCE_ARRAY_JUCEHEADER__ | |||
| #include "containers/juce_Array.h" | |||
| #endif | |||
| @@ -236,14 +236,14 @@ | |||
| #ifndef __JUCE_THREAD_JUCEHEADER__ | |||
| #include "threads/juce_Thread.h" | |||
| #endif | |||
| #ifndef __JUCE_THREADPOOL_JUCEHEADER__ | |||
| #include "threads/juce_ThreadPool.h" | |||
| #endif | |||
| #ifndef __JUCE_TIMESLICETHREAD_JUCEHEADER__ | |||
| #include "threads/juce_TimeSliceThread.h" | |||
| #endif | |||
| #ifndef __JUCE_WAITABLEEVENT_JUCEHEADER__ | |||
| #include "threads/juce_WaitableEvent.h" | |||
| #endif | |||
| #ifndef __JUCE_THREADPOOL_JUCEHEADER__ | |||
| #include "threads/juce_ThreadPool.h" | |||
| #endif | |||
| #endif | |||
| @@ -73,7 +73,9 @@ class CoreGraphicsContext : public LowLevelGraphicsContext | |||
| public: | |||
| CoreGraphicsContext (CGContextRef context_, const float flipHeight_) | |||
| : context (context_), | |||
| flipHeight (flipHeight_) | |||
| flipHeight (flipHeight_), | |||
| gradientLookupTable (0), | |||
| numGradientLookupEntries (0) | |||
| { | |||
| CGContextRetain (context); | |||
| CGContextSetShouldSmoothFonts (context, true); | |||
| @@ -93,6 +95,7 @@ public: | |||
| CGColorSpaceRelease (rgbColourSpace); | |||
| CGColorSpaceRelease (greyColourSpace); | |||
| delete state; | |||
| delete gradientLookupTable; | |||
| } | |||
| //============================================================================== | |||
| @@ -103,13 +106,13 @@ public: | |||
| CGContextTranslateCTM (context, x, -y); | |||
| } | |||
| bool reduceClipRegion (int x, int y, int w, int h) | |||
| bool clipToRectangle (const Rectangle& r) | |||
| { | |||
| CGContextClipToRect (context, CGRectMake (x, flipHeight - (y + h), w, h)); | |||
| CGContextClipToRect (context, CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight())); | |||
| return ! isClipEmpty(); | |||
| } | |||
| bool reduceClipRegion (const RectangleList& clipRegion) | |||
| bool clipToRectangleList (const RectangleList& clipRegion) | |||
| { | |||
| const int numRects = clipRegion.getNumRectangles(); | |||
| CGRect* const rects = new CGRect [numRects]; | |||
| @@ -125,40 +128,44 @@ public: | |||
| return ! isClipEmpty(); | |||
| } | |||
| void excludeClipRegion (int x, int y, int w, int h) | |||
| void excludeClipRectangle (const Rectangle& r) | |||
| { | |||
| RectangleList r (getClipBounds()); | |||
| r.subtract (Rectangle (x, y, w, h)); | |||
| reduceClipRegion (r); | |||
| RectangleList remaining (getClipBounds()); | |||
| remaining.subtract (r); | |||
| clipToRectangleList (remaining); | |||
| } | |||
| void saveState() | |||
| void clipToPath (const Path& path, const AffineTransform& transform) | |||
| { | |||
| CGContextSaveGState (context); | |||
| stateStack.add (new SavedState (*state)); | |||
| createPath (path, transform); | |||
| CGContextClip (context); | |||
| } | |||
| void restoreState() | |||
| void clipToImageAlpha (const Image& sourceImage, const Rectangle& srcClip, const AffineTransform& transform) | |||
| { | |||
| CGContextRestoreGState (context); | |||
| if (! transform.isSingularity()) | |||
| { | |||
| Image* singleChannelImage = createAlphaChannelImage (sourceImage); | |||
| CGImageRef image = createImage (*singleChannelImage, true); | |||
| SavedState* const top = stateStack.getLast(); | |||
| flip(); | |||
| AffineTransform t (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform)); | |||
| applyTransform (t); | |||
| if (top != 0) | |||
| { | |||
| delete state; | |||
| state = top; | |||
| stateStack.removeLast (1, false); | |||
| } | |||
| else | |||
| { | |||
| jassertfalse // trying to pop with an empty stack! | |||
| CGRect r = CGRectMake (0, 0, sourceImage.getWidth(), sourceImage.getHeight()); | |||
| CGContextClipToMask (context, r, image); | |||
| applyTransform (t.inverted()); | |||
| flip(); | |||
| CGImageRelease (image); | |||
| deleteAlphaChannelImage (sourceImage, singleChannelImage); | |||
| } | |||
| } | |||
| bool clipRegionIntersects (int x, int y, int w, int h) | |||
| bool clipRegionIntersects (const Rectangle& r) | |||
| { | |||
| return getClipBounds().intersects (Rectangle (x, y, w, h)); | |||
| return getClipBounds().intersects (r); | |||
| } | |||
| const Rectangle getClipBounds() const | |||
| @@ -176,11 +183,35 @@ public: | |||
| return CGRectIsEmpty (CGContextGetClipBoundingBox (context)); | |||
| } | |||
| //============================================================================== | |||
| void saveState() | |||
| { | |||
| CGContextSaveGState (context); | |||
| stateStack.add (new SavedState (*state)); | |||
| } | |||
| void restoreState() | |||
| { | |||
| CGContextRestoreGState (context); | |||
| SavedState* const top = stateStack.getLast(); | |||
| if (top != 0) | |||
| { | |||
| delete state; | |||
| state = top; | |||
| stateStack.removeLast (1, false); | |||
| } | |||
| else | |||
| { | |||
| jassertfalse // trying to pop with an empty stack! | |||
| } | |||
| } | |||
| //============================================================================== | |||
| void setColour (const Colour& colour) | |||
| { | |||
| state->colour = colour; | |||
| deleteAndZero (state->gradient); | |||
| state->fillType.setColour (colour); | |||
| CGContextSetRGBFillColor (context, | |||
| colour.getFloatRed(), colour.getFloatGreen(), | |||
| @@ -190,15 +221,17 @@ public: | |||
| void setGradient (const ColourGradient& gradient) | |||
| { | |||
| if (state->gradient == 0) | |||
| state->gradient = new ColourGradient (gradient); | |||
| else | |||
| *state->gradient = gradient; | |||
| state->fillType.setGradient (gradient); | |||
| } | |||
| void setTiledFill (const Image& image, int x, int y) | |||
| { | |||
| state->fillType.setTiledImage (image, x, y); | |||
| } | |||
| void setOpacity (float opacity) | |||
| { | |||
| setColour (state->colour.withAlpha (opacity)); | |||
| state->fillType.colour = state->fillType.colour.withAlpha (opacity); | |||
| } | |||
| void setInterpolationQuality (Graphics::ResamplingQuality quality) | |||
| @@ -209,38 +242,48 @@ public: | |||
| } | |||
| //============================================================================== | |||
| void fillRect (int x, int y, int w, int h, const bool replaceExistingContents) | |||
| void fillRect (const Rectangle& r, const bool replaceExistingContents) | |||
| { | |||
| CGRect cgRect = CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()); | |||
| if (replaceExistingContents) | |||
| { | |||
| #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 | |||
| CGContextClearRect (context, CGRectMake (x, y, w, h)); | |||
| CGContextClearRect (context, cgRect); | |||
| #else | |||
| #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 | |||
| if (CGContextDrawLinearGradient == 0) // (just a way of checking whether we're running in 10.5 or later) | |||
| CGContextClearRect (context, CGRectMake (x, y, w, h)); | |||
| CGContextClearRect (context, cgRect); | |||
| else | |||
| #endif | |||
| CGContextSetBlendMode (context, kCGBlendModeCopy); | |||
| #endif | |||
| fillRect (x, y, w, h, false); | |||
| fillRect (r, false); | |||
| CGContextSetBlendMode (context, kCGBlendModeNormal); | |||
| } | |||
| else | |||
| { | |||
| if (state->gradient == 0) | |||
| if (state->fillType.isColour()) | |||
| { | |||
| CGContextFillRect (context, CGRectMake (x, flipHeight - (y + h), w, h)); | |||
| CGContextFillRect (context, cgRect); | |||
| } | |||
| else | |||
| else if (state->fillType.isGradient()) | |||
| { | |||
| CGContextSaveGState (context); | |||
| CGContextClipToRect (context, CGRectMake (x, flipHeight - (y + h), w, h)); | |||
| CGContextClipToRect (context, cgRect); | |||
| flip(); | |||
| drawGradient(); | |||
| CGContextRestoreGState (context); | |||
| } | |||
| else | |||
| { | |||
| CGContextSaveGState (context); | |||
| CGContextClipToRect (context, cgRect); | |||
| drawImage (*(state->fillType.image), Rectangle (0, 0, state->fillType.image->getWidth(), state->fillType.image->getHeight()), | |||
| AffineTransform::translation (state->fillType.imageX, state->fillType.imageY), true); | |||
| CGContextRestoreGState (context); | |||
| } | |||
| } | |||
| } | |||
| @@ -248,7 +291,7 @@ public: | |||
| { | |||
| CGContextSaveGState (context); | |||
| if (state->gradient == 0) | |||
| if (state->fillType.isColour()) | |||
| { | |||
| flip(); | |||
| applyTransform (transform); | |||
| @@ -259,102 +302,78 @@ public: | |||
| else | |||
| CGContextEOFillPath (context); | |||
| } | |||
| else | |||
| else if (state->fillType.isGradient()) | |||
| { | |||
| createPath (path, transform); | |||
| CGContextClip (context); | |||
| flip(); | |||
| applyTransform (state->gradient->transform); | |||
| applyTransform (state->fillType.gradient->transform); | |||
| drawGradient(); | |||
| } | |||
| else | |||
| { | |||
| createPath (path, transform); | |||
| CGContextClip (context); | |||
| drawImage (*(state->fillType.image), Rectangle (0, 0, state->fillType.image->getWidth(), state->fillType.image->getHeight()), | |||
| AffineTransform::translation (state->fillType.imageX, state->fillType.imageY), true); | |||
| } | |||
| CGContextRestoreGState (context); | |||
| } | |||
| void fillPathWithImage (const Path& path, const AffineTransform& transform, | |||
| const Image& image, int imageX, int imageY) | |||
| { | |||
| CGContextSaveGState (context); | |||
| createPath (path, transform); | |||
| CGContextClip (context); | |||
| blendImage (image, imageX, imageY, image.getWidth(), image.getHeight(), 0, 0); | |||
| CGContextRestoreGState (context); | |||
| } | |||
| void fillAlphaChannel (const Image& alphaImage, int alphaImageX, int alphaImageY) | |||
| { | |||
| Image* singleChannelImage = createAlphaChannelImage (alphaImage); | |||
| CGImageRef image = createImage (*singleChannelImage, true); | |||
| CGContextSaveGState (context); | |||
| CGContextSetAlpha (context, 1.0f); | |||
| CGRect r = CGRectMake (alphaImageX, flipHeight - (alphaImageY + alphaImage.getHeight()), | |||
| alphaImage.getWidth(), alphaImage.getHeight()); | |||
| CGContextClipToMask (context, r, image); | |||
| fillRect (alphaImageX, alphaImageY, alphaImage.getWidth(), alphaImage.getHeight(), false); | |||
| CGContextRestoreGState (context); | |||
| CGImageRelease (image); | |||
| deleteAlphaChannelImage (alphaImage, singleChannelImage); | |||
| } | |||
| void fillAlphaChannelWithImage (const Image& alphaImage, int alphaImageX, int alphaImageY, | |||
| const Image& fillerImage, int fillerImageX, int fillerImageY) | |||
| void drawImage (const Image& sourceImage, const Rectangle& srcClip, | |||
| const AffineTransform& transform, const bool fillEntireClipAsTiles) | |||
| { | |||
| Image* singleChannelImage = createAlphaChannelImage (alphaImage); | |||
| CGImageRef image = createImage (*singleChannelImage, true); | |||
| CGImageRef fullImage = createImage (sourceImage, false); | |||
| CGImageRef image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClip.getX(), sourceImage.getHeight() - srcClip.getBottom(), | |||
| srcClip.getWidth(), srcClip.getHeight())); | |||
| CGImageRelease (fullImage); | |||
| CGContextSaveGState (context); | |||
| CGRect r = CGRectMake (alphaImageX, flipHeight - (alphaImageY + alphaImage.getHeight()), | |||
| alphaImage.getWidth(), alphaImage.getHeight()); | |||
| CGContextClipToMask (context, r, image); | |||
| blendImage (fillerImage, fillerImageX, fillerImageY, | |||
| fillerImage.getWidth(), fillerImage.getHeight(), | |||
| 0, 0); | |||
| CGContextSetAlpha (context, state->fillType.colour.getFloatAlpha()); | |||
| CGContextRestoreGState (context); | |||
| flip(); | |||
| applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform)); | |||
| CGRect imageRect = CGRectMake (0, 0, sourceImage.getWidth(), sourceImage.getHeight()); | |||
| CGImageRelease (image); | |||
| deleteAlphaChannelImage (alphaImage, singleChannelImage); | |||
| } | |||
| if (fillEntireClipAsTiles) | |||
| { | |||
| #if JUCE_IPHONE || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5) | |||
| CGContextDrawTiledImage (context, imageRect, image); | |||
| #else | |||
| #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 | |||
| if (CGContextDrawTiledImage != 0) | |||
| CGContextDrawTiledImage (context, imageRect, image); | |||
| else | |||
| #endif | |||
| { | |||
| // Fallback to manually doing a tiled fill on 10.4 | |||
| CGRect clip = CGRectIntegral (CGContextGetClipBoundingBox (context)); | |||
| const int iw = sourceImage.getWidth(); | |||
| const int ih = sourceImage.getHeight(); | |||
| //============================================================================== | |||
| void blendImage (const Image& sourceImage, | |||
| int destX, int destY, int destW, int destH, int sourceX, int sourceY) | |||
| { | |||
| CGImageRef image = createImage (sourceImage, false); | |||
| int x = 0, y = 0; | |||
| while (x > clip.origin.x) x -= iw; | |||
| while (y > clip.origin.y) y -= ih; | |||
| CGContextSaveGState (context); | |||
| CGContextClipToRect (context, CGRectMake (destX, flipHeight - (destY + destH), destW, destH)); | |||
| CGContextSetAlpha (context, state->colour.getFloatAlpha()); | |||
| CGContextDrawImage (context, CGRectMake (destX - sourceX, | |||
| flipHeight - ((destY - sourceY) + sourceImage.getHeight()), | |||
| sourceImage.getWidth(), | |||
| sourceImage.getHeight()), image); | |||
| const int right = clip.origin.x + clip.size.width; | |||
| const int bottom = clip.origin.y + clip.size.height; | |||
| CGContextRestoreGState (context); | |||
| CGImageRelease (image); | |||
| } | |||
| while (y < bottom) | |||
| { | |||
| for (int x2 = x; x2 < right; x2 += iw) | |||
| CGContextDrawImage (context, CGRectMake (x2, y, iw, ih), image); | |||
| void blendImageWarping (const Image& sourceImage, | |||
| int srcClipX, int srcClipY, int srcClipW, int srcClipH, | |||
| const AffineTransform& transform) | |||
| { | |||
| CGImageRef fullImage = createImage (sourceImage, false); | |||
| CGImageRef image = CGImageCreateWithImageInRect (fullImage, CGRectMake (srcClipX, sourceImage.getHeight() - (srcClipY + srcClipH), | |||
| srcClipW, srcClipH)); | |||
| CGImageRelease (fullImage); | |||
| CGContextSaveGState (context); | |||
| flip(); | |||
| applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform)); | |||
| CGContextSetAlpha (context, state->colour.getFloatAlpha()); | |||
| CGContextDrawImage (context, CGRectMake (0, 0, sourceImage.getWidth(), | |||
| sourceImage.getHeight()), image); | |||
| y += ih; | |||
| } | |||
| } | |||
| #endif | |||
| } | |||
| else | |||
| { | |||
| CGContextDrawImage (context, imageRect, image); | |||
| } | |||
| CGImageRelease (image); | |||
| CGContextRestoreGState (context); | |||
| @@ -366,8 +385,8 @@ public: | |||
| CGContextSetLineCap (context, kCGLineCapSquare); | |||
| CGContextSetLineWidth (context, 1.0f); | |||
| CGContextSetRGBStrokeColor (context, | |||
| state->colour.getFloatRed(), state->colour.getFloatGreen(), | |||
| state->colour.getFloatBlue(), state->colour.getFloatAlpha()); | |||
| state->fillType.colour.getFloatRed(), state->fillType.colour.getFloatGreen(), | |||
| state->fillType.colour.getFloatBlue(), state->fillType.colour.getFloatAlpha()); | |||
| CGPoint line[] = { { x1 + 0.5f, flipHeight - (y1 + 0.5f) }, | |||
| { x2 + 0.5f, flipHeight - (y2 + 0.5f) } }; | |||
| @@ -407,40 +426,46 @@ public: | |||
| } | |||
| } | |||
| void drawGlyph (int glyphNumber, float x, float y) | |||
| const Font getFont() | |||
| { | |||
| if (state->fontRef != 0 && state->gradient == 0) | |||
| { | |||
| CGGlyph g = glyphNumber; | |||
| CGContextShowGlyphsAtPoint (context, x, flipHeight - roundFloatToInt (y), &g, 1); | |||
| } | |||
| else | |||
| { | |||
| state->font.renderGlyphIndirectly (*this, glyphNumber, x, y); | |||
| } | |||
| return state->font; | |||
| } | |||
| void drawGlyph (int glyphNumber, const AffineTransform& transform) | |||
| { | |||
| if (state->fontRef != 0) | |||
| if (state->fontRef != 0 && state->fillType.isColour()) | |||
| { | |||
| CGContextSaveGState (context); | |||
| flip(); | |||
| applyTransform (transform); | |||
| if (transform.isOnlyTranslation()) | |||
| { | |||
| CGGlyph g = glyphNumber; | |||
| CGContextShowGlyphsAtPoint (context, transform.getTranslationX(), | |||
| flipHeight - roundFloatToInt (transform.getTranslationY()), &g, 1); | |||
| } | |||
| else | |||
| { | |||
| CGContextSaveGState (context); | |||
| flip(); | |||
| applyTransform (transform); | |||
| CGAffineTransform t = state->fontTransform; | |||
| t.d = -t.d; | |||
| CGContextSetTextMatrix (context, t); | |||
| CGAffineTransform t = state->fontTransform; | |||
| t.d = -t.d; | |||
| CGContextSetTextMatrix (context, t); | |||
| CGGlyph g = glyphNumber; | |||
| CGContextShowGlyphsAtPoint (context, 0, 0, &g, 1); | |||
| CGGlyph g = glyphNumber; | |||
| CGContextShowGlyphsAtPoint (context, 0, 0, &g, 1); | |||
| CGContextSetTextMatrix (context, state->fontTransform); | |||
| CGContextRestoreGState (context); | |||
| CGContextSetTextMatrix (context, state->fontTransform); | |||
| CGContextRestoreGState (context); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| state->font.renderGlyphIndirectly (*this, glyphNumber, transform); | |||
| Path p; | |||
| Font& f = state->font; | |||
| f.getTypeface()->getOutlineForGlyph (glyphNumber, p); | |||
| fillPath (p, AffineTransform::scale (f.getHeight() * f.getHorizontalScale(), f.getHeight()) | |||
| .followedBy (transform)); | |||
| } | |||
| } | |||
| @@ -453,26 +478,21 @@ private: | |||
| struct SavedState | |||
| { | |||
| SavedState() throw() | |||
| : gradient (0), font (1.0f), fontRef (0), | |||
| fontTransform (CGAffineTransformIdentity) | |||
| : font (1.0f), fontRef (0), fontTransform (CGAffineTransformIdentity) | |||
| { | |||
| } | |||
| SavedState (const SavedState& other) throw() | |||
| : colour (other.colour), | |||
| gradient (other.gradient != 0 ? new ColourGradient (*other.gradient) : 0), | |||
| font (other.font), fontRef (other.fontRef), | |||
| : fillType (other.fillType), font (other.font), fontRef (other.fontRef), | |||
| fontTransform (other.fontTransform) | |||
| { | |||
| } | |||
| ~SavedState() throw() | |||
| { | |||
| delete gradient; | |||
| } | |||
| Colour colour; | |||
| ColourGradient* gradient; | |||
| Graphics::FillType fillType; | |||
| Font font; | |||
| CGFontRef fontRef; | |||
| CGAffineTransform fontTransform; | |||
| @@ -480,21 +500,31 @@ private: | |||
| SavedState* state; | |||
| OwnedArray <SavedState> stateStack; | |||
| PixelARGB* gradientLookupTable; | |||
| int numGradientLookupEntries; | |||
| static void gradientCallback (void* info, const CGFloat* inData, CGFloat* outData) | |||
| { | |||
| const ColourGradient* const g = (const ColourGradient*) info; | |||
| const Colour c (g->getColourAtPosition (inData[0])); | |||
| outData[0] = c.getFloatRed(); | |||
| outData[1] = c.getFloatGreen(); | |||
| outData[2] = c.getFloatBlue(); | |||
| outData[3] = c.getFloatAlpha(); | |||
| const CoreGraphicsContext* const g = (const CoreGraphicsContext*) info; | |||
| const int index = roundFloatToInt (g->numGradientLookupEntries * inData[0]); | |||
| PixelARGB colour (g->gradientLookupTable [jlimit (0, g->numGradientLookupEntries, index)]); | |||
| colour.unpremultiply(); | |||
| outData[0] = colour.getRed() / 255.0f; | |||
| outData[1] = colour.getGreen() / 255.0f; | |||
| outData[2] = colour.getBlue() / 255.0f; | |||
| outData[3] = colour.getAlpha() / 255.0f; | |||
| } | |||
| CGShadingRef createGradient (const ColourGradient* const gradient) const throw() | |||
| CGShadingRef createGradient (const ColourGradient* const gradient) throw() | |||
| { | |||
| delete gradientLookupTable; | |||
| gradientLookupTable = gradient->createLookupTable (numGradientLookupEntries); | |||
| --numGradientLookupEntries; | |||
| CGShadingRef result = 0; | |||
| CGFunctionRef function = CGFunctionCreate ((void*) gradient, 1, 0, 4, 0, &gradientCallbacks); | |||
| CGFunctionRef function = CGFunctionCreate ((void*) this, 1, 0, 4, 0, &gradientCallbacks); | |||
| CGPoint p1 (CGPointMake (gradient->x1, gradient->y1)); | |||
| if (gradient->isRadial) | |||
| @@ -514,12 +544,12 @@ private: | |||
| return result; | |||
| } | |||
| void drawGradient() const throw() | |||
| void drawGradient() throw() | |||
| { | |||
| CGContextSetAlpha (context, 1.0f); | |||
| CGContextSetInterpolationQuality (context, kCGInterpolationDefault); // (This is required for 10.4, where there's a crash if | |||
| // you draw a gradient with high quality interp enabled). | |||
| CGShadingRef shading = createGradient (state->gradient); | |||
| CGShadingRef shading = createGradient (state->fillType.gradient); | |||
| CGContextDrawShading (context, shading); | |||
| CGShadingRelease (shading); | |||
| } | |||
| @@ -409,7 +409,7 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | |||
| if (e != 0 && ! isEventBlockedByModalComps (e)) | |||
| [NSApp sendEvent: e]; | |||
| if (Time::getMillisecondCounter() >= endTime) | |||
| break; | |||
| } | |||
| @@ -1471,7 +1471,7 @@ void NSViewComponentPeer::drawRect (NSRect r) | |||
| roundFloatToInt (rects[i].size.height))); | |||
| } | |||
| if (context.reduceClipRegion (clip)) | |||
| if (context.clipToRectangleList (clip)) | |||
| { | |||
| insideDrawRect = true; | |||
| handlePaint (context); | |||
| @@ -35,7 +35,7 @@ | |||
| #include "../../core/juce_StandardHeader.h" | |||
| #define USE_COREGRAPHICS_RENDERING 0 | |||
| #define USE_COREGRAPHICS_RENDERING 1 | |||
| #if JUCE_IPHONE | |||
| #import <Foundation/Foundation.h> | |||
| @@ -1253,7 +1253,7 @@ private: | |||
| updateCurrentModifiers(); | |||
| LowLevelGraphicsSoftwareRenderer context (*offscreenImage); | |||
| context.reduceClipRegion (contextClip); | |||
| context.clipToRectangleList (contextClip); | |||
| context.setOrigin (-x, -y); | |||
| handlePaint (context); | |||