include/cinder/svg/Svg.h
Go to the documentation of this file.
00001 /*
00002  Copyright (c) 2012, The Cinder Project
00003  All rights reserved.
00004  
00005  This code is designed for use with the Cinder C++ library, http://libcinder.org
00006 
00007  Redistribution and use in source and binary forms, with or without modification, are permitted provided that
00008  the following conditions are met:
00009 
00010     * Redistributions of source code must retain the above copyright notice, this list of conditions and
00011     the following disclaimer.
00012     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
00013     the following disclaimer in the documentation and/or other materials provided with the distribution.
00014 
00015  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00016  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00017  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
00018  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00019  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00020  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00021  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00022  POSSIBILITY OF SUCH DAMAGE.
00023 */
00024 
00025 #pragma once
00026 
00027 #include "cinder/Cinder.h"
00028 #include "cinder/Xml.h"
00029 #include "cinder/Vector.h"
00030 #include "cinder/Color.h"
00031 #include "cinder/Shape2d.h"
00032 #include "cinder/PolyLine.h"
00033 #include "cinder/Exception.h"
00034 #include "cinder/MatrixAffine2.h"
00035 #include "cinder/Surface.h"
00036 #include "cinder/Font.h"
00037 #include "cinder/Function.h"
00038 
00039 #include <map>
00040 #include <boost/noncopyable.hpp>
00041 
00042 namespace cinder { namespace svg {
00043 
00044 typedef enum { FILL_RULE_NONZERO, FILL_RULE_EVENODD } FillRule;
00045 typedef enum { LINE_CAP_BUTT, LINE_CAP_ROUND, LINE_CAP_SQUARE } LineCap;
00046 typedef enum { LINE_JOIN_MITER, LINE_JOIN_ROUND, LINE_JOIN_BEVEL } LineJoin;
00047 typedef enum { WEIGHT_100, WEIGHT_200, WEIGHT_300, WEIGHT_400, WEIGHT_NORMAL = WEIGHT_400, WEIGHT_500, WEIGHT_600, WEIGHT_700, WEIGHT_BOLD = WEIGHT_700, WEIGHT_800, WEIGHT_900 } FontWeight;
00048 
00049 class Node;
00050 class Group;
00051 class Rect;
00052 class Circle;
00053 class Path;
00054 class TextSpan;
00055 class Style;
00056 class Line;
00057 class Ellipse;
00058 class Polyline;
00059 class Polygon;
00060 class Image;
00061 class ExcChildNotFound;
00062 
00063 typedef std::function<bool(const Node&, svg::Style *)> RenderVisitor;
00064 
00066 class Renderer {
00067   public:
00068     Renderer() {}
00069     
00070     virtual ~Renderer() {}
00071 
00072     void    setVisitor( const std::function<bool(const Node&, svg::Style *)> &visitor );
00073     
00074     virtual void    pushGroup( const Group &group, float opacity ) {}   
00075     virtual void    popGroup() {}   
00076     virtual void    drawPath( const svg::Path &path ) {}
00077     virtual void    drawPolyline( const svg::Polyline &polyline ) {}
00078     virtual void    drawPolygon( const svg::Polygon &polygon ) {}
00079     virtual void    drawLine( const svg::Line &line ) {}
00080     virtual void    drawRect( const svg::Rect &rect ) {}
00081     virtual void    drawCircle( const svg::Circle &circle ) {}
00082     virtual void    drawEllipse( const svg::Ellipse &ellipse ) {}
00083     virtual void    drawImage( const svg::Image &image ) {}
00084     virtual void    drawTextSpan( const svg::TextSpan &span ) {}
00085 
00086     virtual void    pushMatrix( const MatrixAffine2f &m ) {}
00087     virtual void    popMatrix() {}
00088     virtual void    pushStyle( const svg::Style &style ) {}
00089     virtual void    popStyle( const svg::Style &style ) {}  
00090     virtual void    pushFill( const class Paint &paint ) {}
00091     virtual void    popFill() {}
00092     virtual void    pushStroke( const class Paint &paint ) {}
00093     virtual void    popStroke() {}
00094     virtual void    pushFillOpacity( float opacity ) {}
00095     virtual void    popFillOpacity() {}
00096     virtual void    pushStrokeOpacity( float opacity ) {}
00097     virtual void    popStrokeOpacity() {}
00098     virtual void    pushStrokeWidth( float width ) {}
00099     virtual void    popStrokeWidth() {}
00100     virtual void    pushFillRule( FillRule rule ) {}
00101     virtual void    popFillRule() {}    
00102     virtual void    pushLineCap( LineCap lineCap ) {}
00103     virtual void    popLineCap() {} 
00104     virtual void    pushLineJoin( LineJoin lineJoin ) {}
00105     virtual void    popLineJoin() {}
00106     virtual void    pushTextPen( const Vec2f &penPos ) {}
00107     virtual void    popTextPen() {}
00108     virtual void    pushTextRotation( float rotation ) {}
00109     virtual void    popTextRotation() {}
00110 
00111     bool        visit( const Node &node, svg::Style *style ) const {
00112         if( mVisitor )
00113             return (*mVisitor)( node, style );
00114         else
00115             return true;
00116     }
00117     
00118   protected:
00119     // this is a shared_ptr to work around a bug in Clang 4.0
00120     std::shared_ptr<std::function<bool(const Node&, svg::Style *)> >        mVisitor;
00121     
00122     friend class svg::Node;
00123 };
00124 
00126 class Value {
00127   public:
00128     enum Unit { USER, PX, PERCENT, PT, PC, MM, CM, INCH, EM, EX };
00129     
00130     Value() : mValue( 0 ), mUnit( USER ) {}
00131     Value( float value, Unit unit = USER ) : mValue( value ), mUnit( unit ) {}
00132 
00133     float       asUser( float percentOf = 100, float dpi = 72, float fontSize = 12, float fontXHeight = 7 ) const;
00134 
00135     bool        isUser() const { return mUnit == USER; }
00136     bool        isPercent() const { return mUnit == PERCENT; }
00137     bool        isPixels() const { return mUnit == PX; }
00138 
00139     static Value        parse( const char **sInOut );
00140     static Value        parse( const std::string &s );
00141     
00142     Unit        mUnit;
00143     float       mValue;
00144 };
00145 
00147 class Paint {
00148   public:
00149     enum { NONE, COLOR, LINEAR_GRADIENT, RADIAL_GRADIENT };
00150     
00151     Paint();
00152     Paint( uint8_t type );
00153     Paint( const ColorA8u &color );
00154     
00155     static Paint    parse( const char *value, bool *specified, const Node *parentNode );
00156     
00157     bool            isNone() const { return mType == NONE; }
00158     bool            isLinearGradient() const { return mType == LINEAR_GRADIENT; }
00159     bool            isRadialGradient() const { return mType == RADIAL_GRADIENT; }
00160     const ColorA8u& getColor( size_t idx = 0 ) const { return mStops[idx].second; }
00161     float           getOffset( size_t idx ) const { return mStops[idx].first; }
00162     size_t          getNumColors() const { return mStops.size(); }
00163     
00164     // only apply to gradients
00165     Vec2f           getCoords0() const { return mCoords0; } // (x1,y1) on linear, (cx,cy) on radial
00166     Vec2f           getCoords1() const { return mCoords1; } // (x2,y2) on linear, (fx,fy) on radial
00167     float           getRadius() const { return mRadius; } // radial-only
00168     bool            useObjectBoundingBox() const { return mUseObjectBoundingBox; }
00169     bool            specifiesTransform() const { return mSpecifiesTransform; }
00170     MatrixAffine2f  getTransform() const { return mTransform; }
00171     
00172     uint8_t                                 mType;
00173     std::vector<std::pair<float,ColorA8u> > mStops;
00174     
00175     Vec2f               mCoords0, mCoords1;
00176     float               mRadius;
00177     bool                mUseObjectBoundingBox;
00178     MatrixAffine2f      mTransform;
00179     bool                mSpecifiesTransform;
00180 };
00181 
00183 class Style {
00184   public:
00185     Style();
00186     Style( const XmlTree &xml, const Node *parent );
00187 
00189     static Style    makeGlobalDefaults();
00191     void            clear();
00192 
00193     bool                specifiesFill() const { return mSpecifiesFill; }
00194     void                unspecifyFill() { mSpecifiesFill = false; }
00195     const Paint&        getFill() const { return mFill; }
00196     void                setFill( const Paint &fill ) { mSpecifiesFill = true; mFill = fill; }
00197     static const Paint& getFillDefault() { return sPaintBlack; }
00198 
00199     bool                specifiesStroke() const { return mSpecifiesStroke; }
00200     void                unspecifyStroke() { mSpecifiesStroke = false; }
00201     const Paint&        getStroke() const { return mStroke; }
00202     void                setStroke( const Paint &stroke ) { mSpecifiesStroke = true; mStroke = stroke; }
00203     static const Paint& getStrokeDefault() { return sPaintNone; }
00204 
00205     bool            specifiesOpacity() const { return mSpecifiesOpacity; }
00206     void            unspecifyOpacity() { mSpecifiesOpacity = false; }
00207     float           getOpacity() const { return mOpacity; }
00208     void            setOpacity( float opacity ) { mSpecifiesOpacity = true; mOpacity = opacity; }
00209     static float    getOpacityDefault() { return 1.0f; }
00210 
00211     bool            specifiesStrokeOpacity() const { return mSpecifiesStrokeOpacity; }
00212     void            unspecifyStrokeOpacity() { mSpecifiesStrokeOpacity = false; }
00213     float           getStrokeOpacity() const { return mStrokeOpacity; }
00214     void            setStrokeOpacity( float strokeOpacity ) { mSpecifiesStrokeOpacity = true; mStrokeOpacity = strokeOpacity; }
00215     static float    getStrokeOpacityDefault() { return 1.0f; }
00216 
00217     bool            specifiesFillOpacity() const { return mSpecifiesFillOpacity; }
00218     void            unspecifyFillOpacity() { mSpecifiesFillOpacity = false; }
00219     float           getFillOpacity() const { return mFillOpacity; }
00220     void            setFillOpacity( float fillOpacity ) { mSpecifiesFillOpacity = true; mFillOpacity = fillOpacity; }
00221     static float    getFillOpacityDefault() { return 1.0f; }
00222 
00223     bool            specifiesStrokeWidth() const { return mSpecifiesStrokeWidth; }
00224     void            unspecifyStrokeWidth() { mSpecifiesStrokeWidth = false; }
00225     float           getStrokeWidth() const { return mStrokeWidth; }
00226     void            setStrokeWidth( float strokeWidth ) { mSpecifiesStrokeWidth = true; mStrokeWidth = strokeWidth; }   
00227     static float    getStrokeWidthDefault() { return 1.0f; }
00228 
00229     bool            specifiesFillRule() const { return mSpecifiesFillRule; }
00230     void            unspecifyFillRule() { mSpecifiesFillRule = false; }
00231     FillRule        getFillRule() const { return mFillRule; }
00232     void            setFillRule( FillRule fillRule ) { mSpecifiesFillRule = true; mFillRule = fillRule; }   
00233     static FillRule getFillRuleDefault() { return svg::FILL_RULE_NONZERO; }
00234 
00235     bool            specifiesLineCap() const { return mSpecifiesLineCap; }
00236     void            unspecifyLineCap() { mSpecifiesLineCap = false; }
00237     LineCap         getLineCap() const { return mLineCap; }
00238     void            setLineCap( LineCap lineCap ) { mSpecifiesLineCap = true; mLineCap = lineCap; } 
00239     static LineCap  getLineCapDefault() { return svg::LINE_CAP_BUTT; }
00240 
00241     bool            specifiesLineJoin() const { return mSpecifiesLineJoin; }
00242     void            unspecifyLineJoin() { mSpecifiesLineJoin = false; }
00243     LineJoin        getLineJoin() const { return mLineJoin; }
00244     void            setLineJoin( LineJoin lineJoin ) { mSpecifiesLineJoin = true; mLineJoin = lineJoin; }   
00245     static LineJoin getLineJoinDefault() { return svg::LINE_JOIN_MITER; }
00246     
00247     // fonts
00248     bool                                    specifiesFontFamilies() const { return mSpecifiesFontFamilies; }
00249     void                                    unspecifyFontFamilies() { mSpecifiesFontFamilies = false; }
00250     const std::vector<std::string>&         getFontFamilies() const { return mFontFamilies; }
00251     std::vector<std::string>&               getFontFamilies() { return mFontFamilies; }
00252     void                                    setFontFamily( const std::string &family ) { mSpecifiesFontFamilies = true; mFontFamilies.clear(); mFontFamilies.push_back( family ); }
00253     void                                    setFontFamilies( const std::vector<std::string> &families ) { mSpecifiesFontFamilies = true; mFontFamilies = families; }
00254     static const std::vector<std::string>&  getFontFamiliesDefault();
00255     
00256     bool            specifiesFontSize() const { return mSpecifiesFontSize; }
00257     void            unspecifyFontSize() { mSpecifiesFontSize = false; }
00258     Value           getFontSize() const { return mFontSize; }
00259     void            setFontSize( const Value &fontSize ) { mSpecifiesFontSize = true; mFontSize = fontSize; }
00260     static Value    getFontSizeDefault() { return Value( 12 ); }
00261 
00262     bool                specifiesFontWeight() const { return mSpecifiesFontWeight; }
00263     void                unspecifyFontWeight() { mSpecifiesFontWeight = false; }
00264     FontWeight          getFontWeight() const { return mFontWeight; }
00265     void                setFontWeight( FontWeight weight ) { mSpecifiesFontWeight = true; mFontWeight = weight; }
00266     static FontWeight   getFontWeightDefault() { return svg::WEIGHT_NORMAL; }
00267 
00268     bool            specifiesVisible() const { return mSpecifiesVisible; }
00269     bool            isVisible() const { return mVisible; }
00270     void            setVisible( bool visible ) { mSpecifiesVisible = true; mVisible = visible; }
00271     void            unspecifyVisible() { mSpecifiesVisible = false; }
00272     
00273     bool            isDisplayNone() const { return mDisplayNone; }
00274     void            setDisplayNone( bool displayNone ) { mDisplayNone = displayNone; }
00275 
00276     void        startRender( Renderer &renderer, bool isNodeDrawable ) const;
00277     void        finishRender( Renderer &renderer, bool isNodeDrawable ) const;
00278 
00279     void        parseStyleAttribute( const std::string &stylePropertyString, const Node *parent );
00280     bool        parseProperty( const std::string &key, const std::string &value, const Node *parent );
00281 
00282   protected:
00283     bool            mSpecifiesOpacity;
00284     float           mOpacity;
00285     bool            mSpecifiesFillOpacity, mSpecifiesStrokeOpacity;
00286     float           mFillOpacity, mStrokeOpacity;
00287 
00288     bool            mSpecifiesFill, mSpecifiesStroke;
00289     Paint           mFill, mStroke;
00290     bool            mSpecifiesStrokeWidth;
00291     float           mStrokeWidth;   
00292     bool            mSpecifiesFillRule;
00293     FillRule        mFillRule;
00294     bool            mSpecifiesLineCap;
00295     LineCap         mLineCap;
00296     bool            mSpecifiesLineJoin;
00297     LineJoin        mLineJoin;
00298     
00299     // fonts
00300     bool            mSpecifiesFontFamilies, mSpecifiesFontSize, mSpecifiesFontWeight;
00301     std::vector<std::string>    mFontFamilies;
00302     Value           mFontSize;
00303     FontWeight      mFontWeight;
00304     
00305     // visibility
00306     bool            mSpecifiesVisible, mVisible, mDisplayNone;
00307     
00308   private:
00309     static Paint    sPaintNone, sPaintBlack;
00310 };
00311 
00313 class Node {
00314   public:
00315     Node( const Node *parent ) : mParent( parent ),  mSpecifiesTransform( false ), mBoundingBoxCached( false ) {}
00316     virtual ~Node() {}
00317     
00319     class Doc*          getDoc() const;
00321     const Node*         getParent() const { return mParent; }
00323     const std::string&  getId() const { return mId; }
00325     std::string         getDomPath() const;
00327     const Style&        getStyle() const { return mStyle; }
00329     void                setStyle( const Style &style ) { mStyle = style; }
00331     Style               calcInheritedStyle() const;
00332 
00334     virtual bool    containsPoint( const Vec2f &pt ) const { return false; }
00335     
00337     void            render( Renderer &renderer ) const;
00338 
00340     virtual const Node*     findInAncestors( const std::string &elementId ) const;
00342     Paint                   findPaintInAncestors( const std::string &paintName ) const;
00343 
00345     bool            specifiesTransform() const { return mSpecifiesTransform; }
00347     MatrixAffine2f      getTransform() const { return mTransform; }
00349     void                setTransform( const MatrixAffine2f &transform ) { mTransform = transform; mSpecifiesTransform = true; }
00351     void                unspecifyTransform() { mSpecifiesTransform = false; }
00353     MatrixAffine2f      getTransformInverse() const { return ( mSpecifiesTransform ) ? mTransform.invertCopy() : MatrixAffine2f::identity(); }
00355     MatrixAffine2f      getTransformAbsolute() const;
00357     MatrixAffine2f      getTransformAbsoluteInverse() const { return getTransformAbsolute().invertCopy(); }
00358 
00360     Rectf           getBoundingBox() const { if( ! mBoundingBoxCached ) { mBoundingBox = calcBoundingBox(); mBoundingBoxCached = true; } return mBoundingBox;  }
00362     Rectf           getBoundingBoxAbsolute() const { return getBoundingBox().transformCopy( getTransformAbsolute() ); }
00363 
00365     virtual Shape2d getShape() const { return Shape2d(); }
00367     Shape2d         getShapeAbsolute() const { return getShape().transformCopy( getTransformAbsolute() ); }
00368 
00370     const Paint&    getFill() const;
00372     const Paint&    getStroke() const;
00374     float           getOpacity() const;
00376     float           getFillOpacity() const;
00378     float           getStrokeOpacity() const;
00380     FillRule        getFillRule() const;
00382     LineCap         getLineCap() const;
00384     LineJoin        getLineJoin() const;
00386     float           getStrokeWidth() const;
00388     const std::vector<std::string>&     getFontFamilies() const;
00390     Value           getFontSize() const;
00392     bool            isVisible() const;
00394     bool            isDisplayNone() const { return mStyle.isDisplayNone(); }
00395 
00396 
00397   protected:
00398     Node( const Node *parent, const XmlTree &xml );
00399     // returns whether this type of node directly renders anything. Everything but groups.
00400     virtual bool    isDrawable() const { return true; }
00401 
00402     void            startRender( Renderer &renderer, const Style &style ) const;
00403     void            finishRender( Renderer &renderer, const Style &style ) const;
00404     virtual void    renderSelf( Renderer &renderer ) const = 0;
00405     
00406     virtual Rectf   calcBoundingBox() const { return Rectf( 0, 0, 0, 0 ); }
00407 
00408     static Paint        parsePaint( const char *value, bool *specified, const Node *parentNode );
00409     static MatrixAffine2f   parseTransform( const std::string &value );
00410     static bool         parseTransformComponent( const char **c, MatrixAffine2f *result );
00411     
00412     static std::string  findStyleValue( const std::string &styleString, const std::string &key );
00413     void                parseStyle( const std::string &value );
00414     
00415   protected:
00416     const Node      *mParent;
00417     std::string     mId;
00418     Style           mStyle;
00419     bool            mSpecifiesTransform;
00420     MatrixAffine2f  mTransform;
00421     mutable bool    mBoundingBoxCached;
00422     mutable Rectf   mBoundingBox;
00423     
00424   private:
00425     void            firstStartRender( Renderer &renderer ) const;
00426 
00427     friend class Group;
00428     friend class Use;
00429 };
00430 
00432 class Gradient : public Node {
00433   public:
00434     Gradient( const Node *parent, const XmlTree &xml );
00435     
00436     class Stop {
00437       public:
00438         Stop( const Node *parent, const XmlTree &xml );
00439         
00440         float       mOffset; // normalized 0-1
00441         ColorA8u    mColor;
00442         float       mOpacity;
00443         bool        mSpecifiesColor, mSpecifiesOpacity;
00444     };
00445 
00446     bool            useObjectBoundingBox() const { return mUseObjectBoundingBox; }
00447     bool            specifiesTransform() const { return mSpecifiesTransform; }
00448     
00449   protected:
00450     virtual void    renderSelf( Renderer &renderer ) const {}
00451 
00452     void        parse( const Node *parent, const XmlTree &xml );
00453     void        copyAttributesFrom( const Gradient &rhs );
00454     Paint       asPaint() const;
00455 
00456     std::vector<Stop>   mStops;
00457     Vec2f               mCoords0, mCoords1;
00458     bool                mUseObjectBoundingBox;
00459     bool                mSpecifiesTransform;
00460     MatrixAffine2f      mTransform;
00461 };
00462 
00464 class LinearGradient : public Gradient {
00465   public:
00466     LinearGradient( const Node *parent, const XmlTree &xml );
00467     
00468     Paint       asPaint() const;
00469     
00470   protected:
00471     void        parse( const XmlTree &xml );
00472     
00473     virtual bool    isDrawable() const { return false; }
00474 };
00475 
00477 class RadialGradient : public Gradient {
00478   public:
00479     RadialGradient( const Node *parent, const XmlTree &xml );
00480     
00481     Paint       asPaint() const;
00482     
00483   protected:
00484     void        parse( const XmlTree &xml );
00485 
00486     virtual bool    isDrawable() const { return false; }
00487     float           mRadius;
00488 };
00489 
00491 class Circle : public Node {
00492   public:
00493     Circle( const Node *parent ) : Node( parent ) {}
00494     Circle( const Node *parent, const XmlTree &xml );
00495     
00496     Vec2f       getCenter() const { return mCenter; }
00497     float       getRadius() const { return mRadius; }
00498 
00499     virtual bool    containsPoint( const Vec2f &pt ) const { return pt.distanceSquared( mCenter ) < mRadius * mRadius; }
00500 
00501     virtual Shape2d getShape() const;
00502 
00503   protected:    
00504     virtual void    renderSelf( Renderer &renderer ) const;
00505     virtual Rectf   calcBoundingBox() const { return Rectf( mCenter.x - mRadius, mCenter.y - mRadius, mCenter.x + mRadius, mCenter.y + mRadius ); }
00506 
00507     Vec2f       mCenter;
00508     float       mRadius;    
00509 };
00510 
00512 class Ellipse : public Node {
00513   public:
00514     Ellipse( const Node *parent ) : Node( parent ) {}
00515     Ellipse( const Node *parent, const XmlTree &xml );
00516     
00517     Vec2f       getCenter() const { return mCenter; }
00518     float       getRadiusX() const { return mRadiusX; }
00519     float       getRadiusY() const { return mRadiusY; }
00520 
00521     bool            containsPoint( const Vec2f &pt ) const;
00522 
00523     virtual Shape2d getShape() const;
00524 
00525   protected:
00526     virtual void    renderSelf( Renderer &renderer ) const;
00527     virtual Rectf   calcBoundingBox() const { return Rectf( mCenter.x - mRadiusX, mCenter.y - mRadiusY, mCenter.x + mRadiusX, mCenter.y + mRadiusY ); }
00528   
00529     Vec2f       mCenter;
00530     float       mRadiusX, mRadiusY;
00531 };
00532 
00534 class Path : public Node {
00535   public:
00536     Path( const Node *parent ) : Node( parent ) {}
00537     Path( const Node *parent, const XmlTree &xml );
00538     
00539     const Shape2d&      getShape2d() const { return mPath; }
00540     void                appendShape2d( Shape2d *appendTo ) const;
00541 
00542     virtual bool    containsPoint( const Vec2f &pt ) const { return mPath.contains( pt ); }
00543 
00544     virtual Shape2d getShape() const { return mPath; }
00545 
00546   protected:
00547     virtual void    renderSelf( Renderer &renderer ) const;
00548     virtual Rectf   calcBoundingBox() const { return mPath.calcPreciseBoundingBox(); }
00549         
00550     Shape2d     mPath;
00551 };
00552 
00554 class Line : public Node {
00555   public:
00556     Line( const Node *parent ) : Node( parent ) {}
00557     Line( const Node *parent, const XmlTree &xml );
00558     
00559     const Vec2f&    getPoint1() const { return mPoint1; }
00560     const Vec2f&    getPoint2() const { return mPoint2; }
00561 
00562     virtual Shape2d getShape() const;
00563     
00564   protected:
00565     virtual void    renderSelf( Renderer &renderer ) const;  
00566     virtual Rectf   calcBoundingBox() const { return Rectf( mPoint1, mPoint2 ); }   
00567     
00568     Vec2f       mPoint1, mPoint2;
00569 };
00570 
00572 class Rect : public Node {
00573   public:
00574     Rect( const Node *parent ) : Node( parent ) {}
00575     Rect( const Node *parent, const XmlTree &xml );
00576     
00577     const Rectf&    getRect() const { return mRect; }
00578 
00579     virtual bool    containsPoint( const Vec2f &pt ) const { return mRect.contains( pt ); } 
00580 
00581     virtual Shape2d getShape() const;
00582 
00583   protected:
00584     virtual void    renderSelf( Renderer &renderer ) const;
00585     virtual Rectf   calcBoundingBox() const { return mRect; }   
00586         
00587     Rectf           mRect;
00588 };
00589 
00591 class Polygon : public Node {
00592   public:
00593     Polygon( const Node *parent ) : Node( parent ) {}
00594     Polygon( const Node *parent, const XmlTree &xml );
00595 
00596     const PolyLine2f&   getPolyLine() const { return mPolyLine; }
00597     PolyLine2f&         getPolyLine() { return mPolyLine; }
00598 
00599     virtual bool    containsPoint( const Vec2f &pt ) const { return mPolyLine.contains( pt ); }     
00600 
00601     virtual Shape2d getShape() const;
00602         
00603   protected:
00604     virtual void    renderSelf( Renderer &renderer ) const;  
00605     virtual Rectf   calcBoundingBox() const { return Rectf( mPolyLine.getPoints() ); }
00606     
00607     PolyLine2f  mPolyLine;
00608 };
00609 
00611 class Polyline : public Node {
00612   public:
00613     Polyline( const Node *parent ) : Node( parent ) {}
00614     Polyline( const Node *parent, const XmlTree &xml );
00615 
00616     const PolyLine2f&   getPolyLine() const { return mPolyLine; }
00617     PolyLine2f&         getPolyLine() { return mPolyLine; }
00618 
00619     virtual bool    containsPoint( const Vec2f &pt ) const { return mPolyLine.contains( pt ); }
00620 
00621     virtual Shape2d getShape() const;
00622 
00623   protected:
00624     virtual void    renderSelf( Renderer &renderer ) const;
00625     virtual Rectf   calcBoundingBox() const { return Rectf( mPolyLine.getPoints() ); }
00626         
00627     PolyLine2f  mPolyLine;
00628 };
00629 
00631 class Use : public Node {
00632   public:
00633     Use( const Node *parent, const XmlTree &xml );
00634     
00635     virtual bool    isDrawable() const { return false; }
00636     
00637     virtual Shape2d getShape() const{ if( mReferenced ) return mReferenced->getShape(); else return Shape2d(); }
00638 
00639   protected:
00640     virtual void    renderSelf( Renderer &renderer ) const;  
00641     virtual Rectf   calcBoundingBox() const { if( mReferenced ) return mReferenced->getBoundingBox(); else return Rectf(0,0,0,0); }
00642     
00643     void parse( const XmlTree &xml );
00644     
00645     const Node      *mReferenced;
00646 };
00647 
00649 class Image : public Node {
00650   public:
00651     Image( const Node *parent, const XmlTree &xml );
00652 
00653     const Rectf&                        getRect() const { return mRect; }
00654     const std::shared_ptr<Surface8u>    getSurface() const { return mImage; }
00655 
00656     virtual bool    containsPoint( const Vec2f &pt ) const { return mRect.contains( pt ); }
00657 
00658   protected:
00659     virtual void    renderSelf( Renderer &renderer ) const;
00660     virtual Rectf   calcBoundingBox() const { return mRect; }
00661   
00662     static std::shared_ptr<Surface8u>   parseDataImage( const std::string &data );
00663 
00664     Rectf       mRect;
00665     fs::path    mFilePath;
00666     std::shared_ptr<Surface8u>  mImage;
00667 };
00668 
00669 typedef std::shared_ptr<TextSpan>   TextSpanRef;
00670 
00672 class TextSpan : public Node {
00673   public:
00674     class Attributes {
00675       public:
00676         Attributes() {}
00677         Attributes( const XmlTree &xml );
00678 
00679         void    startRender( Renderer &renderer ) const;
00680         void    finishRender( Renderer &renderer ) const;
00681 
00682         std::vector<Value>  mX, mY;
00683         float               mDx, mDy;
00684         std::vector<Value>  mRotate;
00685         float               mTextLength;
00686         float               mLengthAdjust;
00687     };
00688 
00689     TextSpan( const Node *parent, const XmlTree &xml );
00690     TextSpan( const Node *parent, const std::string &spanString );
00691     
00692     const std::string&                          getString() const { return mString; }
00693     const std::shared_ptr<Font>                 getFont() const;
00695     std::vector<std::pair<uint16_t,Vec2f> >     getGlyphMeasures() const;
00696     Vec2f                                       getTextPen() const;
00697     float                       getRotation() const;
00698     
00699   protected:
00700     virtual void    renderSelf( Renderer &renderer ) const;
00701 
00702     bool                            mIgnoreAttributes; // TextSpans that are actually the contents of Text's attributes should be ignored
00703     Attributes                      mAttributes;
00704     std::string                     mString;
00705     mutable std::shared_ptr<Font>   mFont;
00706     mutable std::shared_ptr<std::vector<std::pair<uint16_t,Vec2f> > > mGlyphMeasures;
00707     mutable std::shared_ptr<Shape2d>    mShape;
00708     
00709     std::vector<TextSpanRef>        mSpans;
00710     
00711     friend class Text;
00712 };
00713 
00715 class Text : public Node {
00716   public:
00717     Text( const Node *parent, const XmlTree &xml );
00718 
00719     Vec2f   getTextPen() const;
00720     float   getRotation() const;
00721     
00722   protected:
00723     virtual void    renderSelf( Renderer &renderer ) const;
00724 
00725     TextSpan::Attributes        mAttributes;
00726 
00727     std::vector<TextSpanRef>    mSpans;
00728 };
00729 
00731 class Group : public Node, private boost::noncopyable {
00732   public:
00733     Group( const Node *parent ) : Node( parent ) {}
00734     Group( const Node *parent, const XmlTree &xml );
00735     ~Group();
00736 
00738     template<typename T>
00739     const T*                find( const std::string &id ) { return dynamic_cast<const T*>( findNode( id ) ); }
00741     const Node*             findNode( const std::string &id, bool recurse = true ) const;
00743     template<typename T>
00744     const T*                findByIdContains( const std::string &idPartial ) { return dynamic_cast<const T*>( findNodeByIdContains( idPartial ) ); }
00746     const Node*             findNodeByIdContains( const std::string &idPartial, bool recurse = true ) const;
00747     virtual const Node*     findInAncestors( const std::string &elementId ) const;
00749     const Node&             getChild( const std::string &id ) const;
00751     const Node&             operator/( const std::string &id ) const { return getChild( id ); }
00752     
00754     virtual Shape2d getShape() const { return getMergedShape2d(); }
00755 
00757     void                    appendMergedShape2d( Shape2d *appendTo ) const;
00758 
00760     const std::list<Node*>& getChildren() const { return mChildren; }
00762     std::list<Node*>&       getChildren() { return mChildren; }
00763 
00764   protected:
00765     Node*       nodeUnderPoint( const Vec2f &absolutePoint, const MatrixAffine2f &parentInverseMatrix ) const;
00766     Shape2d     getMergedShape2d() const;
00767 
00768     virtual void    renderSelf( Renderer &renderer ) const;
00769     virtual Rectf   calcBoundingBox() const;
00770 
00771     virtual bool    isDrawable() const { return false; }
00772     void            parse( const XmlTree &xml );
00773 
00774     std::list<Node*>        mChildren;
00775     std::shared_ptr<Group>  mDefs;
00776 };
00777 
00778 
00779 typedef std::shared_ptr<Doc>    DocRef;
00781 class Doc : public Group {
00782   public:
00783     Doc() : Group( 0 ), mWidth( 0 ), mHeight( 0 ) {}
00784     Doc( const fs::path &filePath );
00785     Doc( DataSourceRef dataSource, const fs::path &filePath = fs::path() );
00786 
00787     static DocRef   create( const fs::path &filePath );
00788     static DocRef   create( DataSourceRef dataSource, const fs::path &filePath = fs::path() );
00789     static DocRef   createFromSvgz( DataSourceRef dataSource, const fs::path &filePath = fs::path() );
00790 
00792     int32_t     getWidth() const { return mWidth; }
00794     int32_t     getHeight() const { return mHeight; }
00796     Vec2i       getSize() const { return Vec2i( getWidth(), getHeight() ); }    
00798     float       getAspectRatio() const { return getWidth() / (float)getHeight(); }
00800     Area        getBounds() const { return Area( 0, 0, mWidth, mHeight ); }
00801     
00803     float       getDpi() const { return 72.0f; }
00804     
00806     Node*       nodeUnderPoint( const Vec2f &pt );
00807     
00809     std::shared_ptr<Surface8u>  loadImage( fs::path relativePath );
00810   private:
00811     void    loadDoc( DataSourceRef source, fs::path filePath );
00812 
00813     virtual void        renderSelf( Renderer &renderer ) const;
00814   
00815     std::shared_ptr<XmlTree>    mXmlTree;
00816     std::map<fs::path,std::shared_ptr<Surface8u> >  mImageCache;
00817     
00818     fs::path        mFilePath;
00819     Area            mViewBox;
00820     int32_t         mWidth, mHeight;
00821 };
00822 
00824 class Exc : public Exception
00825 {};
00826 
00827 class ValueExc : public Exc
00828 {};
00829 
00830 class FloatParseExc : public Exc
00831 {};
00832 
00833 class PathParseExc : public Exc
00834 {};
00835 
00836 class TransformParseExc : public Exc
00837 {};
00838 
00839 class ExcChildNotFound : public Exc {
00840   public:
00841     ExcChildNotFound( const std::string &child ) throw();
00842   
00843     virtual const char* what() const throw() { return mMessage; }
00844   
00845   private:
00846     char mMessage[2048];
00847 };
00848 
00849 
00850 } } // namespace cinder::svg