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