Best way to generate a rendering in a DLL


#1

Hi all,

What’s the best way to generate a rendered “picture” in a DLL ?
I have an application that needs to display something that comes for a plugin (living in a DLL).
At first, I thought about putting a “renderData” method in the plugin.
However, the renderData will have to take a “Graphic” or a “Image” object to render onto, but this mean that the plugin will have to be recompiled everytime I update the Juce repo in the main application (as the Graphic or Image interface might have changed).

This also means that the plugin must be build with Juce linked in.
All plugins will then be 3 or 4MB larger than expected.

I haven’t found a “clean” way to do this.
Up to now, I’ve thought of:
[list]
[] Building Juce as a DLL in both code, so the Juce code segment isn’t duplicated in memory, but this still breaks when whatever side update its repository[/]
[] Writing a wrapper for the Graphic / Image class, that I’d give to the plugin, so it’s wrapper code that takes charge of being up to date. However this solution is a really, really boring task, and it doesn’t prevent the plugin to embed its own Juce code segment, still wasting space[/]
[] Giving the plugin a “byte * imageData, int width, int height” parameter and let the plugin writer deal with this (with all the issues this will create) [/][/list]

How do you solve this task ?


#2

Yes, I guess that’s c++ for you. Personally I’d probably go for the shared DLL approach, but there’s no easy trick that I can think of.


#3

I’ve had a look to the Graphic class, and it’s not that big.
The dependencies are on Font (which is a small class), Colour (small), Image (quite big in fact), and Path (quite big to), and AffineTransform (useless for me ?)

Maybe I’ll try to merge both ideas (wrapper + DLL) so it solves the duplicate code segment issue, and the difference code base issues too.

How do you deal with the VST plugins ?
Does each plugin embed its own Juce lib as static ?


#4

Yes, VSTs are all independent modules. I guess if you were building a bunch of them, you could use a shared DLL for them all.


#5

Ok, I’ve done it.

For those interested, I’ve wrapped all the Juce graphic stuff as clean pure virtual interface, that can be given to any plugin (even without Juce inside).

So any code can draw on a Juce graphic object without even knowing it’s Juce underneath.

This solves the Juce dependency for only graphic stuff, and also make the plugin independant from the used Juce version in the application.

If you are interested, I’ll share it.

I still have a question, how does it deal with the license ?
I know I can’t enforce GPL for the plugin, but giving pure virtual interfaces (I’ve rewritten them all) does imply GPLization of the plugin ?
From what I’ve read so far, I don’t think so (after all, they are a lot of commercial VST that could run in the juce’s audio demo), but I prefer make sure.


#6

Sounds interesting.

[quote]I still have a question, how does it deal with the license ?
I know I can’t enforce GPL for the plugin, but giving pure virtual interfaces (I’ve rewritten them all) does imply GPLization of the plugin ?
From what I’ve read so far, I don’t think so (after all, they are a lot of commercial VST that could run in the juce’s audio demo), but I prefer make sure.[/quote]

well you wrote the code, so you can choose to let people use it however you want. You could LGPL it, GPL it, or whatever seems like a good idea…


#7

The shared declaration:

namespace TwoDimensionalRendering
{
    /** Used for colours */
//    typedef unsigned char uint8;
//    typedef unsigned int  uint32;

// Whatever string class you're using for exchange
    typedef Strings::FastString String;

    /** This is a wrapper of Juce's AffineTransform class, used to allow different Juce code base in the same software */
    struct AffineTransform
    {
        /** Transform the given point */
        virtual void 	transformPoint (double & x, double & y) const = 0;
        /** Get the translated transform for this object */
        virtual const AffineTransform 	* translated (const float deltaX, const float deltaY) const = 0;
        /** Get the rotated transform for this object */
        virtual const AffineTransform   * rotated (const float angleInRadians) const = 0;
        /** Get the rotated transform for this object around the given pivot */
        virtual const AffineTransform 	* rotated (const float angleInRadians, const float pivotX, const float pivotY) const = 0;
        /** Get the scaled transform for this object */
        virtual const AffineTransform 	* scaled (const float factorX, const float factorY) const = 0;
        /** Get the sheared transform for this object */
        virtual const AffineTransform 	* sheared (const float shearX, const float shearY) const = 0;
        /** Get the inverse matrix of this one */
        virtual const AffineTransform 	* inverted () const = 0;
        /** Get the result of the two transformation */
        virtual const AffineTransform 	* followedBy (const AffineTransform & other) const = 0;
        /** Check if this transform is an identity matrix */
        virtual bool 	isIdentity () const throw () = 0;
        /** Check if this transform is a singularity matrix */
        virtual bool 	isSingularity () const throw () = 0;
    };

    /** This is a factory used to create transforms.
        @warning You must call deleteTransform for each pointer returned. 
                 This is because the memory tracking tools can be confused with heap allocated in a code segment and deallocated in another segment. */
    struct AffineTransformFactory
    {
        virtual const AffineTransform *	createIdentity () const = 0;
        virtual const AffineTransform *	createTranslation (const float deltaX, const float deltaY) const = 0;
        virtual const AffineTransform *	createRotation (const float angleInRadians) const = 0;
        virtual const AffineTransform *	createRotation (const float angleInRadians, const float pivotX, const float pivotY) const = 0;
        virtual const AffineTransform *	createScale (const float factorX, const float factorY) const = 0;
        virtual void deleteTransform (const AffineTransform * transform) const = 0;
    };



    /** This class is a wrapper of the Juce Path class.
        This is used to simplify different Juce code base in the same process.
        */
    struct Path
    {
        /** Check if the path is currently empty */
        virtual bool 	isEmpty () const throw () = 0;
        /** Get the bounds for this path */
        virtual void 	getBounds (float & x, float & y, float & w, float & h) const throw () = 0;
        /** Get the bounds after the given transformation */
        virtual void 	getBoundsTransformed (const AffineTransform & transform, float & x, float & y, float & w, float & h) const throw () = 0;
        /** Return true if the path contains the given point */
        virtual bool 	contains (const float x, const float y) const throw () = 0;
        /** Return true if the path intersect the given line */
        virtual bool 	intersectsLine (const float x1, const float y1, const float x2, const float y2) throw () = 0;
        /** Clear this path */
        virtual void 	clear () throw () = 0;
        /** Start new sub path at the given position */
        virtual void 	startNewSubPath (const float startX, const float startY) throw () = 0;
        /** Close the sub path */
        virtual void 	closeSubPath () throw () = 0;
        /** Append a line segment from the current position to the given position */
        virtual void 	lineTo (const float endX, const float endY) throw () = 0;
        /** Append a quadratic curve from the current position to the given position */
        virtual void 	quadraticTo (const float controlPointX, const float controlPointY, const float endPointX, const float endPointY) throw () = 0;
        /** Append a Bezier curve from the current position to the given position */
        virtual void 	cubicTo (const float controlPoint1X, const float controlPoint1Y, const float controlPoint2X, const float controlPoint2Y, const float endPointX, const float endPointY) throw () = 0;
        /** Get the current position */
        virtual void 	getCurrentPosition (float & x, float & y) const throw () = 0;
        /** Add a rectangle as a sub path */
        virtual void 	addRectangle (const float x, const float y, const float w, const float h) throw () = 0;
        /** Add a rectangle with rounded corner as a sub path */
        virtual void 	addRoundedRectangle (const float x, const float y, const float w, const float h, float cornerSizeX, float cornerSizeY) throw () = 0;
        /** Add a triangle as a sub path */
        virtual void 	addTriangle (const float x1, const float y1, const float x2, const float y2, const float x3, const float y3) throw () = 0;
        /** Add a quadrilateral as a sub path */
        virtual void 	addQuadrilateral (const float x1, const float y1, const float x2, const float y2, const float x3, const float y3, const float x4, const float y4) throw () = 0;
        /** Add an ellipse as a sub path */
        virtual void 	addEllipse (const float x, const float y, const float width, const float height) throw () = 0;
        /** Add an arc as a sub path */
        virtual void 	addArc (const float x, const float y, const float width, const float height, const float fromRadians, const float toRadians, const bool startAsNewSubPath=false) throw () = 0;
        /** Add a centred arc as a sub path */
        virtual void 	addCentredArc (const float centreX, const float centreY, const float radiusX, const float radiusY, const float rotationOfEllipse, const float fromRadians, const float toRadians, const bool startAsNewSubPath=false) throw () = 0;
        /** Add a pie segment as a sub path */
        virtual void 	addPieSegment (const float x, const float y, const float width, const float height, const float fromRadians, const float toRadians, const float innerCircleProportionalSize) = 0;
        /** Add a line segment as a sub path */
        virtual void 	addLineSegment (const float startX, const float startY, const float endX, const float endY, float lineThickness) throw () = 0;
        /** Add an arrow as a sub path */
        virtual void 	addArrow (const float startX, const float startY, const float endX, const float endY, float lineThickness, float arrowheadWidth, float arrowheadLength) throw () = 0;
        /** Add a star as a sub path */
        virtual void 	addStar (const float centreX, const float centreY, const int numberOfPoints, const float innerRadius, const float outerRadius, const float startAngle=0.0f) = 0;
        /** Add a bubble as a sub path */
        virtual void 	addBubble (float bodyX, float bodyY, float bodyW, float bodyH, float cornerSize, float arrowTipX, float arrowTipY, int whichSide, float arrowPositionAlongEdgeProportional, float arrowWidth) = 0;
        /** Add a path as a sub path */
        virtual void 	addPath (const Path & pathToAppend, const AffineTransform & transformToApply) throw () = 0;
        /** Swap this path with the given path */
        virtual void 	swapWithPath (Path & other) = 0;
        /** Apply the given transform for this path */
        virtual void 	applyTransform (const AffineTransform & transform) throw () = 0;
        /** Scale the path to fit the given bounding box */
        virtual void 	scaleToFit (const float x, const float y, const float width, const float height, const bool preserveProportions) throw () = 0;
        /** Get the transform used to fit the given bounding box */
        virtual const AffineTransform *	getTransformToScaleToFit (const float x, const float y, const float width, const float height, const bool preserveProportions) const throw () = 0;
        /** Create a new path with rounded corners */
        virtual const Path * createPathWithRoundedCorners (const float cornerRadius) const throw () = 0;
        /** Set using non-zero winding (used to change the fill mode) */
        virtual void 	setUsingNonZeroWinding (const bool isNonZeroWinding) throw () = 0;
        /** Get the winding mode */
        virtual bool 	isUsingNonZeroWinding () const throw () = 0;
    };

    /** This class is a wrapper of the Juce PathStrokeType class.
        This is used to simplify different Juce code base in the same process. */
    struct PathStrokeType
    {
        /** The type of shape to use for the corners between two adjacent line segments. */
        enum JointStyle
        {
            mitered,    /**< Indicates that corners should be drawn with sharp joints.
                             Note that for angles that curve back on themselves, drawing a
                             mitre could require extending the point too far away from the
                             path, so a mitre limit is imposed and any corners that exceed it
                             are drawn as bevelled instead. */
            curved,     /**< Indicates that corners should be drawn as rounded-off. */
            beveled     /**< Indicates that corners should be drawn with a line flattening their
                             outside edge. */
        };

        /** The type shape to use for the ends of lines. */
        enum EndCapStyle
        {
            butt,       /**< Ends of lines are flat and don't extend beyond the end point. */
            square,     /**< Ends of lines are flat, but stick out beyond the end point for half
                             the thickness of the stroke. */
            rounded     /**< Ends of lines are rounded-off with a circular shape. */
        };

        /** Applies this stroke type to a path and returns the resultant stroke as another Path. */
        virtual void createStrokedPath (Path& destPath, const Path& sourcePath, const AffineTransform& transform, const float extraAccuracy = 1.0f) const throw() = 0;
        /** Applies this stroke type to a path, creating a dashed line. */
        virtual void createDashedStroke (Path& destPath, const Path& sourcePath, const float* dashLengths, int numDashLengths, const AffineTransform& transform, const float extraAccuracy = 1.0f) const throw() = 0;
        /** Returns the stroke thickness. */
        virtual float getStrokeThickness() const throw() = 0;                  
        /** Returns the joint style. */
        virtual JointStyle getJointStyle() const throw() = 0;
        /** Returns the end-cap style. */
        virtual EndCapStyle getEndStyle() const throw() = 0;
    };


    /** This is a factory used to create Path.
        @warning You must call deletePath for each pointer returned. 
                 This is because the memory tracking tools can be confused with heap allocated in a code segment and deallocated in another segment. */
    struct PathFactory
    {
        /** Create an empty path instance */
        virtual Path * createEmptyPathInstance() const = 0;
        /** Create a path stroke type object */
        virtual PathStrokeType * createPathStrokeType(const float strokeThickness, const PathStrokeType::JointStyle jointStyle, const PathStrokeType::EndCapStyle endStyle) const = 0;

        /** Delete a created path instance */
        virtual void deletePath(Path * path) const = 0;
        /** Delete a path stroke type object */
        virtual void deletePathStrokeType(PathStrokeType * strokeType) const = 0;
    };

    /** This class is a wrapper of the Juce Colour class.
        This is used to simplify different Juce code base in the same process. */
    struct Colour
    {
        /** Returns the red component of this colour. */
        virtual uint8 	getRed () const throw () = 0;
        /** Returns the green component of this colour. */
        virtual uint8 	getGreen () const throw () = 0;
        /** Returns the blue component of this colour. */
        virtual uint8 	getBlue () const throw () = 0;
        /** Returns the colour's alpha (opacity). */
        virtual uint8 	getAlpha () const throw () = 0;
        /** Returns a 32-bit integer that represents this colour. */
        virtual uint32 	getARGB () const throw () = 0;
        /** Returns true if this colour is completely opaque. */
        virtual bool 	isOpaque () const throw () = 0;
        /** Returns true if this colour is completely transparent. */
        virtual bool 	isTransparent () const throw () = 0;
        /** Returns the colour's hue, saturation and brightness components all at once. */
        virtual void 	getHSB (float & hue, float & saturation, float & brightness) const throw () = 0;
        /** Returns a colour that's the same colour as this one, but with a new alpha value. */
        virtual const Colour * 	withAlpha (const uint8 newAlpha) const throw () = 0;
        /** Returns a colour that's the same colour as this one, but with a modified alpha value. */
        virtual const Colour *	withMultipliedAlpha (const float alphaMultiplier) const throw () = 0;
        /** Returns a colour that is the result of alpha-compositing a new colour over this one. */
        virtual const Colour * overlaidWith (const Colour & foregroundColour) const throw () = 0;
        /** Returns a copy of this colour with a different hue. */
        virtual const Colour *	withHue (const float newHue) const throw () = 0;
        /** Returns a copy of this colour with a different saturation. */
        virtual const Colour *	withSaturation (const float newSaturation) const throw () = 0;
        /** Returns a copy of this colour with a different brightness. */
        virtual const Colour *	withBrightness (const float newBrightness) const throw () = 0;
        /** Returns a copy of this colour with it hue rotated. */
        virtual const Colour *	withRotatedHue (const float amountToRotate) const throw () = 0;
        /** Returns a copy of this colour with its saturation multiplied by the given value. */
        virtual const Colour *	withMultipliedSaturation (const float multiplier) const throw () = 0;
        /** Returns a copy of this colour with its brightness multiplied by the given value. */
        virtual const Colour *	withMultipliedBrightness (const float amount) const throw () = 0;
        /** Returns a brighter version of this colour. */
        virtual const Colour *	brighter (float amountBrighter=0.4f) const throw () = 0;
        /** Returns a darker version of this colour. */
        virtual const Colour *	darker (float amountDarker=0.4f) const throw () = 0;
        /** Returns a colour that will be clearly visible against this colour.  */
        virtual const Colour *	contrasting (const float amount=1.0f) const throw () = 0;
    };

    /** This class is a wrapper of the Juce Image class.
        This is used to simplify different Juce code base in the same process.
        */
    struct Image
    {
        /** The pixel format used for this image */
        enum  	PixelFormat { RGB, ARGB, SingleChannel  };
        /** Get the image width in pixels */
        virtual int 	getWidth () const throw () = 0;
        /** Get the image height in pixels */
        virtual int 	getHeight () const throw () = 0;
        /** Get the pixel format used */
        virtual PixelFormat 	getFormat () const throw () = 0;
        /** Clear the given section with the given colour */
        virtual void 	clear (int x, int y, int w, int h, const Colour & colourToClearTo) = 0;
        /** Create a resized copy for this image */ 
        virtual Image * 	createCopy (int newWidth = -1, int newHeight = -1) const = 0;
        /** Get the pixel at the given position */
        virtual const Colour *	getPixelAt (const int x, const int y) const = 0;
        /** Set the pixel at the given position */
        virtual void 	setPixelAt (const int x, const int y, const Colour & colour) = 0;
        /** Change the opacity for a pixel */
        virtual void 	multiplyAlphaAt (const int x, const int y, const float multiplier) = 0;
        /** Change the opacity for the whole image */
        virtual void 	multiplyAllAlphas (const float amountToMultiplyBy) = 0;
        /** Remove image saturation (the image will be grey) */
        virtual void 	desaturate () = 0;
        /** Lock the pixel section for writing */
        virtual uint8 * lockPixelDataReadWrite (int x, int y, int w, int h, int & lineStride, int & pixelStride) = 0;
        /** Then release the locked section */
        virtual void 	releasePixelDataReadWrite (void * sourceData) = 0;
        /** Lock the pixel section for reading only */
        virtual const uint8 * 	lockPixelDataReadOnly (int x, int y, int w, int h, int & lineStride, int & pixelStride) const = 0;
        /** Then release the locked section */
        virtual void 	releasePixelDataReadOnly (const void *sourceData) const = 0;
        /** Copy the given pixel array to the given rectangle in the image */
        virtual void 	setPixelData (int destX, int destY, int destW, int destH, const uint8 *sourcePixelData, int sourceLineStride) = 0;
        /** Move a section of the image to somewhere else */
        virtual void 	moveImageSection (int destX, int destY, int sourceX, int sourceY, int width, int height) = 0;
    };

    /** This is a factory used to create Images.
        @warning You must call deleteImage for each pointer returned. 
                 This is because the memory tracking tools can be confused with heap allocated in a code segment and deallocated in another segment. */
    struct ImageFactory
    {
        /** Create an empty memory based image */
        virtual Image * createEmptyImage(const Image::PixelFormat format, const int imageWidth, const int imageHeight, const bool clearImage) const = 0;
        /** Create an image from a memory section */
        virtual Image * createImageFromMemory(const uint8 * section, const int sectionSizeInBytes) const = 0;
        /** Create an image from a file path (stored as UTF-8) */
        virtual Image * createImageFromFile(const String & absoluteFilePath) const = 0;

        /** Create a colour (alpha = 255 means opaque) */
        virtual Colour * createARGBColour(const uint8 red, const uint8 green, const uint8 blue, const uint8 alpha) const = 0;
        /** Create a colour from Hue Saturation Brightness space (alpha = 255 means opaque) */
        virtual Colour * createAHSBColour(const float hue, const float saturation, const float brightness, const uint8 alpha) const = 0;

        /** Delete a created image */
        virtual void deleteImage(Image * image) const throw() = 0;
        /** Delete a created colour */
        virtual void deleteColour(Colour * image) const throw() = 0;
    };


    /** This class is a wrapper of the Juce Brush class.
        This is used to simplify different Juce code base in the same process.
        */
    struct Brush
    {
        /** Create a copy for this brush */
        virtual Brush * createCopy () const throw () = 0;
        /** Apply a transform to this brush (if applicable) */
        virtual void 	applyTransform (const AffineTransform & transform) throw () = 0;
        /** Multiply the opacity for this brush */
        virtual void 	multiplyOpacity (const float multiple) throw () = 0;
        /** Check whether this brush is invisible */
        virtual bool 	isInvisible () const throw () = 0; 
    };

    /** This is a factory used to create Brushes.
        @warning You must call deleteBrush for each pointer returned. 
                 This is because the memory tracking tools can be confused with heap allocated in a code segment and deallocated in another segment. */
    struct BrushFactory
    {
        /** Create a gradient brush */
        virtual Brush * createGradientBrush(const Colour & colour1, const float x1, const float y1, const Colour & colour2, const float x2, const float y2, const bool isRadial) const = 0;
        /** Create a solid color brush */
        virtual Brush * createSolidColourBrush(const Colour & colour) const = 0;
        /** Create an image brush */
        virtual Brush * createImageBrush(Image & image, const int anchorX, const int anchorY, const float opacity) const = 0;
        /** Delete a created brush */
        virtual void deleteBrush(Brush * brush) const throw() = 0;
    };

    /** This class is a wrapper of the Juce Font class.
        This is used to simplify different Juce code base in the same process.
        */
    struct Font
    {
        enum  	FontStyleFlags { plain = 0, bold = 1, italic = 2, underlined = 4 };

 	    /** Changes the name of the typeface family. */
        virtual void setTypefaceName (const String & faceName) throw () = 0;
 	    /** Returns the name of the typeface family that this font uses. */
        virtual const String  	getTypefaceName () const throw () = 0;
 	    /** Returns the total height of this font. */
        virtual float 	getHeight () const throw () = 0;
 	    /** Changes the font's height. */
        virtual void 	setHeight (float newHeight) throw () = 0;
 	    /** Changes the font's height without changing its width. */
        virtual void 	setHeightWithoutChangingWidth (float newHeight) throw () = 0;
 	    /** Returns the height of the font above its baseline. */
        virtual float 	getAscent () const throw () = 0;
 	    /** Returns the amount that the font descends below its baseline. */
        virtual float 	getDescent () const throw () = 0;
 	    /** Returns the font's style flags. */
        virtual int 	getStyleFlags () const throw () = 0;
 	    /** Changes the font's style. */
        virtual void 	setStyleFlags (const int newFlags) throw () = 0;
 	    /** Makes the font bold or non-bold. */
        virtual void 	setBold (const bool shouldBeBold) throw () = 0;
 	    /** Returns true if the font is bold. */
        virtual bool 	isBold () const throw () = 0;
 	    /** Makes the font italic or non-italic. */
        virtual void 	setItalic (const bool shouldBeItalic) throw () = 0;
 	    /** Returns true if the font is italic. */
        virtual bool 	isItalic () const throw () = 0;
 	    /** Makes the font underlined or non-underlined. */
        virtual void 	setUnderline (const bool shouldBeUnderlined) throw () = 0;
 	    /** Returns true if the font is underlined. */
        virtual bool 	isUnderlined () const throw () = 0;
 	    /** Changes the font's horizontal scale factor. */
        virtual void 	setHorizontalScale (const float scaleFactor) throw () = 0;
 	    /** Returns the font's horizontal scale. */
        virtual float 	getHorizontalScale () const throw () = 0;
 	    /** Changes the font's kerning. */
        virtual void 	setExtraKerningFactor (const float extraKerning) throw () = 0;
 	    /** Returns the font's kerning. */
        virtual float 	getExtraKerningFactor () const throw () = 0;
 	    /** Changes all the font's characteristics with one call. */
        virtual void 	setSizeAndStyle (const float newHeight, const int newStyleFlags, const float newHorizontalScale, const float newKerningAmount) throw () = 0;
 	    /** Resets this font's characteristics. */
        virtual void 	resetToDefaultState () throw () = 0;
 	    /** Returns the total width of a string as it would be drawn using this font. */
        virtual float 	getStringWidthFloat (const String & text) const throw () = 0;
    };

    /** A definition of the Justification flags */
    struct Justification
    {
        enum Flags
        {
          left = 1, right = 2, horizontallyCentred = 4, top = 8,
          bottom = 16, verticallyCentred = 32, horizontallyJustified = 64, centred = 36,
          centredLeft = 33, centredRight = 34, centredTop = 12, centredBottom = 20,
          topLeft = 9, topRight = 10, bottomLeft = 17, bottomRight = 18
        };
    };

    /** This is a factory used to create Fonts.
        @warning You must call deleteFont for each pointer returned. 
                 This is because the memory tracking tools can be confused with heap allocated in a code segment and deallocated in another segment. */
    struct FontFactory
    {
 	    /** Creates a sans-serif font in a given size. */
        virtual Font * createSansSerifFont(const float fontHeight, const int styleFlags = Font::plain) const = 0;
 	    /** Creates a font with a given typeface and parameters. */
 	    virtual Font * createFont(const String & typefaceName, const float fontHeight, const int styleFlags) const = 0;
        /** Delete created font */
        virtual void deleteFont(Font * font) const = 0;
    };


    /** This class is a wrapper of the Juce Graphics class.
        This is used to simplify different Juce code base in the same process. */
    struct Graphics
    {
        /** Change the current drawing colour. */
        virtual void setColour (const Colour & newColour) throw () = 0;
 	    /** Returns the colour that's currently being used. */
        virtual const Colour * 	getCurrentColour () const throw () = 0;
        /** Changes the opacity to use with the current colour. */
        virtual void setOpacity (const float newOpacity) throw () = 0;
 	    /** Changes the current brush to use for drawing. */
        virtual void setBrush (const Brush * const newBrush) throw () = 0;
 	    /** Changes the font to use for subsequent text-drawing functions. */
        virtual void setFont (const Font & newFont) throw () = 0;
 	    /** Changes the size and style of the currently-selected font. */
        virtual void setFont (const float newFontHeight, const int fontStyleFlags = Font::plain) throw () = 0;
 	    /** Returns the font that's currently being used for text operations. */
        virtual const Font * getCurrentFont () const throw () = 0;
 	    /** Draws a one-line text string. */
        virtual void drawSingleLineText (const String & text, const int startX, const int baselineY) const throw () = 0;
 	    /** Draws text across multiple lines. */
        virtual void drawMultiLineText (const String & text, const int startX, const int baselineY, const int maximumLineWidth) const throw () = 0;
 	    /** Renders a string of text as a vector path. */
        virtual void drawTextAsPath (const String & text, const AffineTransform & transform) const throw () = 0;
 	    /** Draws a line of text within a specified rectangle. */
        virtual void drawText (const String & text, const int x, const int y, const int width, const int height, const int justificationType, const bool useEllipsesIfTooBig) const throw () = 0;
 	    /** Tries to draw a text string inside a given space. */
        virtual void drawFittedText (const String & text, const int x, const int y, const int width, const int height, const int justificationFlags, const int maximumNumberOfLines, const float minimumHorizontalScale=0.7f) const throw () = 0;
 	    /** Fills the context's entire clip region with the current colour or brush. */
        virtual void fillAll () const throw () = 0;
 	    /** Fills the context's entire clip region with a given colour. */
        virtual void fillAll (const Colour & colourToUse) const throw () = 0;
 	    /** Fills a rectangle with the current colour or brush. */
        virtual void fillRect (const float x, const float y, const float width, const float height) const throw () = 0;
 	    /** Uses the current colour or brush to fill a rectangle with rounded corners. */
        virtual void fillRoundedRectangle (const float x, const float y, const float width, const float height, const float cornerSize) const throw () = 0;
 	    /** Fills a rectangle with a checkerboard pattern, alternating between two colours. */
        virtual void fillCheckerBoard (int x, int y, int width, int height, const int checkWidth, const int checkHeight, const Colour & colour1, const Colour & colour2) const throw () = 0;
 	    /** Draws four lines to form a rectangular outline, using the current colour or brush. */
        virtual void drawRect (const int x, const int y, const int width, const int height, const int lineThickness=1) const throw () = 0;
 	    /** Uses the current colour or brush to draw the outline of a rectangle with rounded corners. */
        virtual void drawRoundedRectangle (const float x, const float y, const float width, const float height, const float cornerSize, const float lineThickness) const throw () = 0;
 	    /** Draws a 3D raised (or indented) bevel using two colours. */
        virtual void drawBevel (const int x, const int y, const int width, const int height, const int bevelThickness, const Colour & topLeftColour, const Colour & bottomRightColour, const bool useGradient=true) const throw () = 0;
 	    /** Draws a pixel using the current colour or brush. */
        virtual void setPixel (int x, int y) const throw () = 0;
 	    /** Fills an ellipse with the current colour or brush. */
        virtual void fillEllipse (const float x, const float y, const float width, const float height) const throw () = 0;
 	    /** Draws an elliptical stroke using the current colour or brush. */
        virtual void drawEllipse (const float x, const float y, const float width, const float height, const float lineThickness) const throw () = 0;
 	    /** Draws a line between two points with a given thickness. */
        virtual void drawLine (const float startX, const float startY, const float endX, const float endY, const float lineThickness = 1.0f) const throw () = 0;
 	    /** Draws a dashed line using a custom set of dash-lengths. */
        virtual void drawDashedLine (const float startX, const float startY, const float endX, const float endY, const float *const dashLengths, const int numDashLengths, const float lineThickness = 1.0f) const throw () = 0;
 	    /** Draws a vertical line of pixels at a given x position. */
        virtual void drawVerticalLine (const int x, float top, float bottom) const throw () = 0;
 	    /** Draws a horizontal line of pixels at a given y position. */
        virtual void drawHorizontalLine (const int y, float left, float right) const throw () = 0;
 	    /** Fills a path using the currently selected colour or brush. */
        virtual void fillPath (const Path & path, const AffineTransform & transform) const throw () = 0;
 	    /** Draws a path's outline using the currently selected colour or brush. */
        virtual void strokePath (const Path & path, const PathStrokeType & strokeType, const AffineTransform & transform) const throw () = 0;
 	    /** Draws a line with an arrowhead. */
        virtual void drawArrow (const float startX, const float startY, const float endX, const float endY, const float lineThickness, const float arrowheadWidth, const float arrowheadLength) const throw () = 0;
 	    /** Draws an image. */
        virtual void drawImageAt (const Image * const imageToDraw, const int topLeftX, const int topLeftY, const bool fillAlphaChannelWithCurrentBrush = false) const throw () = 0;
 	    /** Draws part of an image, rescaling it to fit in a given target region. */
        virtual void drawImage (const Image * const imageToDraw, int destX, int destY, int destWidth, int destHeight, int sourceX, int sourceY, int sourceWidth, int sourceHeight, const bool fillAlphaChannelWithCurrentBrush = false) const throw () = 0;
 	    /** Draws part of an image, having applied an affine transform to it. */
        virtual void drawImageTransformed (const Image * const imageToDraw, int sourceClipX, int sourceClipY, int sourceClipWidth, int sourceClipHeight, const AffineTransform & transform, const bool fillAlphaChannelWithCurrentBrush) const throw () = 0;
 	    /** Returns the position of the bounding box for the current clipping region. */
        virtual void getClipBounds (int & x, int & y, int & width, int & height) const throw () = 0;
 	    /** Checks whether a rectangle overlaps the context's clipping region. */
        virtual bool clipRegionIntersects (const int x, const int y, const int width, const int height) const throw () = 0;
 	    /** Intersects the current clipping region with another region. */
        virtual bool reduceClipRegion (const int x, const int y, const int width, const int height) throw () = 0;
 	    /** Excludes a rectangle to stop it being drawn into. */
        virtual void excludeClipRegion (const int x, const int y, const int width, const int height) throw () = 0;
 	    /** Returns true if no drawing can be done because the clip region is zero. */
        virtual bool isClipEmpty () const throw () = 0;
 	    /** Saves the current graphics state on an internal stack. */
        virtual void saveState () throw () = 0;
 	    /** Restores a graphics state that was previously saved with saveState(). */
        virtual void restoreState () throw () = 0;
 	    /** Moves the position of the context's origin. */
        virtual void setOrigin (const int newOriginX, const int newOriginY) throw () = 0;
 	    /** Resets the current colour, brush, and font to default settings. */
        virtual void resetToDefaultState () throw () = 0;
 	    /** Returns true if this context is drawing to a vector-based device, such as a printer.  */
        virtual bool isVectorDevice () const throw () = 0;
        /** Draw the given SVG file inside the given rectangle */
        virtual bool drawSVG(const String & fileName, const int destX, const int destY, const int destWidth, const int destHeight, const int justification) const = 0;
    };


    /** The general factory of factories object */
    struct RenderingFactory
    {
        virtual const AffineTransformFactory & getAffineTransformFactory() const = 0;
        virtual const PathFactory & getPathFactory() const = 0;
        virtual const ImageFactory & getImageFactory() const = 0;
        virtual const BrushFactory & getBrushFactory() const = 0;
        virtual const FontFactory & getFontFactory() const = 0;
    };
}

#8

and the implementation:

// We need RenderingPrimitive declaration
// We need Juce too

// The implementation here is all private, so it's not possible to use the members directly, only through the base class declaration
class AffineTransform : public TwoDimensionalRendering::AffineTransform
{
    juce::AffineTransform object;
    
    /** Transform the given point */
    virtual void 	transformPoint (double & x, double & y) const { object.transformPoint(x, y); }
    /** Get the translated transform for this object */
    virtual const TwoDimensionalRendering::AffineTransform 	* translated (const float deltaX, const float deltaY) const { return new AffineTransform(object.translated(deltaX, deltaY)); }
    /** Get the rotated transform for this object */
    virtual const TwoDimensionalRendering::AffineTransform  * rotated (const float angleInRadians) const { return new AffineTransform(object.rotated(angleInRadians)); }
    /** Get the rotated transform for this object around the given pivot */
    virtual const TwoDimensionalRendering::AffineTransform 	* rotated (const float angleInRadians, const float pivotX, const float pivotY) const { return new AffineTransform(object.rotated(angleInRadians, pivotX, pivotY)); }
    /** Get the scaled transform for this object */
    virtual const TwoDimensionalRendering::AffineTransform 	* scaled (const float factorX, const float factorY) const { return new AffineTransform(object.scaled(factorX, factorY)); }
    /** Get the sheared transform for this object */
    virtual const TwoDimensionalRendering::AffineTransform 	* sheared (const float shearX, const float shearY) const { return new AffineTransform(object.sheared(shearX, shearY)); }
    /** Get the inverse matrix of this one */
    virtual const TwoDimensionalRendering::AffineTransform 	* inverted () const { return new AffineTransform(object.inverted()); }
    /** Get the result of the two transformation */
    virtual const TwoDimensionalRendering::AffineTransform 	* followedBy (const TwoDimensionalRendering::AffineTransform & other) const { return new AffineTransform(object.followedBy(((AffineTransform&)other).object)); }
    /** Check if this transform is an identity matrix */
    virtual bool 	isIdentity () const throw () { return object.isIdentity(); }
    /** Check if this transform is a singularity matrix */
    virtual bool 	isSingularity () const throw () { return object.isSingularity(); }

    /** Constructor */
    AffineTransform(const juce::AffineTransform & _obj) : object(_obj) {}
    /** The factory is our friend */
    friend class AffineTransformFactory;
    friend class Path;
    friend class PathStrokeType;
    friend class Brush;
    friend class Graphics;
};

// The implementation here is all private, so it's not possible to use the members directly, only through the base class declaration 
class AffineTransformFactory : public TwoDimensionalRendering::AffineTransformFactory
{
    virtual const TwoDimensionalRendering::AffineTransform *	createIdentity () const { return new AffineTransform(juce::AffineTransform()); }
    virtual const TwoDimensionalRendering::AffineTransform *	createTranslation (const float deltaX, const float deltaY) const { return new AffineTransform(juce::AffineTransform::translation(deltaX, deltaY)); }
    virtual const TwoDimensionalRendering::AffineTransform *	createRotation (const float angleInRadians) const { return new AffineTransform(juce::AffineTransform::rotation(angleInRadians)); }
    virtual const TwoDimensionalRendering::AffineTransform *	createRotation (const float angleInRadians, const float pivotX, const float pivotY) const { return new AffineTransform(juce::AffineTransform::rotation(angleInRadians, pivotX, pivotY)); }
    virtual const TwoDimensionalRendering::AffineTransform *	createScale (const float factorX, const float factorY) const { return new AffineTransform(juce::AffineTransform::scale(factorX, factorY)); }
    virtual void  deleteTransform (const TwoDimensionalRendering::AffineTransform * transform) const { delete (AffineTransform*)transform; }
};

class Path : public TwoDimensionalRendering::Path
{
    juce::Path path;
    /** Check if the path is currently empty */
    virtual bool    isEmpty () const throw () { return path.isEmpty(); }
    /** Get the bounds for this path */
    virtual void 	getBounds (float & x, float & y, float & w, float & h) const throw () { path.getBounds(x, y, w, h); }
    /** Get the bounds after the given transformation */
    virtual void 	getBoundsTransformed (const TwoDimensionalRendering::AffineTransform & transform, float & x, float & y, float & w, float & h) const throw () { path.getBoundsTransformed(((AffineTransform&)transform).object, x, y, w, h); }
    /** Return true if the path contains the given point */
    virtual bool 	contains (const float x, const float y) const throw () { return path.contains(x, y); }
    /** Return true if the path intersect the given line */
    virtual bool 	intersectsLine (const float x1, const float y1, const float x2, const float y2) throw () { return path.intersectsLine(x1, y1, x2, y2); }
    /** Clear this path */
    virtual void 	clear () throw () { path.clear(); }
    /** Start new sub path at the given position */
    virtual void 	startNewSubPath (const float startX, const float startY) throw () { path.startNewSubPath(startX, startY); }
    /** Close the sub path */
    virtual void 	closeSubPath () throw () { path.closeSubPath(); }
    /** Append a line segment from the current position to the given position */
    virtual void 	lineTo (const float endX, const float endY) throw () { path.lineTo(endX, endY); }
    /** Append a quadratic curve from the current position to the given position */
    virtual void 	quadraticTo (const float controlPointX, const float controlPointY, const float endPointX, const float endPointY) throw () { path.quadraticTo(controlPointX, controlPointY, endPointX, endPointY); }
    /** Append a Bezier curve from the current position to the given position */
    virtual void 	cubicTo (const float controlPoint1X, const float controlPoint1Y, const float controlPoint2X, const float controlPoint2Y, const float endPointX, const float endPointY) throw () { path.cubicTo(controlPoint1X, controlPoint1Y, controlPoint2X, controlPoint2Y, endPointX, endPointY); }
    /** Get the current position */
    virtual void 	getCurrentPosition (float & x, float & y) const throw () { juce::Point pt = path.getCurrentPosition(); x = pt.getX(), y = pt.getY(); }
    /** Add a rectangle as a sub path */
    virtual void 	addRectangle (const float x, const float y, const float w, const float h) throw () { path.addRectangle(x, y, w, h); }
    /** Add a rectangle with rounded corner as a sub path */
    virtual void 	addRoundedRectangle (const float x, const float y, const float w, const float h, float cornerSizeX, float cornerSizeY) throw () { path.addRoundedRectangle(x, y, w, h, cornerSizeX, cornerSizeY); }
    /** Add a triangle as a sub path */
    virtual void 	addTriangle (const float x1, const float y1, const float x2, const float y2, const float x3, const float y3) throw () { path.addTriangle(x1, y1, x2, y2, x3, y3); }
    /** Add a quadrilateral as a sub path */
    virtual void 	addQuadrilateral (const float x1, const float y1, const float x2, const float y2, const float x3, const float y3, const float x4, const float y4) throw () { path.addQuadrilateral(x1, y1, x2, y2, x3, y3, x4, y4); }
    /** Add an ellipse as a sub path */
    virtual void 	addEllipse (const float x, const float y, const float width, const float height) throw () { path.addEllipse(x, y, width, height); }
    /** Add an arc as a sub path */
    virtual void 	addArc (const float x, const float y, const float width, const float height, const float fromRadians, const float toRadians, const bool startAsNewSubPath = false) throw () { path.addArc(x, y, width, height, fromRadians, toRadians, startAsNewSubPath); }
    /** Add a centred arc as a sub path */
    virtual void 	addCentredArc (const float centreX, const float centreY, const float radiusX, const float radiusY, const float rotationOfEllipse, const float fromRadians, const float toRadians, const bool startAsNewSubPath=false) throw () { path.addCentredArc(centreX, centreY, radiusX, radiusY, rotationOfEllipse, fromRadians, toRadians, startAsNewSubPath); }
    /** Add a pie segment as a sub path */
    virtual void 	addPieSegment (const float x, const float y, const float width, const float height, const float fromRadians, const float toRadians, const float innerCircleProportionalSize) { path.addPieSegment(x, y, width, height, fromRadians, toRadians, innerCircleProportionalSize); }
    /** Add a line segment as a sub path */
    virtual void 	addLineSegment (const float startX, const float startY, const float endX, const float endY, float lineThickness) throw () { path.addLineSegment(startX, startY, endX, endY, lineThickness); }
    /** Add an arrow as a sub path */
    virtual void 	addArrow (const float startX, const float startY, const float endX, const float endY, float lineThickness, float arrowheadWidth, float arrowheadLength) throw () { path.addArrow(startX, startY, endX, endY, lineThickness, arrowheadWidth, arrowheadLength); }
    /** Add a star as a sub path */
    virtual void 	addStar (const float centreX, const float centreY, const int numberOfPoints, const float innerRadius, const float outerRadius, const float startAngle = 0.0f) { path.addStar(centreX, centreY, numberOfPoints, innerRadius, outerRadius, startAngle); }
    /** Add a bubble as a sub path */
    virtual void 	addBubble (float bodyX, float bodyY, float bodyW, float bodyH, float cornerSize, float arrowTipX, float arrowTipY, int whichSide, float arrowPositionAlongEdgeProportional, float arrowWidth) { path.addBubble(bodyX, bodyY, bodyW, bodyH, cornerSize, arrowTipX, arrowTipY, whichSide, arrowPositionAlongEdgeProportional, arrowWidth); }
    /** Add a path as a sub path */
    virtual void 	addPath (const TwoDimensionalRendering::Path & pathToAppend, const TwoDimensionalRendering::AffineTransform & transformToApply) throw () { path.addPath(((Path&)pathToAppend).path, ((AffineTransform&)transformToApply).object); }
    /** Swap this path with the given path */
    virtual void 	swapWithPath (TwoDimensionalRendering::Path & other) { path.swapWithPath(((Path&)other).path); }
    /** Apply the given transform for this path */
    virtual void 	applyTransform (const TwoDimensionalRendering::AffineTransform & transform) throw () { path.applyTransform(((AffineTransform&)transform).object); }
    /** Scale the path to fit the given bounding box */
    virtual void 	scaleToFit (const float x, const float y, const float width, const float height, const bool preserveProportions) throw () { path.scaleToFit(x, y, width, height, preserveProportions); }
    /** Get the transform used to fit the given bounding box */
    virtual const TwoDimensionalRendering::AffineTransform *	getTransformToScaleToFit (const float x, const float y, const float width, const float height, const bool preserveProportions) const throw () { return new AffineTransform(path.getTransformToScaleToFit(x, y, width, height, preserveProportions)); }
    /** Create a new path with rounded corners */
    virtual const TwoDimensionalRendering::Path * createPathWithRoundedCorners (const float cornerRadius) const throw () { return new Path(path.createPathWithRoundedCorners(cornerRadius)); }
    /** Set using non-zero winding (used to change the fill mode) */
    virtual void 	setUsingNonZeroWinding (const bool isNonZeroWinding) throw () { path.setUsingNonZeroWinding(isNonZeroWinding); }
    /** Get the winding mode */
    virtual bool 	isUsingNonZeroWinding () const throw () { return path.isUsingNonZeroWinding(); }

    Path(const juce::Path & _path) : path(_path) {}
    friend class PathFactory;
    friend class PathStrokeType;
    friend class Graphics;
};

/** This class is a wrapper of the Juce PathStrokeType class.
    This is used to simplify different Juce code base in the same process. */
class PathStrokeType : public TwoDimensionalRendering::PathStrokeType
{
    juce::PathStrokeType pathST;
    /** Applies this stroke type to a path and returns the resultant stroke as another Path. */
    virtual void createStrokedPath (TwoDimensionalRendering::Path& destPath, const TwoDimensionalRendering::Path& sourcePath, const TwoDimensionalRendering::AffineTransform& transform, const float extraAccuracy = 1.0f) const throw()
    {
        pathST.createStrokedPath(((Path&)destPath).path, ((Path&)sourcePath).path, ((AffineTransform&)transform).object, extraAccuracy); 
    }
    /** Applies this stroke type to a path, creating a dashed line. */
    virtual void createDashedStroke (TwoDimensionalRendering::Path& destPath, const TwoDimensionalRendering::Path& sourcePath, const float* dashLengths, int numDashLengths, const TwoDimensionalRendering::AffineTransform& transform, const float extraAccuracy = 1.0f) const throw()
    {
        pathST.createDashedStroke(((Path&)destPath).path, ((Path&)sourcePath).path, dashLengths, numDashLengths, ((AffineTransform&)transform).object, extraAccuracy); 
    }

    /** Returns the stroke thickness. */
    virtual float getStrokeThickness() const throw() { return pathST.getStrokeThickness(); }                  
    /** Returns the joint style. */
    virtual TwoDimensionalRendering::PathStrokeType::JointStyle getJointStyle() const throw() { return (TwoDimensionalRendering::PathStrokeType::JointStyle)(pathST.getJointStyle()); }
    /** Returns the end-cap style. */
    virtual TwoDimensionalRendering::PathStrokeType::EndCapStyle getEndStyle() const throw() { return (TwoDimensionalRendering::PathStrokeType::EndCapStyle)(pathST.getEndStyle()); }

    PathStrokeType(const juce::PathStrokeType & type) : pathST(type) {}

    friend class PathFactory;
    friend class Graphics;
};

class PathFactory : public TwoDimensionalRendering::PathFactory
{
    /** Create an empty path instance */
    virtual TwoDimensionalRendering::Path * createEmptyPathInstance() const { return new Path(juce::Path()); }
    /** Create a path stroke type object */
    virtual TwoDimensionalRendering::PathStrokeType * createPathStrokeType(const float strokeThickness, const TwoDimensionalRendering::PathStrokeType::JointStyle jointStyle, const TwoDimensionalRendering::PathStrokeType::EndCapStyle endStyle) const { return new PathStrokeType(juce::PathStrokeType(strokeThickness, (juce::PathStrokeType::JointStyle)jointStyle, (juce::PathStrokeType::EndCapStyle)endStyle)); }

    /** Delete a created path instance */
    virtual void deletePath(TwoDimensionalRendering::Path * path) const { delete (Path*)path; }
    /** Delete a path stroke type object */
    virtual void deletePathStrokeType(TwoDimensionalRendering::PathStrokeType * strokeType) const { delete (PathStrokeType*)strokeType; }
};

class Colour : public TwoDimensionalRendering::Colour
{
    juce::Colour colour;

    /** Returns the red component of this colour. */
    virtual uint8 	getRed () const throw () { return colour.getRed(); }
    /** Returns the green component of this colour. */
    virtual uint8 	getGreen () const throw () { return colour.getGreen(); }
    /** Returns the blue component of this colour. */
    virtual uint8 	getBlue () const throw () { return colour.getBlue(); }
    /** Returns the colour's alpha (opacity). */
    virtual uint8 	getAlpha () const throw () { return colour.getAlpha(); }
    /** Returns a 32-bit integer that represents this colour. */
    virtual uint32 	getARGB () const throw () { return colour.getARGB(); }
    /** Returns true if this colour is completely opaque. */
    virtual bool 	isOpaque () const throw () { return colour.isOpaque(); }
    /** Returns true if this colour is completely transparent. */
    virtual bool 	isTransparent () const throw () { return colour.isTransparent(); }
    /** Returns the colour's hue, saturation and brightness components all at once. */
    virtual void 	getHSB (float & hue, float & saturation, float & brightness) const throw () { colour.getHSB(hue, saturation, brightness); }
    /** Returns a colour that's the same colour as this one, but with a new alpha value. */
    virtual const TwoDimensionalRendering::Colour * 	withAlpha (const uint8 newAlpha) const throw () { return new Colour(colour.withAlpha(newAlpha)); }
    /** Returns a colour that's the same colour as this one, but with a modified alpha value. */
    virtual const TwoDimensionalRendering::Colour *	withMultipliedAlpha (const float alphaMultiplier) const throw () { return new Colour(colour.withMultipliedAlpha(alphaMultiplier)); }
    /** Returns a colour that is the result of alpha-compositing a new colour over this one. */
    virtual const TwoDimensionalRendering::Colour * overlaidWith (const TwoDimensionalRendering::Colour & foregroundColour) const throw () { return new Colour(colour.overlaidWith(((Colour&)foregroundColour).colour)); }
    /** Returns a copy of this colour with a different hue. */
    virtual const TwoDimensionalRendering::Colour *	withHue (const float newHue) const throw () { return new Colour(colour.withHue(newHue)); }
    /** Returns a copy of this colour with a different saturation. */
    virtual const TwoDimensionalRendering::Colour *	withSaturation (const float newSaturation) const throw () { return new Colour(colour.withSaturation(newSaturation)); }
    /** Returns a copy of this colour with a different brightness. */
    virtual const TwoDimensionalRendering::Colour *	withBrightness (const float newBrightness) const throw () { return new Colour(colour.withBrightness(newBrightness)); }
    /** Returns a copy of this colour with it hue rotated. */
    virtual const TwoDimensionalRendering::Colour *	withRotatedHue (const float amountToRotate) const throw () { return new Colour(colour.withRotatedHue(amountToRotate)); }
    /** Returns a copy of this colour with its saturation multiplied by the given value. */
    virtual const TwoDimensionalRendering::Colour *	withMultipliedSaturation (const float multiplier) const throw () { return new Colour(colour.withMultipliedSaturation(multiplier)); }
    /** Returns a copy of this colour with its brightness multiplied by the given value. */
    virtual const TwoDimensionalRendering::Colour *	withMultipliedBrightness (const float amount) const throw () { return new Colour(colour.withMultipliedBrightness(amount)); }
    /** Returns a brighter version of this colour. */
    virtual const TwoDimensionalRendering::Colour *	brighter (float amountBrighter = 0.4f) const throw () { return new Colour(colour.brighter(amountBrighter)); }
    /** Returns a darker version of this colour. */
    virtual const TwoDimensionalRendering::Colour *	darker (float amountDarker = 0.4f) const throw () { return new Colour(colour.darker(amountDarker)); }
    /** Returns a colour that will be clearly visible against this colour.  */
    virtual const TwoDimensionalRendering::Colour *	contrasting (const float amount=1.0f) const throw () { return new Colour(colour.contrasting(amount)); }

    Colour(const juce::Colour & color) : colour(color) {}
    friend class Image;
    friend class ImageFactory;
    friend class Brush; 
    friend class BrushFactory; 
    friend class Graphics;
};

/** This class is a wrapper of the Juce Image class.
    This is used to simplify different Juce code base in the same process.
    */
class Image : public TwoDimensionalRendering::Image
{
    juce::Image * image;
    /** Get the image width in pixels */
    virtual int 	getWidth () const throw () { return image->getWidth(); }
    /** Get the image height in pixels */
    virtual int 	getHeight () const throw () { return image->getHeight(); }
    /** Get the pixel format used */
    virtual TwoDimensionalRendering::Image::PixelFormat 	getFormat () const throw () { return (TwoDimensionalRendering::Image::PixelFormat)image->getFormat(); }
    /** Clear the given section with the given colour */
    virtual void 	clear (int x, int y, int w, int h, const TwoDimensionalRendering::Colour & colourToClearTo) { image->clear(x, y, w, h, ((Colour&)colourToClearTo).colour); }
    /** Create a resized copy for this image */ 
    virtual TwoDimensionalRendering::Image * 	createCopy (int newWidth = -1, int newHeight = -1) const { return new Image(image->createCopy(newWidth, newHeight)); }
    /** Get the pixel at the given position */
    virtual const TwoDimensionalRendering::Colour *	getPixelAt (const int x, const int y) const { return new Colour(image->getPixelAt(x, y)); }
    /** Set the pixel at the given position */
    virtual void 	setPixelAt (const int x, const int y, const TwoDimensionalRendering::Colour & colour) { image->setPixelAt(x, y, ((Colour&)colour).colour); }
    /** Change the opacity for a pixel */
    virtual void 	multiplyAlphaAt (const int x, const int y, const float multiplier) { image->multiplyAlphaAt(x, y, multiplier); }
    /** Change the opacity for the whole image */
    virtual void 	multiplyAllAlphas (const float amountToMultiplyBy) { image->multiplyAllAlphas(amountToMultiplyBy); }
    /** Remove image saturation (the image will be grey) */
    virtual void 	desaturate () { image->desaturate(); }
    /** Lock the pixel section for writing */
    virtual uint8 * lockPixelDataReadWrite (int x, int y, int w, int h, int & lineStride, int & pixelStride) { return image->lockPixelDataReadWrite(x, y, w, h, lineStride, pixelStride); }
    /** Then release the locked section */
    virtual void 	releasePixelDataReadWrite (void * sourceData) { image->releasePixelDataReadWrite(sourceData); }
    /** Lock the pixel section for reading only */
    virtual const uint8 * 	lockPixelDataReadOnly (int x, int y, int w, int h, int & lineStride, int & pixelStride) const { return image->lockPixelDataReadOnly(x, y, w, h, lineStride, pixelStride); }
    /** Then release the locked section */
    virtual void 	releasePixelDataReadOnly (const void *sourceData) const { image->releasePixelDataReadOnly(sourceData); }
    /** Copy the given pixel array to the given rectangle in the image */
    virtual void 	setPixelData (int destX, int destY, int destW, int destH, const uint8 *sourcePixelData, int sourceLineStride) { image->setPixelData(destX, destY, destW, destH, sourcePixelData, sourceLineStride); }
    /** Move a section of the image to somewhere else */
    virtual void 	moveImageSection (int destX, int destY, int sourceX, int sourceY, int width, int height) { image->moveImageSection(destX, destY, sourceX, sourceY, width, height); }

    Image(juce::Image * _image) : image(_image) { }
    ~Image() { delete image; image = 0; }
    friend class ImageFactory;
    friend class Graphics;
    friend class ImageBrush;
    friend class BrushFactory;
};

/** This is a factory used to create Images.
    @warning You must call deleteImage for each pointer returned. 
             This is because the memory tracking tools can be confused with heap allocated in a code segment and deallocated in another segment. */
class ImageFactory : public TwoDimensionalRendering::ImageFactory
{
    /** Create an empty memory based image */
    virtual TwoDimensionalRendering::Image * createEmptyImage(const TwoDimensionalRendering::Image::PixelFormat format, const int imageWidth, const int imageHeight, const bool clearImage) const 
    {
        return new Image(new juce::Image((juce::Image::PixelFormat)format, imageWidth, imageHeight, clearImage));
    }
    /** Create an image from a memory section */
    virtual TwoDimensionalRendering::Image * createImageFromMemory(const uint8 * section, const int sectionSizeInBytes) const
    {
        juce::Image * image = juce::ImageFileFormat::loadFrom(section, sectionSizeInBytes);
        if (!image) return 0;
        return new Image(image);
    }

    /** Create an image from a file path (stored as UTF-8) */
    virtual TwoDimensionalRendering::Image * createImageFromFile(const TwoDimensionalRendering::String & absoluteFilePath) const 
    {
        juce::Image * image = juce::ImageFileFormat::loadFrom(juce::File(juce::String::fromUTF8(absoluteFilePath)));
        if (!image) return 0;
        return new Image(image);
    }

    /** Create a colour (alpha = 255 means opaque) */
    virtual TwoDimensionalRendering::Colour * createARGBColour(const uint8 red, const uint8 green, const uint8 blue, const uint8 alpha) const 
    {
        return new Colour(juce::Colour(red, green, blue, alpha));
    }
    /** Create a colour from Hue Saturation Brightness space (alpha = 255 means opaque) */
    virtual TwoDimensionalRendering::Colour * createAHSBColour(const float hue, const float saturation, const float brightness, const uint8 alpha) const 
    {
        return new Colour(juce::Colour(hue, saturation, brightness, alpha));
    }

    /** Delete a created image */
    virtual void deleteImage(TwoDimensionalRendering::Image * image) const throw() { delete (Image*)image; }
    /** Delete a created colour */
    virtual void deleteColour(TwoDimensionalRendering::Colour * colour) const throw() { delete (Colour*)colour; }
};

class Brush : public TwoDimensionalRendering::Brush
{
    juce::Brush * brush;
    /** Create a copy for this brush */
    virtual TwoDimensionalRendering::Brush * createCopy () const throw () { return new Brush(brush->createCopy()); }
    /** Apply a transform to this brush (if applicable) */
    virtual void 	applyTransform (const TwoDimensionalRendering::AffineTransform & transform) throw () { brush->applyTransform(((AffineTransform&)transform).object); }
    /** Multiply the opacity for this brush */
    virtual void 	multiplyOpacity (const float multiple) throw () { brush->multiplyOpacity(multiple); }
    /** Check whether this brush is invisible */
    virtual bool 	isInvisible () const throw () { return brush->isInvisible(); }

    Brush(juce::Brush * _brush) : brush(_brush) {}
    ~Brush() { delete brush; brush = 0; }

    friend class BrushFactory;
    friend class Graphics;
};

/** This is a factory used to create Brushes.
    @warning You must call deleteBrush for each pointer returned. 
             This is because the memory tracking tools can be confused with heap allocated in a code segment and deallocated in another segment. */
class BrushFactory : public TwoDimensionalRendering::BrushFactory
{
    /** Create a gradient brush */
    virtual TwoDimensionalRendering::Brush * createGradientBrush(const TwoDimensionalRendering::Colour & colour1, const float x1, const float y1, const TwoDimensionalRendering::Colour & colour2, const float x2, const float y2, const bool isRadial) const 
    {
        return new Brush(new juce::GradientBrush(((Colour &)colour1).colour, x1, y1, ((Colour &)colour2).colour, x2, y2, isRadial));
    }
    /** Create a solid color brush */
    virtual TwoDimensionalRendering::Brush * createSolidColourBrush(const TwoDimensionalRendering::Colour & colour) const
    {
        return new Brush(new juce::SolidColourBrush(((Colour &)colour).colour));
    }
    /** Create an image brush */
    virtual TwoDimensionalRendering::Brush * createImageBrush(TwoDimensionalRendering::Image & image, const int anchorX, const int anchorY, const float opacity) const
    {
        return new Brush(new juce::ImageBrush(((Image &)image).image, anchorX, anchorY, opacity));
    }

    /** Delete a created brush */
    virtual void deleteBrush(TwoDimensionalRendering::Brush * brush) const throw() { delete (Brush*)brush; }
};

class Font : public TwoDimensionalRendering::Font
{
    juce::Font font;

 	/** Changes the name of the typeface family. */
    virtual void setTypefaceName (const TwoDimensionalRendering::String & faceName) throw () { font.setTypefaceName(juce::String::fromUTF8(faceName)); }
 	/** Returns the name of the typeface family that this font uses. */
    virtual const TwoDimensionalRendering::String getTypefaceName () const throw () { return font.getTypefaceName().toUTF8(); }
 	/** Returns the total height of this font. */
    virtual float 	getHeight () const throw () { return font.getHeight(); }
 	/** Changes the font's height. */
    virtual void 	setHeight (float newHeight) throw () { font.setHeight(newHeight); }
 	/** Changes the font's height without changing its width. */
    virtual void 	setHeightWithoutChangingWidth (float newHeight) throw () { font.setHeightWithoutChangingWidth(newHeight); }
 	/** Returns the height of the font above its baseline. */
    virtual float 	getAscent () const throw () { return font.getAscent(); }
 	/** Returns the amount that the font descends below its baseline. */
    virtual float 	getDescent () const throw () { return font.getDescent(); }
 	/** Returns the font's style flags. */
    virtual int 	getStyleFlags () const throw () { return font.getStyleFlags(); }
 	/** Changes the font's style. */
    virtual void 	setStyleFlags (const int newFlags) throw () { font.setStyleFlags(newFlags); }
 	/** Makes the font bold or non-bold. */
    virtual void 	setBold (const bool shouldBeBold) throw () { font.setBold(shouldBeBold); }
 	/** Returns true if the font is bold. */
    virtual bool 	isBold () const throw () { return font.isBold(); }
 	/** Makes the font italic or non-italic. */
    virtual void 	setItalic (const bool shouldBeItalic) throw () { font.setItalic(shouldBeItalic); }
 	/** Returns true if the font is italic. */
    virtual bool 	isItalic () const throw () { return font.isItalic(); }
 	/** Makes the font underlined or non-underlined. */
    virtual void 	setUnderline (const bool shouldBeUnderlined) throw () { font.setUnderline(shouldBeUnderlined); }
 	/** Returns true if the font is underlined. */
    virtual bool 	isUnderlined () const throw () { return font.isUnderlined(); }
 	/** Changes the font's horizontal scale factor. */
    virtual void 	setHorizontalScale (const float scaleFactor) throw () { font.setHorizontalScale(scaleFactor); }
 	/** Returns the font's horizontal scale. */
    virtual float 	getHorizontalScale () const throw () { return font.getHorizontalScale(); }
 	/** Changes the font's kerning. */
    virtual void 	setExtraKerningFactor (const float extraKerning) throw () { font.setExtraKerningFactor(extraKerning); }
 	/** Returns the font's kerning. */
    virtual float 	getExtraKerningFactor () const throw () { return font.getExtraKerningFactor(); }
 	/** Changes all the font's characteristics with one call. */
    virtual void 	setSizeAndStyle (const float newHeight, const int newStyleFlags, const float newHorizontalScale, const float newKerningAmount) throw () 
        { font.setSizeAndStyle(newHeight, newStyleFlags, newHorizontalScale, newKerningAmount); }
 	/** Resets this font's characteristics. */
    virtual void 	resetToDefaultState () throw () { font.resetToDefaultState(); }
 	/** Returns the total width of a string as it would be drawn using this font. */
    virtual float 	getStringWidthFloat (const TwoDimensionalRendering::String & text) const throw () { return font.getStringWidthFloat(juce::String::fromUTF8(text)); }

    Font(const juce::Font & _font) : font(_font) {}
    friend class FontFactory;
    friend class Graphics;
};


class FontFactory : public TwoDimensionalRendering::FontFactory
{
 	/** Creates a sans-serif font in a given size. */
    virtual TwoDimensionalRendering::Font * createSansSerifFont(const float fontHeight, const int styleFlags = TwoDimensionalRendering::Font::plain) const 
    { return new Font(juce::Font(juce::Font::getDefaultSansSerifFontName(), fontHeight, styleFlags)); }
 	/** Creates a font with a given typeface and parameters. */
    virtual TwoDimensionalRendering::Font * createFont(const TwoDimensionalRendering::String & typefaceName, const float fontHeight, const int styleFlags) const
    { return new Font(juce::Font(juce::String::fromUTF8(typefaceName), fontHeight, styleFlags)); }
    /** Delete created font */
    virtual void deleteFont(TwoDimensionalRendering::Font * font) const { delete (Font*)font; }
};


class Graphics : public TwoDimensionalRendering::Graphics
{
    juce::Graphics & graphic;
    /** Change the current drawing colour. */
    virtual void setColour (const TwoDimensionalRendering::Colour & newColour) throw () { graphic.setColour(((Colour&)newColour).colour); }
 	/** Returns the colour that's currently being used. */
    virtual const TwoDimensionalRendering::Colour * 	getCurrentColour () const throw () { return new Colour(graphic.getCurrentColour()); }
    /** Changes the opacity to use with the current colour. */
    virtual void setOpacity (const float newOpacity) throw () { graphic.setOpacity(newOpacity); }
 	/** Changes the current brush to use for drawing. */
    virtual void setBrush (const TwoDimensionalRendering::Brush * const newBrush) throw () { graphic.setBrush(((Brush*)newBrush)->brush); }
 	/** Changes the font to use for subsequent text-drawing functions. */
    virtual void setFont (const TwoDimensionalRendering::Font & newFont) throw () { graphic.setFont(((Font&)newFont).font); }
 	/** Changes the size and style of the currently-selected font. */
    virtual void setFont (const float newFontHeight, const int fontStyleFlags = Font::plain) throw () { graphic.setFont(newFontHeight, fontStyleFlags); }
 	/** Returns the font that's currently being used for text operations. */
    virtual const TwoDimensionalRendering::Font * getCurrentFont () const throw () { return new Font(graphic.getCurrentFont()); }
 	/** Draws a one-line text string. */
    virtual void drawSingleLineText (const TwoDimensionalRendering::String & text, const int startX, const int baselineY) const throw () { graphic.drawSingleLineText(juce::String::fromUTF8(text), startX, baselineY); }
 	/** Draws text across multiple lines. */
    virtual void drawMultiLineText (const TwoDimensionalRendering::String & text, const int startX, const int baselineY, const int maximumLineWidth) const throw () { graphic.drawMultiLineText(juce::String::fromUTF8(text), startX, baselineY, maximumLineWidth); }
 	/** Renders a string of text as a vector path. */
    virtual void drawTextAsPath (const TwoDimensionalRendering::String & text, const TwoDimensionalRendering::AffineTransform & transform) const throw () { graphic.drawTextAsPath(juce::String::fromUTF8(text), ((AffineTransform&)transform).object); }
 	/** Draws a line of text within a specified rectangle. */
    virtual void drawText (const TwoDimensionalRendering::String & text, const int x, const int y, const int width, const int height, const int justificationType, const bool useEllipsesIfTooBig) const throw () { graphic.drawText(juce::String::fromUTF8(text), x, y, width, height, justificationType, useEllipsesIfTooBig); }
 	/** Tries to draw a text string inside a given space. */
    virtual void drawFittedText (const TwoDimensionalRendering::String & text, const int x, const int y, const int width, const int height, const int justificationFlags, const int maximumNumberOfLines, const float minimumHorizontalScale=0.7f) const throw () { graphic.drawFittedText(juce::String::fromUTF8(text), x, y, width, height, justificationFlags, maximumNumberOfLines, minimumHorizontalScale); }
 	/** Fills the context's entire clip region with the current colour or brush. */
    virtual void fillAll () const throw () { graphic.fillAll(); }
 	/** Fills the context's entire clip region with a given colour. */
    virtual void fillAll (const TwoDimensionalRendering::Colour & colourToUse) const throw () { graphic.fillAll(((Colour&)colourToUse).colour); }
 	/** Fills a rectangle with the current colour or brush. */
    virtual void fillRect (const float x, const float y, const float width, const float height) const throw () { graphic.fillRect(x, y, width, height); }
 	/** Uses the current colour or brush to fill a rectangle with rounded corners. */
    virtual void fillRoundedRectangle (const float x, const float y, const float width, const float height, const float cornerSize) const throw () { graphic.fillRoundedRectangle(x, y, width, height, cornerSize); }
 	/** Fills a rectangle with a checkerboard pattern, alternating between two colours. */
    virtual void fillCheckerBoard (int x, int y, int width, int height, const int checkWidth, const int checkHeight, const TwoDimensionalRendering::Colour & colour1, const TwoDimensionalRendering::Colour & colour2) const throw () { graphic.fillCheckerBoard(x, y, width, height, checkWidth, checkHeight, ((Colour&)colour1).colour, ((Colour&)colour2).colour); }
 	/** Draws four lines to form a rectangular outline, using the current colour or brush. */
    virtual void drawRect (const int x, const int y, const int width, const int height, const int lineThickness=1) const throw () { graphic.drawRect(x, y, width, height, lineThickness); }
 	/** Uses the current colour or brush to draw the outline of a rectangle with rounded corners. */
    virtual void drawRoundedRectangle (const float x, const float y, const float width, const float height, const float cornerSize, const float lineThickness) const throw () { graphic.drawRoundedRectangle(x, y, width, height, cornerSize, lineThickness); }
 	/** Draws a 3D raised (or indented) bevel using two colours. */
    virtual void drawBevel (const int x, const int y, const int width, const int height, const int bevelThickness, const TwoDimensionalRendering::Colour & topLeftColour, const TwoDimensionalRendering::Colour & bottomRightColour, const bool useGradient=true) const throw () { graphic.drawBevel(x, y, width, height, bevelThickness, ((Colour&)topLeftColour).colour, ((Colour&)bottomRightColour).colour, useGradient); }
 	/** Draws a pixel using the current colour or brush. */
    virtual void setPixel (int x, int y) const throw () { graphic.setPixel(x, y); }
 	/** Fills an ellipse with the current colour or brush. */
    virtual void fillEllipse (const float x, const float y, const float width, const float height) const throw () { graphic.fillEllipse(x, y, width, height); }
 	/** Draws an elliptical stroke using the current colour or brush. */
    virtual void drawEllipse (const float x, const float y, const float width, const float height, const float lineThickness) const throw () { graphic.drawEllipse(x, y, width, height, lineThickness); }
 	/** Draws a line between two points with a given thickness. */
    virtual void drawLine (const float startX, const float startY, const float endX, const float endY, const float lineThickness = 1.0f) const throw () { graphic.drawLine(startX, startY, endX, endY, lineThickness); }
 	/** Draws a dashed line using a custom set of dash-lengths. */
    virtual void drawDashedLine (const float startX, const float startY, const float endX, const float endY, const float *const dashLengths, const int numDashLengths, const float lineThickness = 1.0f) const throw () { graphic.drawDashedLine(startX, startY, endX, endY, dashLengths, numDashLengths, lineThickness); }
 	/** Draws a vertical line of pixels at a given x position. */
    virtual void drawVerticalLine (const int x, float top, float bottom) const throw () { graphic.drawVerticalLine(x, top, bottom); }
 	/** Draws a horizontal line of pixels at a given y position. */
    virtual void drawHorizontalLine (const int y, float left, float right) const throw () { graphic.drawHorizontalLine(y, left, right); }
 	/** Fills a path using the currently selected colour or brush. */
    virtual void fillPath (const TwoDimensionalRendering::Path & path, const TwoDimensionalRendering::AffineTransform & transform) const throw () { graphic.fillPath((((Path&)path).path), ((AffineTransform&)transform).object); }
 	/** Draws a path's outline using the currently selected colour or brush. */
    virtual void strokePath (const TwoDimensionalRendering::Path & path, const TwoDimensionalRendering::PathStrokeType & strokeType, const TwoDimensionalRendering::AffineTransform & transform) const throw () { graphic.strokePath((((Path&)path).path), ((PathStrokeType&)strokeType).pathST, ((AffineTransform&)transform).object); }
 	/** Draws a line with an arrowhead. */
    virtual void drawArrow (const float startX, const float startY, const float endX, const float endY, const float lineThickness, const float arrowheadWidth, const float arrowheadLength) const throw () { graphic.drawArrow(startX, startY, endX, endY, lineThickness, arrowheadWidth, arrowheadLength); }
 	/** Draws an image. */
    virtual void drawImageAt (const TwoDimensionalRendering::Image * const imageToDraw, const int topLeftX, const int topLeftY, const bool fillAlphaChannelWithCurrentBrush = false) const throw () { graphic.drawImageAt(((Image*)imageToDraw)->image, topLeftX, topLeftY, fillAlphaChannelWithCurrentBrush); }
 	/** Draws part of an image, rescaling it to fit in a given target region. */
    virtual void drawImage (const TwoDimensionalRendering::Image * const imageToDraw, int destX, int destY, int destWidth, int destHeight, int sourceX, int sourceY, int sourceWidth, int sourceHeight, const bool fillAlphaChannelWithCurrentBrush = false) const throw () { graphic.drawImage(((Image*)imageToDraw)->image, destX, destY, destWidth, destHeight, sourceX, sourceY, sourceWidth, sourceHeight, fillAlphaChannelWithCurrentBrush); }
 	/** Draws part of an image, having applied an affine transform to it. */
    virtual void drawImageTransformed (const TwoDimensionalRendering::Image * const imageToDraw, int sourceClipX, int sourceClipY, int sourceClipWidth, int sourceClipHeight, const TwoDimensionalRendering::AffineTransform & transform, const bool fillAlphaChannelWithCurrentBrush) const throw () 
        { graphic.drawImageTransformed(((Image*)imageToDraw)->image, sourceClipX, sourceClipY, sourceClipWidth, sourceClipHeight, ((AffineTransform&)transform).object, fillAlphaChannelWithCurrentBrush); }
 	/** Returns the position of the bounding box for the current clipping region. */
    virtual void getClipBounds (int & x, int & y, int & width, int & height) const throw () { const juce::Rectangle & rect = graphic.getClipBounds(); x = rect.getX(), y = rect.getY(), width = rect.getWidth(), height = rect.getHeight(); }
 	/** Checks whether a rectangle overlaps the context's clipping region. */
    virtual bool clipRegionIntersects (const int x, const int y, const int width, const int height) const throw () { return graphic.clipRegionIntersects(x, y, width, height); }
 	/** Intersects the current clipping region with another region. */
    virtual bool reduceClipRegion (const int x, const int y, const int width, const int height) throw () { return graphic.reduceClipRegion(x, y, width, height); }
 	/** Excludes a rectangle to stop it being drawn into. */
    virtual void excludeClipRegion (const int x, const int y, const int width, const int height) throw () { graphic.excludeClipRegion(x, y, width, height); }
 	/** Returns true if no drawing can be done because the clip region is zero. */
    virtual bool isClipEmpty () const throw () { return graphic.isClipEmpty(); }
 	/** Saves the current graphics state on an internal stack. */
    virtual void saveState () throw () { graphic.saveState(); }
 	/** Restores a graphics state that was previously saved with saveState(). */
    virtual void restoreState () throw () { graphic.restoreState(); }
 	/** Moves the position of the context's origin. */
    virtual void setOrigin (const int newOriginX, const int newOriginY) throw () { graphic.setOrigin(newOriginX, newOriginY); }
 	/** Resets the current colour, brush, and font to default settings. */
    virtual void resetToDefaultState () throw () { graphic.resetToDefaultState(); }
 	/** Returns true if this context is drawing to a vector-based device, such as a printer.  */
    virtual bool isVectorDevice () const throw () { return graphic.isVectorDevice(); }
    /** Draw the given SVG file inside the given rectangle */
    virtual bool drawSVG(const TwoDimensionalRendering::String & fileName, const int destX, const int destY, const int destWidth, const int destHeight, const int justification) const 
    { 
        // Find the file
        juce::File file(juce::String::fromUTF8(fileName));
        if (!file.existsAsFile()) return false;
        
        juce::Drawable * drawable = juce::Drawable::createFromImageFile(file);
        if (!drawable) return false;
        int flags = (justification & TwoDimensionalRendering::Justification::left) ? juce::RectanglePlacement::xLeft : 0;
        flags |= (justification & TwoDimensionalRendering::Justification::right) ? juce::RectanglePlacement::xRight : 0;
        flags |= (justification & TwoDimensionalRendering::Justification::horizontallyCentred) ? juce::RectanglePlacement::xMid : 0;
        flags |= (justification & TwoDimensionalRendering::Justification::verticallyCentred) ? juce::RectanglePlacement::yMid : 0;
        flags |= (justification & TwoDimensionalRendering::Justification::top) ? juce::RectanglePlacement::yTop : 0;
        flags |= (justification & TwoDimensionalRendering::Justification::bottom) ? juce::RectanglePlacement::yBottom : 0;

        drawable->drawWithin(graphic, destX, destY, destWidth, destHeight, juce::RectanglePlacement(flags | juce::RectanglePlacement::doNotResize));
        delete drawable;
        return true;
    }

    Graphics(juce::Graphics & _graphic) : graphic(_graphic){}
};


class RenderingFactory : public TwoDimensionalRendering::RenderingFactory
{
    AffineTransformFactory affine;
    PathFactory path;
    ImageFactory image;
    BrushFactory brush;
    FontFactory font;


    virtual const TwoDimensionalRendering::AffineTransformFactory & getAffineTransformFactory() const { return affine; }
    virtual const TwoDimensionalRendering::PathFactory & getPathFactory() const { return path; }
    virtual const TwoDimensionalRendering::ImageFactory & getImageFactory() const { return image; }
    virtual const TwoDimensionalRendering::BrushFactory & getBrushFactory() const { return brush; }
    virtual const TwoDimensionalRendering::FontFactory & getFontFactory() const { return font; }
};