Code

r13127@tres: ted | 2006-07-30 22:18:42 -0700
authorgouldtj <gouldtj@users.sourceforge.net>
Mon, 31 Jul 2006 05:20:20 +0000 (05:20 +0000)
committergouldtj <gouldtj@users.sourceforge.net>
Mon, 31 Jul 2006 05:20:20 +0000 (05:20 +0000)
 Updates from the libwpg development CVS

src/extension/internal/libwpg/WPG2Parser.cpp
src/extension/internal/libwpg/WPG2Parser.h
src/extension/internal/libwpg/WPGPath.cpp
src/extension/internal/libwpg/WPGPath.h
src/extension/internal/wpg-input.cpp

index 43823d0b2c26c8924f3d999a688923940ea1d906..8b6a4a674e53193dde77fc6d0be28c9ead1ccd0b 100644 (file)
@@ -208,8 +208,7 @@ WPG2Parser::WPG2Parser(WPGInputStream *input, WPGPaintInterface* painter):
        m_xofs(0), m_yofs(0),
        m_width(0), m_height(0),
        m_doublePrecision(false),
-       m_layerOpened(false), m_layerId(0),
-       m_subIndex(0)
+       m_layerOpened(false), m_layerId(0)
 {
 }
 
@@ -294,9 +293,12 @@ bool WPG2Parser::parse()
        m_doublePrecision = false;
        m_layerOpened = false;
        m_matrix = WPG2TransformMatrix();
-       m_subIndex = 0;
-       while(!m_indexStack.empty())
-               m_indexStack.pop();
+       m_groupStack = std::stack<WPGGroupContext>();
+       m_compoundMatrix = WPG2TransformMatrix();
+       m_compoundWindingRule = false;
+       m_compoundFilled = false;
+       m_compoundFramed = true;
+       m_compoundClosed = false;
        
        // default style
        m_pen.foreColor = WPGColor(0,0,0);
@@ -319,8 +321,8 @@ bool WPG2Parser::parse()
                long nextPos = m_input->tell() + length;
                
                // inside a subgroup, one less sub record
-               if(m_subIndex > 0)
-                       m_subIndex--;
+               if(!m_groupStack.empty())
+                       m_groupStack.top().subIndex--;
 
                // search function to handler this record
                int index = -1;
@@ -351,11 +353,32 @@ bool WPG2Parser::parse()
                        }
                }
 
-               // we enter another subgroup, save the index to stack
+               // the last subgroup
+               if(!m_groupStack.empty())
+               {
+                       WPGGroupContext& context = m_groupStack.top();
+                       if(context.subIndex == 0)
+                       {
+                               if(context.isCompoundPolygon())
+                                       flushCompoundPolygon();
+                               m_groupStack.pop();
+                       }
+               }
+
+               // we enter another subgroup, save the context to stack
                if(extension > 0)
                {
-                       m_indexStack.push(m_subIndex);
-                       m_subIndex = extension;
+                       WPGGroupContext context;
+                       context.parentType = recordType;
+                       context.subIndex = extension;
+                       if(context.isCompoundPolygon())
+                       {
+                               context.compoundMatrix = m_compoundMatrix;
+                               context.compoundFilled = m_compoundFilled;
+                               context.compoundFramed = m_compoundFramed;
+                               context.compoundClosed = m_compoundClosed;
+                       }
+                       m_groupStack.push(context);
                }
 
                //if(m_input->tell() > nextPos)
@@ -513,8 +536,6 @@ void WPG2Parser::handleEndWPG()
 
        m_painter->endDocument();
        m_exit = true;
-       
-       WPG_DEBUG_MSG(("EndWPG\n"));
 }
 
 void WPG2Parser::handleLayer()
@@ -528,14 +549,32 @@ void WPG2Parser::handleLayer()
        m_painter->startLayer(m_layerId);
        m_layerOpened = true;
 
-       WPG_DEBUG_MSG(("Layer\n"));
-       WPG_DEBUG_MSG(("  Id: %d\n", m_layerId));
+       WPG_DEBUG_MSG(("  Layer Id: %d\n", m_layerId));
 }
 
 void WPG2Parser::handleCompoundPolygon()
 {
        ObjectCharacterization objCh;
        parseCharacterization(&objCh);
+
+       m_compoundWindingRule = objCh.windingRule;
+       m_compoundMatrix = objCh.matrix;
+       m_compoundFilled = objCh.filled;
+       m_compoundFramed = objCh.framed;
+       m_compoundClosed = objCh.closed;
+}
+void WPG2Parser::flushCompoundPolygon()
+{
+       WPGGroupContext& context = m_groupStack.top();
+       
+       m_painter->setBrush( context.compoundFilled ? m_brush : WPGBrush() );
+       m_painter->setPen( context.compoundFramed ? m_pen : WPGPen() );
+       if(context.compoundWindingRule)
+               m_painter->setFillRule(WPGPaintInterface::WindingFill);
+       else
+               m_painter->setFillRule(WPGPaintInterface::AlternatingFill);
+       context.compoundPath.closed = context.compoundClosed;
+       m_painter->drawPath(context.compoundPath);
 }
 
 void WPG2Parser::handlePenStyleDefinition()
@@ -544,7 +583,7 @@ void WPG2Parser::handlePenStyleDefinition()
        unsigned int segments = readU16();
 
        WPGDashArray dashArray;
-       for(int i = 0; i < segments; i++)
+       for(unsigned i = 0; i < segments; i++)
        {
                unsigned int p = (m_doublePrecision) ? readU32() : readU16();
                unsigned int q = (m_doublePrecision) ? readU32() : readU16();
@@ -553,7 +592,6 @@ void WPG2Parser::handlePenStyleDefinition()
        }
        m_penStyles[style] = dashArray;
 
-       WPG_DEBUG_MSG(("PenStyleDefinition\n"));
        WPG_DEBUG_MSG(("          Style : %d\n", style));
        WPG_DEBUG_MSG(("  Segment pairs : %d\n", segments));
 }
@@ -569,8 +607,7 @@ void WPG2Parser::handleColorPalette()
        unsigned startIndex = readU16();
        unsigned numEntries = readU16();
 
-       WPG_DEBUG_MSG(("Color Palette\n"));
-       for(int i = 0; i < numEntries; i++)
+       for(unsigned i = 0; i < numEntries; i++)
        {
                WPGColor color;
                color.red = readU8();
@@ -587,7 +624,6 @@ void WPG2Parser::handleDPColorPalette()
        unsigned startIndex = readU16();
        unsigned numEntries = readU16();
 
-       WPG_DEBUG_MSG(("Color Palette\n"));
        for(int i = 0; i < numEntries; i++)
        {
                WPGColor color;
@@ -609,7 +645,6 @@ void WPG2Parser::handlePenForeColor()
 
        m_pen.foreColor = WPGColor(red, green, blue, alpha);
 
-       WPG_DEBUG_MSG(("PenForeColor\n"));
        WPG_DEBUG_MSG(("   Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
 }
 
@@ -623,7 +658,6 @@ void WPG2Parser::handleDPPenForeColor()
 
        m_pen.foreColor = WPGColor(red, green, blue, alpha);
 
-       WPG_DEBUG_MSG(("PenForeColor\n"));
        WPG_DEBUG_MSG(("   Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
 }
 
@@ -636,7 +670,6 @@ void WPG2Parser::handlePenBackColor()
 
        m_pen.backColor = WPGColor(red, green, blue, alpha);
 
-       WPG_DEBUG_MSG(("PenBackColor\n"));
        WPG_DEBUG_MSG(("   Background color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
 }
 
@@ -650,7 +683,6 @@ void WPG2Parser::handleDPPenBackColor()
 
        m_pen.backColor = WPGColor(red, green, blue, alpha);
 
-       WPG_DEBUG_MSG(("PenBackColor\n"));
        WPG_DEBUG_MSG(("   Background color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
 }
 
@@ -661,7 +693,6 @@ void WPG2Parser::handlePenStyle()
        m_pen.dashArray = m_penStyles[style];
        m_pen.solid = (style == 0);
 
-       WPG_DEBUG_MSG(("PenStyle\n"));
        WPG_DEBUG_MSG(("   Pen style : %d\n", style));
        WPG_DEBUG_MSG(("   Segments : %d\n", m_pen.dashArray.count()));
 }
@@ -674,7 +705,6 @@ void WPG2Parser::handlePenSize()
        m_pen.width = TO_DOUBLE(width) / m_xres;
        m_pen.height = TO_DOUBLE(height) / m_yres;
 
-       WPG_DEBUG_MSG(("PenSize\n"));
        WPG_DEBUG_MSG(("   Width: %d\n", width));
        WPG_DEBUG_MSG(("   Height: %d\n", height));
 }
@@ -687,7 +717,6 @@ void WPG2Parser::handleDPPenSize()
        m_pen.width = TO_DOUBLE(width) / m_xres / 256;
        m_pen.height = TO_DOUBLE(height) / m_yres / 256;
 
-       WPG_DEBUG_MSG(("PenSize\n"));
        WPG_DEBUG_MSG(("   Width: %d\n", width));
        WPG_DEBUG_MSG(("   Height: %d\n", height));
 }
@@ -699,8 +728,8 @@ void WPG2Parser::handleBrushGradient()
        unsigned xref = readU16();
        unsigned yref = readU16();
        unsigned flag = readU16();
-       bool granular = flag & (1<<6);
-       bool anchor = flag & (1<<7);
+       bool granular = (flag & (1<<6)) == 1;
+       bool anchor = (flag & (1<<7)) == 1;
        
        // TODO: get gradient extent
        
@@ -721,8 +750,8 @@ void WPG2Parser::handleDPBrushGradient()
        unsigned xref = readU16();
        unsigned yref = readU16();
        unsigned flag = readU16();
-       bool granular = flag & (1<<6);
-       bool anchor = flag & (1<<7);
+       bool granular = (flag & (1<<6)) == 1;
+       bool anchor = (flag & (1<<7)) == 1;
        
        // TODO: get gradient extent (in double precision)
        
@@ -750,7 +779,7 @@ void WPG2Parser::handleBrushForeColor()
                WPG_DEBUG_MSG(("   Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
 
                m_brush.foreColor = WPGColor(red, green, blue, alpha);
-               if(m_brush.style == WPGBrush::NoBrush)
+               if(m_brush.style != WPGBrush::Gradient)
                        m_brush.style = WPGBrush::Solid;
        }
        else
@@ -802,20 +831,64 @@ void WPG2Parser::handleBrushForeColor()
 void WPG2Parser::handleDPBrushForeColor()
 {
        unsigned char gradientType = readU8();
+       WPG_DEBUG_MSG(("   Gradient type : %d (%s)\n", gradientType, describeGradient(gradientType)));
 
-       // we just ignore the least significant 8 bits
-       unsigned int red = (m_doublePrecision)   ? readU16()>>8 : readU8();
-       unsigned int green = (m_doublePrecision) ? readU16()>>8 : readU8();
-       unsigned int blue = (m_doublePrecision)  ? readU16()>>8 : readU8();
-       unsigned int alpha = (m_doublePrecision) ? readU16()>>8 : readU8();
+       if(gradientType == 0)
+       {
+               unsigned char red = (m_doublePrecision)   ? readU16()>>8 : readU8();
+               unsigned char green = (m_doublePrecision)   ? readU16()>>8 : readU8();
+               unsigned char blue = (m_doublePrecision)   ? readU16()>>8 : readU8();
+               unsigned char alpha = (m_doublePrecision)   ? readU16()>>8 : readU8();
+               WPG_DEBUG_MSG(("   Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
 
-       m_brush.foreColor = WPGColor(red, green, blue, alpha);
-       if(m_brush.style == WPGBrush::NoBrush)
-               m_brush.style = WPGBrush::Solid;
+               m_brush.foreColor = WPGColor(red, green, blue, alpha);
+               if(m_brush.style != WPGBrush::NoBrush)
+                       m_brush.style = WPGBrush::Solid;
+       }
+       else
+       {
+               unsigned count = readU16();
+               std::vector<WPGColor> colors;
+               std::vector<double> positions;
+               WPG_DEBUG_MSG(("  Gradient colors : %d\n", count));
 
-       WPG_DEBUG_MSG(("BrushForeColor\n"));
-       WPG_DEBUG_MSG(("   Gradient type : %d (%s)\n", gradientType, describeGradient(gradientType)));
-       WPG_DEBUG_MSG(("   Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
+               for(unsigned i = 0; i < count; i++)
+               {
+                       unsigned char red = (m_doublePrecision)   ? readU16()>>8 : readU8();
+                       unsigned char green = (m_doublePrecision)   ? readU16()>>8 : readU8();
+                       unsigned char blue = (m_doublePrecision)   ? readU16()>>8 : readU8();
+                       unsigned char alpha = (m_doublePrecision)   ? readU16()>>8 : readU8();
+                       WPGColor color(red, green, blue, alpha);
+                       colors.push_back(color);
+                       WPG_DEBUG_MSG(("   Color #%d (RGBA): %d %d %d %d\n", i+1, red, green, blue, alpha));
+               }
+
+               for(unsigned j = 0; j < count-1; j++)
+               {
+                       unsigned pos = readU16();
+                       positions.push_back(TO_DOUBLE(pos));
+                       WPG_DEBUG_MSG(("   Position #%d : %d\n", j+1, pos));
+               }
+               
+               // looks like Corel Presentations only create 2 colors gradient
+               // and they are actually in reverse order
+               if(count == 2)
+               {
+                       double xref = (double)m_gradientRef.x/65536.0;
+                       double yref = (double)m_gradientRef.y/65536.0;
+                       double angle = m_gradientAngle*M_PI/180.0;
+                       double tanangle = tan(angle);
+                       double ref = (tanangle<1e2) ? (yref+xref*tanangle)/(1+tanangle) : xref;
+                       WPGGradient gradient;
+                       gradient.setAngle(-m_gradientAngle); // upside down
+                       gradient.addStop(0, colors[1]);
+                       gradient.addStop(ref, colors[0]);
+                       if((m_gradientRef.x != 65535) && (m_gradientRef.y != 65536))
+                               gradient.addStop(1, colors[1]);
+                       m_brush.gradient = gradient;
+                       m_brush.style = WPGBrush::Gradient;
+               }
+       }
 }
 
 void WPG2Parser::handleBrushBackColor()
@@ -829,7 +902,6 @@ void WPG2Parser::handleBrushBackColor()
        if(m_brush.style == WPGBrush::NoBrush)
                m_brush.style = WPGBrush::Solid;
 
-       WPG_DEBUG_MSG(("BrushBackColor\n"));
        WPG_DEBUG_MSG(("   Backround color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
 }
 
@@ -845,7 +917,6 @@ void WPG2Parser::handleDPBrushBackColor()
        if(m_brush.style == WPGBrush::NoBrush)
                m_brush.style = WPGBrush::Solid;
 
-       WPG_DEBUG_MSG(("PenBackColor\n"));
        WPG_DEBUG_MSG(("   Background color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
 }
 
@@ -855,7 +926,6 @@ void WPG2Parser::handleBrushPattern()
 
        // TODO
 
-       WPG_DEBUG_MSG(("BrushPattern\n"));
        WPG_DEBUG_MSG(("   Pattern : %d\n", pattern));
 }
 
@@ -946,6 +1016,13 @@ void WPG2Parser::handlePolyline()
        parseCharacterization(&objCh);
        m_matrix = objCh.matrix;
 
+       bool insideCompound = m_groupStack.empty() ? false : 
+               m_groupStack.top().isCompoundPolygon();
+
+       // inside a compound, so take the parent transformation into account
+       if(insideCompound)
+               m_matrix.transformBy(m_groupStack.top().compoundMatrix); 
+
        unsigned long count = readU16();
 
        WPGPointArray points;
@@ -958,17 +1035,32 @@ void WPG2Parser::handlePolyline()
                points.add(p);
        }
 
-       m_painter->setBrush( objCh.filled ? m_brush : WPGBrush() );
-       m_painter->setPen( objCh.framed ? m_pen : WPGPen() );
-       if(objCh.windingRule)
-               m_painter->setFillRule(WPGPaintInterface::WindingFill);
+       if(insideCompound)
+       {
+               if(count > 0)
+               {
+                       // inside a compound ? convert it into path because for compound 
+                       // we will only use paths
+                       WPGPath& path = m_groupStack.top().compoundPath;
+                       path.moveTo(points[0]);
+                       for(unsigned long ii = 1; ii < count; ii++)
+                               path.lineTo(points[ii]);
+               }
+       }
        else
-               m_painter->setFillRule(WPGPaintInterface::AlternatingFill);
-       m_painter->drawPolygon(points);
+       {
+               // otherwise draw directly
+               m_painter->setBrush( objCh.filled ? m_brush : WPGBrush() );
+               m_painter->setPen( objCh.framed ? m_pen : WPGPen() );
+               if(objCh.windingRule)
+                       m_painter->setFillRule(WPGPaintInterface::WindingFill);
+               else
+                       m_painter->setFillRule(WPGPaintInterface::AlternatingFill);
+               m_painter->drawPolygon(points);
+       }
 
-       WPG_DEBUG_MSG(("Polyline\n"));
        WPG_DEBUG_MSG(("   Vertices count : %d\n", count));
-       for(int j = 0; j < count; j++ )
+       for(unsigned int j = 0; j < count; j++ )
                WPG_DEBUG_MSG(("        Point #%d : %g,%g\n", j+1, points[j].x, points[j].y));
 }
 
@@ -978,6 +1070,13 @@ void WPG2Parser::handlePolycurve()
        parseCharacterization(&objCh);
        m_matrix = objCh.matrix;
 
+       bool insideCompound = m_groupStack.empty() ? false : 
+               m_groupStack.top().isCompoundPolygon();
+
+       // inside a compound, so take the parent transformation into account
+       if(insideCompound)
+               m_matrix.transformBy(m_groupStack.top().compoundMatrix); 
+
        unsigned int count = readU16();
 
        WPGPointArray vertices;
@@ -1006,17 +1105,25 @@ void WPG2Parser::handlePolycurve()
        }
 
        WPGPath path;
+       path.closed = objCh.closed;
        path.moveTo(vertices[0]);
        for(unsigned j = 1; j < vertices.count(); j++)
                path.curveTo(controlPoints[j*2-2], controlPoints[j*2-1], vertices[j]);
 
-       m_painter->setBrush( objCh.filled ? m_brush : WPGBrush() );
-       m_painter->setPen( objCh.framed ? m_pen : WPGPen() );
-       if(objCh.windingRule)
-               m_painter->setFillRule(WPGPaintInterface::WindingFill);
+       if(insideCompound)
+               // inside a compound ? just collect the path together
+               m_groupStack.top().compoundPath.append(path);
        else
-               m_painter->setFillRule(WPGPaintInterface::AlternatingFill);
-       m_painter->drawPath(path);
+       {
+               // otherwise draw directly
+               m_painter->setBrush( objCh.filled ? m_brush : WPGBrush() );
+               m_painter->setPen( objCh.framed ? m_pen : WPGPen() );
+               if(objCh.windingRule)
+                       m_painter->setFillRule(WPGPaintInterface::WindingFill);
+               else
+                       m_painter->setFillRule(WPGPaintInterface::AlternatingFill);
+               m_painter->drawPath(path);
+       }
 }
 
 void WPG2Parser::handleRectangle()
@@ -1053,7 +1160,6 @@ void WPG2Parser::handleRectangle()
        m_painter->setPen( objCh.framed ? m_pen : WPGPen() );
        m_painter->drawRectangle(rect, roundx, roundy);
        
-       WPG_DEBUG_MSG(("Rectangle\n"));
        WPG_DEBUG_MSG(("      X1 : %d\n", x1));
        WPG_DEBUG_MSG(("      Y1 : %d\n", y1));
        WPG_DEBUG_MSG(("      X2 : %d\n", x2));
@@ -1095,7 +1201,6 @@ void WPG2Parser::handleArc()
                m_painter->drawEllipse(center, rx, ry);
        }
 
-       WPG_DEBUG_MSG(("Arc\n"));
        WPG_DEBUG_MSG(("   Center point x : %d\n", cx));
        WPG_DEBUG_MSG(("   Center point y : %d\n", cy));
        WPG_DEBUG_MSG(("         Radius x : %d\n", radx));
index e472ccee07e99dcbf1d336a73977730921ba3d9e..8fd0ab4cc970a1be1809d81131890d359463aab0 100644 (file)
@@ -74,6 +74,25 @@ public:
                rect.y2 = element[0][1]*r.x2 + element[1][1]*r.y2 + element[2][1]; 
                return rect;
        }
+
+       WPG2TransformMatrix& transformBy(const WPG2TransformMatrix& m)
+       {
+               double result[3][3];
+
+               for(int i = 0; i < 3; i++)
+                       for(int j = 0; j < 3; j++)
+                       {
+                               result[i][j] = 0;
+                               for(int k = 0; k < 3; k++)
+                                       result[i][j] += m.element[i][k]*element[k][j];
+                       }
+
+               for(int x = 0; x < 3; x++)
+                       for(int y = 0; y < 3; y++)
+                               element[x][y] = result[x][y];
+       
+               return *this;
+       }
 };
 
 class WPGCompoundPolygon
@@ -87,6 +106,25 @@ public:
        WPGCompoundPolygon(): matrix(), isFilled(true), isFramed(true), isClosed(true) {}
 };
 
+class WPGGroupContext
+{
+public:
+       unsigned subIndex;
+       int parentType;
+       WPGPath compoundPath;
+       WPG2TransformMatrix compoundMatrix;
+       bool compoundWindingRule;
+       bool compoundFilled;
+       bool compoundFramed;
+       bool compoundClosed;
+
+       WPGGroupContext(): subIndex(0), parentType(0), 
+       compoundPath(), compoundMatrix(), compoundWindingRule(false),
+       compoundFilled(false), compoundFramed(true), compoundClosed(false)      {}
+
+       bool isCompoundPolygon() const { return parentType == 0x1a; }
+};
+
 class WPG2Parser : public WPGXParser
 {
 public:
@@ -124,6 +162,7 @@ private:
        void handleArc();
        
        void resetPalette();
+       void flushCompoundPolygon();
 
        // parsing context
        bool m_success;
@@ -143,11 +182,12 @@ private:
        WPG2TransformMatrix m_matrix;
        double m_gradientAngle;
        WPGPoint m_gradientRef;
-       unsigned m_subIndex;
-       std::stack<unsigned> m_indexStack;
-
-       WPGCompoundPolygon m_currentCompound;
-       std::stack<WPGCompoundPolygon> m_compoundStack;
+       std::stack<WPGGroupContext> m_groupStack;
+       WPG2TransformMatrix m_compoundMatrix;
+       bool m_compoundWindingRule;
+       bool m_compoundFilled;
+       bool m_compoundFramed;
+       bool m_compoundClosed;
 
        class ObjectCharacterization;
        void parseCharacterization(ObjectCharacterization*);
index c04754d4248f7b987c42b6a4edd7fa9033c3cac3..a69ff3f72319fa5c65afe531996cb52d06b7739a 100644 (file)
@@ -44,6 +44,7 @@ using namespace libwpg;
 WPGPath::WPGPath()
 {
        d = new WPGPathPrivate;
+       closed = true;
 }
        
 WPGPath::~WPGPath()
@@ -103,4 +104,9 @@ void WPGPath::addElement(const WPGPathElement& element)
 {
        d->elements.push_back(element);
 }
-       
+
+void WPGPath::append(const WPGPath& path)
+{
+       for(unsigned i = 0; i < path.count(); i++)
+               addElement(path.element(i));
+}
index 889d4789c6ce448af5f1ddb46fbad0745b2a735f..85fcc5c8fc98918a2cd2a033d9a71ca42c5fbda1 100644 (file)
@@ -55,6 +55,8 @@ class WPGPathPrivate;
 class WPGPath
 {
 public:
+
+       bool closed;
        
        WPGPath();
        
@@ -76,6 +78,8 @@ public:
        
        void addElement(const WPGPathElement& element);
        
+       void append(const WPGPath& path);
+       
 private:
        WPGPathPrivate *d;
 };
index fc730a3ce6c03369e758d4042645dcb3206b5916..28e9476149c4c3bb736773b4b900c91c13c37fd1 100644 (file)
@@ -252,6 +252,10 @@ void InkscapePainter::drawPath(const WPGPath& path)
                                break;\r
                }\r
        }\r
+       \r
+       if(path.closed)\r
+               printf("Z");\r
+\r
        printf("\" \n");\r
        writeStyle();\r
        printf("/>\n");\r