LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/filter/source/svg - svgreader.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 1001 0.0 %
Date: 2013-07-09 Functions: 0 55 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  */
      12             : 
      13             : #include "svgreader.hxx"
      14             : #include <xmloff/attrlist.hxx>
      15             : #include "gfxtypes.hxx"
      16             : #include "units.hxx"
      17             : #include "parserfragments.hxx"
      18             : #include "tokenmap.hxx"
      19             : #include "b2dellipse.hxx"
      20             : 
      21             : #include <rtl/math.hxx>
      22             : #include <rtl/ref.hxx>
      23             : #include <rtl/ustring.hxx>
      24             : #include <rtl/ustrbuf.hxx>
      25             : #include <basegfx/vector/b2enums.hxx>
      26             : #include <basegfx/range/b2drange.hxx>
      27             : #include <basegfx/matrix/b2dhommatrix.hxx>
      28             : #include <basegfx/polygon/b2dpolypolygon.hxx>
      29             : #include <basegfx/polygon/b2dlinegeometry.hxx>
      30             : #include <basegfx/polygon/b2dpolygontools.hxx>
      31             : #include <basegfx/polygon/b2dpolypolygontools.hxx>
      32             : #include <com/sun/star/io/XSeekable.hpp>
      33             : #include <com/sun/star/xml/sax/XParser.hpp>
      34             : #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
      35             : #include <com/sun/star/xml/dom/NodeType.hpp>
      36             : 
      37             : #include <comphelper/processfactory.hxx>
      38             : #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
      39             : #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
      40             : #include <unotools/streamwrap.hxx>
      41             : #include <sax/tools/converter.hxx>
      42             : #include <vcl/graph.hxx>
      43             : #include <vcl/virdev.hxx>
      44             : #include <vcl/gradient.hxx>
      45             : #include <vcl/graphicfilter.hxx>
      46             : #include <tools/zcodec.hxx>
      47             : 
      48             : #include <boost/bind.hpp>
      49             : #include <boost/unordered_set.hpp>
      50             : #include <map>
      51             : #include <string.h>
      52             : 
      53             : #define OASIS_STR "urn:oasis:names:tc:opendocument:xmlns:"
      54             : 
      55             : using namespace ::com::sun::star;
      56             : 
      57             : namespace svgi
      58             : {
      59             : namespace
      60             : {
      61             : 
      62             : /** visits all children of the specified type with the given functor
      63             :  */
      64           0 : template<typename Func> void visitChildren(const Func& rFunc,
      65             :                                            const uno::Reference<xml::dom::XElement> xElem,
      66             :                                            xml::dom::NodeType eChildType )
      67             : {
      68           0 :     uno::Reference<xml::dom::XNodeList> xChildren( xElem->getChildNodes() );
      69           0 :     const sal_Int32 nNumNodes( xChildren->getLength() );
      70           0 :     for( sal_Int32 i=0; i<nNumNodes; ++i )
      71             :     {
      72             :         SAL_INFO("svg", "node type: " << sal::static_int_cast<sal_uInt32>(xChildren->item(i)->getNodeType()) << " tag name " << xChildren->item(i)->getNodeName() << " value |" << xChildren->item(i)->getNodeValue() << "|");
      73           0 :         if( xChildren->item(i)->getNodeType() == eChildType )
      74           0 :             rFunc( *xChildren->item(i).get() );
      75           0 :     }
      76           0 : }
      77             : 
      78             : /** Visit all elements of the given tree (in-order traversal)
      79             : 
      80             :     Given functor is called for every element, and passed the
      81             :     element's attributes, if any
      82             :  */
      83           0 : template<typename Func> void visitElements(Func& rFunc,
      84             :                                            const uno::Reference<xml::dom::XElement> xElem)
      85             : {
      86           0 :     if( xElem->hasAttributes() )
      87           0 :         rFunc(xElem,xElem->getAttributes());
      88             :     else
      89           0 :         rFunc(xElem);
      90             : 
      91             :     // notify children processing
      92           0 :     rFunc.push();
      93             : 
      94             :     // recurse over children
      95           0 :     uno::Reference<xml::dom::XNodeList> xChildren( xElem->getChildNodes() );
      96           0 :     const sal_Int32 nNumNodes( xChildren->getLength() );
      97           0 :     for( sal_Int32 i=0; i<nNumNodes; ++i )
      98             :     {
      99           0 :         if( xChildren->item(i)->getNodeType() == xml::dom::NodeType_ELEMENT_NODE )
     100           0 :             visitElements( rFunc,
     101             :                            uno::Reference<xml::dom::XElement>(
     102           0 :                                xChildren->item(i),
     103           0 :                                uno::UNO_QUERY_THROW) );
     104             :     }
     105             : 
     106             :     // children processing done
     107           0 :     rFunc.pop();
     108           0 : }
     109             : 
     110           0 : template<typename value_type> value_type square(value_type v)
     111             : {
     112           0 :     return v*v;
     113             : }
     114             : 
     115           0 : double colorDiffSquared(const ARGBColor& rCol1, const ARGBColor& rCol2)
     116             : {
     117             :     return
     118           0 :         square(rCol1.a-rCol2.a)
     119           0 :         + square(rCol1.r-rCol2.r)
     120           0 :         + square(rCol1.g-rCol2.g)
     121           0 :         + square(rCol1.b-rCol2.b);
     122             : }
     123             : 
     124             : typedef std::map<OUString,sal_Size> ElementRefMapType;
     125             : 
     126           0 : struct AnnotatingVisitor
     127             : {
     128           0 :     AnnotatingVisitor(StatePool&                                        rStatePool,
     129             :                       StateMap&                                         rStateMap,
     130             :                       const State&                                       rInitialState,
     131             :                       const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler) :
     132             :         mnCurrStateId(0),
     133             :         maCurrState(),
     134             :         maParentStates(),
     135             :         mrStates(rStatePool),
     136             :         mrStateMap(rStateMap),
     137             :         mxDocumentHandler(xDocumentHandler),
     138             :         maGradientVector(),
     139           0 :         maGradientStopVector()
     140             :     {
     141           0 :         maParentStates.push_back(rInitialState);
     142           0 :     }
     143             : 
     144           0 :     void operator()( const uno::Reference<xml::dom::XElement>& xElem)
     145             :     {
     146           0 :         const sal_Int32 nTagId(getTokenId(xElem->getTagName()));
     147           0 :         if (nTagId != XML_TEXT)
     148           0 :             return;
     149             : 
     150           0 :         maCurrState = maParentStates.back();
     151           0 :         maCurrState.maTransform.identity();
     152           0 :         maCurrState.maViewBox.reset();
     153             :         // if necessary, serialize to automatic-style section
     154           0 :         writeStyle(xElem,nTagId);
     155             :     }
     156             : 
     157           0 :     void operator()( const uno::Reference<xml::dom::XElement>&      xElem,
     158             :                      const uno::Reference<xml::dom::XNamedNodeMap>& xAttributes )
     159             :     {
     160           0 :         const sal_Int32 nTagId(getTokenId(xElem->getTagName()));
     161           0 :         switch (nTagId)
     162             :         {
     163             :             case XML_LINEARGRADIENT:
     164             :             {
     165           0 :                 const sal_Int32 nNumAttrs( xAttributes->getLength() );
     166           0 :                 maGradientVector.push_back(Gradient(Gradient::LINEAR));
     167             : 
     168             :                 // do we have a reference to a parent gradient? parse
     169             :                 // that first, as it sets our defaults here (manually
     170             :                 // tracking default state on each Gradient variable is
     171             :                 // much more overhead)
     172           0 :                 uno::Reference<xml::dom::XNode> xNode(xAttributes->getNamedItem("href"));
     173           0 :                 if(xNode.is())
     174             :                 {
     175           0 :                     const OUString sValue(xNode->getNodeValue());
     176           0 :                     ElementRefMapType::iterator aFound=maGradientIdMap.end();
     177           0 :                     if ( sValue.copy(0,1) == "#" )
     178           0 :                         aFound = maGradientIdMap.find(sValue.copy(1));
     179             :                     else
     180           0 :                         aFound = maGradientIdMap.find(sValue);
     181             : 
     182           0 :                     if( aFound != maGradientIdMap.end() )
     183           0 :                         maGradientVector.back() = maGradientVector[aFound->second];
     184             :                 }
     185             : 
     186             :                 // do that after dereferencing, to prevent hyperlinked
     187             :                 // gradient to clobber our Id again
     188           0 :                 maGradientVector.back().mnId = maGradientVector.size()-1;
     189           0 :                 maGradientVector.back().meType = Gradient::LINEAR; // has been clobbered as well
     190             : 
     191           0 :                 for( sal_Int32 i=0; i<nNumAttrs; ++i )
     192             :                 {
     193           0 :                     parseLinearGradientData( maGradientVector.back(),
     194           0 :                                              maGradientVector.size()-1,
     195           0 :                                              getTokenId(xAttributes->item(i)->getNodeName()),
     196           0 :                                              xAttributes->item(i)->getNodeValue() );
     197             :                 }
     198           0 :                 break;
     199             :             }
     200             :             case XML_RADIALGRADIENT:
     201             :             {
     202           0 :                 const sal_Int32 nNumAttrs( xAttributes->getLength() );
     203           0 :                 maGradientVector.push_back(Gradient(Gradient::RADIAL));
     204             : 
     205             :                 // do we have a reference to a parent gradient? parse
     206             :                 // that first, as it sets our defaults here (manually
     207             :                 // tracking default state on each Gradient variable is
     208             :                 // much more overhead)
     209           0 :                 uno::Reference<xml::dom::XNode> xNode(xAttributes->getNamedItem("href"));
     210           0 :                 if(xNode.is())
     211             :                 {
     212           0 :                     const OUString sValue(xNode->getNodeValue());
     213           0 :                     ElementRefMapType::iterator aFound=maGradientIdMap.end();
     214           0 :                     if ( sValue.copy(0,1) == "#" )
     215           0 :                         aFound = maGradientIdMap.find(sValue.copy(1));
     216             :                     else
     217           0 :                         aFound = maGradientIdMap.find(sValue);
     218             : 
     219           0 :                     if( aFound != maGradientIdMap.end() )
     220           0 :                         maGradientVector.back() = maGradientVector[aFound->second];
     221             :                 }
     222             : 
     223             :                 // do that after dereferencing, to prevent hyperlinked
     224             :                 // gradient to clobber our Id again
     225           0 :                 maGradientVector.back().mnId = maGradientVector.size()-1;
     226           0 :                 maGradientVector.back().meType = Gradient::RADIAL; // has been clobbered as well
     227             : 
     228           0 :                 for( sal_Int32 i=0; i<nNumAttrs; ++i )
     229             :                 {
     230           0 :                     parseRadialGradientData( maGradientVector.back(),
     231           0 :                                              maGradientVector.size()-1,
     232           0 :                                              getTokenId(xAttributes->item(i)->getNodeName()),
     233           0 :                                              xAttributes->item(i)->getNodeValue() );
     234             :                 }
     235           0 :                 break;
     236             :             }
     237             :             case XML_STOP:
     238             :             {
     239           0 :                 const sal_Int32 nNumAttrs( xAttributes->getLength() );
     240           0 :                 maGradientStopVector.push_back(GradientStop());
     241           0 :                 maGradientVector.back().maStops.push_back(maGradientStopVector.size()-1);
     242           0 :                 for( sal_Int32 i=0; i<nNumAttrs; ++i )
     243             :                 {
     244           0 :                     parseGradientStop( maGradientStopVector.back(),
     245           0 :                                        maGradientStopVector.size()-1,
     246           0 :                                        getTokenId(xAttributes->item(i)->getNodeName()),
     247           0 :                                        xAttributes->item(i)->getNodeValue() );
     248             :                 }
     249           0 :                 break;
     250             :             }
     251             :             default:
     252             :             {
     253             :                 // init state. inherit defaults from parent.
     254           0 :                 maCurrState = maParentStates.back();
     255           0 :                 maCurrState.maTransform.identity();
     256           0 :                 maCurrState.maViewBox.reset();
     257             : 
     258             :                 // scan for style info
     259           0 :                 const sal_Int32 nNumAttrs( xAttributes->getLength() );
     260           0 :                 OUString sAttributeValue;
     261           0 :                 for( sal_Int32 i=0; i<nNumAttrs; ++i )
     262             :                 {
     263           0 :                     sAttributeValue = xAttributes->item(i)->getNodeValue();
     264             :                     const sal_Int32 nTokenId(
     265           0 :                         getTokenId(xAttributes->item(i)->getNodeName()));
     266           0 :                     if( XML_STYLE == nTokenId )
     267           0 :                         parseStyle(sAttributeValue);
     268             :                     else
     269             :                         parseAttribute(nTokenId,
     270           0 :                                        sAttributeValue);
     271             :                 }
     272             : 
     273             :                 // all attributes parsed, can calc total CTM now
     274           0 :                 basegfx::B2DHomMatrix aLocalTransform;
     275           0 :                 if( !maCurrState.maViewBox.isEmpty() &&
     276           0 :                     maCurrState.maViewBox.getWidth() != 0.0 &&
     277           0 :                     maCurrState.maViewBox.getHeight() != 0.0 )
     278             :                 {
     279             :                     // transform aViewBox into viewport, keep aspect ratio
     280           0 :                     aLocalTransform.translate(-maCurrState.maViewBox.getMinX(),
     281           0 :                                               -maCurrState.maViewBox.getMinY());
     282           0 :                     double scaleW = maCurrState.maViewport.getWidth()/maCurrState.maViewBox.getWidth();
     283           0 :                     double scaleH = maCurrState.maViewport.getHeight()/maCurrState.maViewBox.getHeight();
     284           0 :                     double scale = (scaleW < scaleH) ? scaleW : scaleH;
     285           0 :                     aLocalTransform.scale(scale,scale);
     286             :                 }
     287           0 :                 maCurrState.maCTM = maCurrState.maCTM*maCurrState.maTransform*aLocalTransform;
     288             : 
     289             :                 OSL_TRACE("annotateStyle - CTM is: %f %f %f %f %f %f",
     290             :                           maCurrState.maCTM.get(0,0),
     291             :                           maCurrState.maCTM.get(0,1),
     292             :                           maCurrState.maCTM.get(0,2),
     293             :                           maCurrState.maCTM.get(1,0),
     294             :                           maCurrState.maCTM.get(1,1),
     295             :                           maCurrState.maCTM.get(1,2));
     296             : 
     297             :                 // if necessary, serialize to automatic-style section
     298           0 :                 writeStyle(xElem,nTagId);
     299             :             }
     300             :         }
     301           0 :     }
     302             : 
     303           0 :     OUString getStyleName( const char* sPrefix, sal_Int32 nId )
     304             :     {
     305           0 :         return OUString::createFromAscii(sPrefix)+OUString::valueOf(nId);
     306             :     }
     307             : 
     308           0 :     bool hasGradientOpacity( const Gradient& rGradient )
     309             :     {
     310             :         return
     311           0 :             (rGradient.maStops.size() > 1) &&
     312             :             (maGradientStopVector[
     313           0 :                  rGradient.maStops[0]].maStopColor.a != 1.0 ||
     314             :              maGradientStopVector[
     315           0 :                  rGradient.maStops[1]].maStopColor.a != 1.0);
     316             :     }
     317             : 
     318             :     struct StopSorter
     319             :     {
     320           0 :         explicit StopSorter( const std::vector< GradientStop >& rStopVec ) :
     321           0 :             mrStopVec(rStopVec)
     322           0 :         {}
     323             : 
     324           0 :         bool operator()( sal_Size rLHS, sal_Size rRHS )
     325             :         {
     326           0 :             return mrStopVec[rLHS].mnStopPosition < mrStopVec[rRHS].mnStopPosition;
     327             :         }
     328             : 
     329             :         const std::vector< GradientStop >& mrStopVec;
     330             :     };
     331             : 
     332           0 :     void optimizeGradientStops( Gradient& rGradient )
     333             :     {
     334             :         // sort for increasing stop position
     335             :         std::sort(rGradient.maStops.begin(),rGradient.maStops.end(),
     336           0 :                   StopSorter(maGradientStopVector));
     337             : 
     338           0 :         if( rGradient.maStops.size() < 3 )
     339           0 :             return; //easy! :-)
     340             : 
     341             :         // join similar colors
     342           0 :         std::vector<sal_Size> aNewStops(1,rGradient.maStops.front());
     343           0 :         for( sal_Size i=1; i<rGradient.maStops.size(); ++i )
     344             :         {
     345           0 :             if( maGradientStopVector[rGradient.maStops[i]].maStopColor !=
     346           0 :                 maGradientStopVector[aNewStops.back()].maStopColor )
     347           0 :                 aNewStops.push_back(rGradient.maStops[i]);
     348             :         }
     349             : 
     350           0 :         rGradient.maStops = aNewStops;
     351           0 :         if (rGradient.maStops.size() < 2)
     352             :         {
     353           0 :             return; // can't optimize further...
     354             :         }
     355             : 
     356             :         // axial gradient, maybe?
     357           0 :         if( rGradient.meType == Gradient::LINEAR &&
     358           0 :             rGradient.maStops.size() == 3 &&
     359           0 :             maGradientStopVector[rGradient.maStops.front()].maStopColor ==
     360           0 :             maGradientStopVector[rGradient.maStops.back()].maStopColor )
     361             :         {
     362             :             // yep - keep it at that
     363           0 :             return;
     364             :         }
     365             : 
     366             :         // find out most significant color difference, and limit to
     367             :         // those two stops around this border (metric is
     368             :         // super-simplistic: take euclidean distance of colors, weigh
     369             :         // with stop distance)
     370           0 :         sal_Size nMaxIndex=0;
     371           0 :         double    fMaxDistance=0.0;
     372           0 :         for( sal_Size i=1; i<rGradient.maStops.size(); ++i )
     373             :         {
     374             :             const double fCurrDistance(
     375             :                 colorDiffSquared(
     376           0 :                     maGradientStopVector[rGradient.maStops[i-1]].maStopColor,
     377           0 :                     maGradientStopVector[rGradient.maStops[i]].maStopColor) *
     378           0 :                 (square(maGradientStopVector[rGradient.maStops[i-1]].mnStopPosition) +
     379           0 :                  square(maGradientStopVector[rGradient.maStops[i]].mnStopPosition)) );
     380             : 
     381           0 :             if( fCurrDistance > fMaxDistance )
     382             :             {
     383           0 :                 nMaxIndex = i-1;
     384           0 :                 fMaxDistance = fCurrDistance;
     385             :             }
     386             :         }
     387           0 :         rGradient.maStops[0] = rGradient.maStops[nMaxIndex];
     388           0 :         rGradient.maStops[1] = rGradient.maStops[nMaxIndex+1];
     389           0 :         rGradient.maStops.erase(rGradient.maStops.begin()+2,rGradient.maStops.end());
     390             :     }
     391             : 
     392           0 :     sal_Int8 toByteColor( double val )
     393             :     {
     394             :         // TODO(Q3): duplicated from vcl::unotools
     395             :         return sal::static_int_cast<sal_Int8>(
     396           0 :             basegfx::fround(val*255.0));
     397             :     }
     398             : 
     399           0 :     OUString getOdfColor( const ARGBColor& rColor )
     400             :     {
     401             :         // TODO(Q3): duplicated from pdfimport
     402           0 :         OUStringBuffer aBuf( 7 );
     403           0 :         const sal_uInt8 nRed  ( toByteColor(rColor.r)   );
     404           0 :         const sal_uInt8 nGreen( toByteColor(rColor.g) );
     405           0 :         const sal_uInt8 nBlue ( toByteColor(rColor.b)  );
     406           0 :         aBuf.append( sal_Unicode('#') );
     407           0 :         if( nRed < 0x10 )
     408           0 :             aBuf.append( sal_Unicode('0') );
     409           0 :         aBuf.append( sal_Int32(nRed), 16 );
     410           0 :         if( nGreen < 0x10 )
     411           0 :             aBuf.append( sal_Unicode('0') );
     412           0 :         aBuf.append( sal_Int32(nGreen), 16 );
     413           0 :         if( nBlue < 0x10 )
     414           0 :             aBuf.append( sal_Unicode('0') );
     415           0 :         aBuf.append( sal_Int32(nBlue), 16 );
     416             : 
     417             :         // TODO(F3): respect alpha transparency (polygons etc.)
     418             :         OSL_ASSERT(rColor.a == 1.0);
     419             : 
     420           0 :         return aBuf.makeStringAndClear();
     421             :     }
     422             : 
     423           0 :     OUString getOdfAlign( TextAlign eAlign )
     424             :     {
     425           0 :         static OUString aStart("start");
     426           0 :         static OUString aEnd("end");
     427             :         // static OUString aJustify("justify");
     428           0 :         static OUString aCenter("center");
     429           0 :         switch(eAlign)
     430             :         {
     431             :             default:
     432             :             case BEFORE:
     433           0 :                 return aStart;
     434             :             case CENTER:
     435           0 :                 return aCenter;
     436             :             case AFTER:
     437           0 :                 return aEnd;
     438             :         }
     439             :     }
     440             : 
     441           0 :     bool writeStyle(State& rState, const sal_Int32 nTagId)
     442             :     {
     443           0 :         rtl::Reference<SvXMLAttributeList> xAttrs( new SvXMLAttributeList() );
     444           0 :         uno::Reference<xml::sax::XAttributeList> xUnoAttrs( xAttrs.get() );
     445             : 
     446           0 :         if (XML_TEXT == nTagId) {
     447           0 :             rState.mbIsText = true;
     448           0 :             basegfx::B2DTuple aScale, aTranslate;
     449             :             double fRotate, fShearX;
     450           0 :             if (rState.maCTM.decompose(aScale, aTranslate, fRotate, fShearX))
     451             :             {
     452           0 :                 rState.mnFontSize *= aScale.getX();
     453           0 :             }
     454             :         }
     455             : 
     456             :         std::pair<StatePool::iterator,
     457           0 :                   bool> aRes = mrStates.insert(rState);
     458             :         SAL_INFO ("svg", "size " << mrStates.size() << "   id " <<  const_cast<State&>(*aRes.first).mnStyleId);
     459             : 
     460           0 :         if( !aRes.second )
     461           0 :             return false; // not written
     462             : 
     463           0 :         ++mnCurrStateId;
     464             : 
     465             :         // mnStyleId does not take part in hashing/comparison
     466           0 :         const_cast<State&>(*aRes.first).mnStyleId = mnCurrStateId;
     467             :         SAL_INFO ("svg", " --> " <<  const_cast<State&>(*aRes.first).mnStyleId);
     468             : 
     469             :         mrStateMap.insert(std::make_pair(
     470             :                               mnCurrStateId,
     471           0 :                               rState));
     472             : 
     473             :         // find two representative stop colors (as ODF only support
     474             :         // start&end color)
     475           0 :         optimizeGradientStops(rState.maFillGradient);
     476             : 
     477           0 :         if( !mxDocumentHandler.is() )
     478           0 :             return true; // cannot write style, svm import case
     479             : 
     480             :         // do we have a gradient fill? then write out gradient as well
     481           0 :         if( rState.meFillType == GRADIENT && rState.maFillGradient.maStops.size() > 1 )
     482             :         {
     483             :             // TODO(F3): ODF12 supposedly also groks svg:linear/radialGradient. But CL says: nope.
     484           0 :             xAttrs->AddAttribute( "draw:name", getStyleName("svggradient", rState.maFillGradient.mnId) );
     485           0 :             if( rState.maFillGradient.meType == Gradient::LINEAR )
     486             :             {
     487             :                 // should the optimizeGradientStops method decide that
     488             :                 // this is a three-color gradient, it prolly wanted us
     489             :                 // to take axial instead
     490             :                 xAttrs->AddAttribute( "draw:style",
     491           0 :                                       rState.maFillGradient.maStops.size() == 3 ?
     492             :                                       OUString("axial") :
     493           0 :                                       OUString("linear") );
     494             :             }
     495             :             else
     496             :             {
     497           0 :                 xAttrs->AddAttribute( "draw:style", "ellipsoid" );
     498           0 :                 xAttrs->AddAttribute( "draw:cx", "50%" );
     499           0 :                 xAttrs->AddAttribute( "draw:cy", "50%" );
     500             :             }
     501             : 
     502           0 :             basegfx::B2DTuple rScale, rTranslate;
     503             :             double rRotate, rShearX;
     504           0 :             if( rState.maFillGradient.maTransform.decompose(rScale, rTranslate, rRotate, rShearX) )
     505             :                 xAttrs->AddAttribute( "draw:angle",
     506           0 :                                       OUString::valueOf(rRotate*1800.0/M_PI ) );
     507             :             xAttrs->AddAttribute( "draw:start-color",
     508             :                                   getOdfColor(
     509             :                                       maGradientStopVector[
     510           0 :                                           rState.maFillGradient.maStops[0]].maStopColor) );
     511             :             xAttrs->AddAttribute( "draw:end-color",
     512             :                                   getOdfColor(
     513             :                                       maGradientStopVector[
     514           0 :                                           rState.maFillGradient.maStops[1]].maStopColor) );
     515           0 :             xAttrs->AddAttribute( "draw:border", "0%" );
     516           0 :             mxDocumentHandler->startElement( "draw:gradient", xUnoAttrs );
     517           0 :             mxDocumentHandler->endElement( "draw:gradient" );
     518             : 
     519           0 :             if( hasGradientOpacity(rState.maFillGradient) )
     520             :             {
     521             :                 // need to write out opacity style as well
     522           0 :                 xAttrs->Clear();
     523           0 :                 xAttrs->AddAttribute( "draw:name", getStyleName("svgopacity", rState.maFillGradient.mnId) );
     524           0 :                 if( rState.maFillGradient.meType == Gradient::LINEAR )
     525             :                 {
     526           0 :                     xAttrs->AddAttribute( "draw:style", "linear" );
     527             :                 }
     528             :                 else
     529             :                 {
     530           0 :                     xAttrs->AddAttribute( "draw:style", "ellipsoid" );
     531           0 :                     xAttrs->AddAttribute( "draw:cx", "50%" );
     532           0 :                     xAttrs->AddAttribute( "draw:cy", "50%" );
     533             :                 }
     534             : 
     535             :                 // modulate gradient opacity with overall fill opacity
     536             :                 xAttrs->AddAttribute( "draw:end",
     537             :                                       OUString::valueOf(
     538             :                                           maGradientStopVector[
     539           0 :                                               rState.maFillGradient.maStops[0]].maStopColor.a*
     540           0 :                                           maCurrState.mnFillOpacity*maCurrState.mnOpacity*100.0)+"%" );
     541             :                 xAttrs->AddAttribute( "draw:start",
     542             :                                       OUString::valueOf(
     543             :                                           maGradientStopVector[
     544           0 :                                               rState.maFillGradient.maStops[1]].maStopColor.a*
     545           0 :                                           maCurrState.mnFillOpacity*maCurrState.mnOpacity*100.0)+"%" );
     546           0 :                 xAttrs->AddAttribute( "draw:border", "0%" );
     547           0 :                 mxDocumentHandler->startElement( "draw:opacity", xUnoAttrs );
     548           0 :                 mxDocumentHandler->endElement( "draw:opacity" );
     549           0 :             }
     550             :         }
     551             : 
     552             :         // serialize to automatic-style section
     553           0 :         if( nTagId == XML_TEXT )
     554             :         {
     555             :             // write paragraph style attributes
     556           0 :             xAttrs->Clear();
     557             : 
     558           0 :             xAttrs->AddAttribute( "style:name", getStyleName("svgparagraphstyle", mnCurrStateId) );
     559           0 :             xAttrs->AddAttribute( "style:family", "paragraph" );
     560           0 :             mxDocumentHandler->startElement( "style:style", xUnoAttrs );
     561             : 
     562           0 :             xAttrs->Clear();
     563           0 :             xAttrs->AddAttribute( "fo:text-align", getOdfAlign(rState.meTextAnchor));
     564             : 
     565           0 :             mxDocumentHandler->startElement( "style:paragraph-properties", xUnoAttrs );
     566           0 :             mxDocumentHandler->endElement( "style:paragraph-properties" );
     567           0 :             mxDocumentHandler->endElement( "style:style" );
     568             : 
     569             :             // write text style attributes
     570           0 :             xAttrs->Clear();
     571             : 
     572           0 :             xAttrs->AddAttribute( "style:name", getStyleName("svgtextstyle", mnCurrStateId) );
     573           0 :             xAttrs->AddAttribute( "style:family", "text" );
     574           0 :             mxDocumentHandler->startElement( "style:style", xUnoAttrs );
     575           0 :             xAttrs->Clear();
     576           0 :             xAttrs->AddAttribute( "fo:font-family", rState.maFontFamily);
     577             :             xAttrs->AddAttribute( "fo:font-size",
     578           0 :                                   OUString::valueOf(pt2mm(rState.mnFontSize))+"mm");
     579           0 :             xAttrs->AddAttribute( "fo:font-style", rState.maFontStyle);
     580           0 :             xAttrs->AddAttribute( "fo:font-variant", rState.maFontVariant);
     581             :             xAttrs->AddAttribute( "fo:font-weight",
     582           0 :                                   OUString::valueOf(rState.mnFontWeight));
     583           0 :             xAttrs->AddAttribute( "fo:color", getOdfColor(rState.maFillColor));
     584             : 
     585           0 :             mxDocumentHandler->startElement( "style:text-properties", xUnoAttrs );
     586           0 :             mxDocumentHandler->endElement( "style:text-properties" );
     587           0 :             mxDocumentHandler->endElement( "style:style" );
     588             :         }
     589             : 
     590           0 :         xAttrs->Clear();
     591           0 :         xAttrs->AddAttribute( "style:name" , getStyleName("svggraphicstyle", mnCurrStateId) );
     592           0 :         xAttrs->AddAttribute( "style:family", "graphic" );
     593           0 :         mxDocumentHandler->startElement( "style:style", xUnoAttrs );
     594             : 
     595           0 :         xAttrs->Clear();
     596             :         // text or shape? if the former, no use in processing any
     597             :         // graphic attributes except stroke color, ODF can do ~nothing
     598             :         // with text shapes
     599           0 :         if( nTagId == XML_TEXT )
     600             :         {
     601             :             //xAttrs->AddAttribute( "draw:auto-grow-height", "true");
     602           0 :             xAttrs->AddAttribute( "draw:auto-grow-width", "true");
     603           0 :             xAttrs->AddAttribute( "draw:textarea-horizontal-align", "left");
     604             :             //xAttrs->AddAttribute( "draw:textarea-vertical-align", "top");
     605           0 :             xAttrs->AddAttribute( "fo:min-height", "0cm");
     606             : 
     607           0 :             xAttrs->AddAttribute( "fo:padding-top", "0cm");
     608           0 :             xAttrs->AddAttribute( "fo:padding-left", "0cm");
     609           0 :             xAttrs->AddAttribute( "fo:padding-right", "0cm");
     610           0 :             xAttrs->AddAttribute( "fo:padding-bottom", "0cm");
     611             : 
     612             :             // disable any background shape
     613           0 :             xAttrs->AddAttribute( "draw:stroke", "none");
     614           0 :             xAttrs->AddAttribute( "draw:fill", "none");
     615             :         }
     616             :         else
     617             :         {
     618           0 :             if( rState.meFillType != NONE )
     619             :             {
     620           0 :                 if( rState.meFillType == GRADIENT )
     621             :                 {
     622           0 :                     xAttrs->AddAttribute( "draw:fill", "gradient");
     623             :                     xAttrs->AddAttribute( "draw:fill-gradient-name",
     624           0 :                                           getStyleName("svggradient", rState.maFillGradient.mnId) );
     625           0 :                     if( hasGradientOpacity(rState.maFillGradient) )
     626             :                     {
     627             :                         // needs transparency gradient as well
     628             :                         xAttrs->AddAttribute( "draw:opacity-name",
     629           0 :                                               getStyleName("svgopacity", rState.maFillGradient.mnId) );
     630             :                     }
     631           0 :                     else if( maCurrState.mnFillOpacity*maCurrState.mnOpacity != 1.0 )
     632             :                         xAttrs->AddAttribute( "draw:opacity",
     633           0 :                                               OUString::valueOf(100.0*maCurrState.mnFillOpacity*maCurrState.mnOpacity)+"%" );
     634             :                 }
     635             :                 else
     636             :                 {
     637           0 :                     xAttrs->AddAttribute( "draw:fill", "solid");
     638           0 :                     xAttrs->AddAttribute( "draw:fill-color", getOdfColor(rState.maFillColor));
     639           0 :                     if( maCurrState.mnFillOpacity*maCurrState.mnOpacity != 1.0 )
     640             :                         xAttrs->AddAttribute( "draw:opacity",
     641           0 :                                               OUString::valueOf(100.0*maCurrState.mnFillOpacity*maCurrState.mnOpacity)+"%" );
     642             :                 }
     643             :             }
     644             :             else
     645           0 :                 xAttrs->AddAttribute( "draw:fill", "none");
     646             : 
     647           0 :             if( rState.meStrokeType == SOLID )
     648             :             {
     649           0 :                 xAttrs->AddAttribute( "draw:stroke", "solid");
     650           0 :                 xAttrs->AddAttribute( "svg:stroke-color", getOdfColor(rState.maStrokeColor));
     651             :             }
     652           0 :             else if( rState.meStrokeType == DASH )
     653             :             {
     654           0 :                 xAttrs->AddAttribute( "draw:stroke", "dash");
     655           0 :                 xAttrs->AddAttribute( "draw:stroke-dash", "dash"+OUString::valueOf(mnCurrStateId));
     656           0 :                 xAttrs->AddAttribute( "svg:stroke-color", getOdfColor(rState.maStrokeColor));
     657             :             }
     658             :             else
     659           0 :                 xAttrs->AddAttribute( "draw:stroke", "none");
     660             : 
     661           0 :             if( maCurrState.mnStrokeWidth != 0.0 )
     662             :             {
     663           0 :                 ::basegfx::B2DVector aVec(maCurrState.mnStrokeWidth,0);
     664           0 :                 aVec *= maCurrState.maCTM;
     665           0 :                 xAttrs->AddAttribute( "svg:stroke-width", OUString::valueOf( pt2mm(aVec.getLength()) )+"mm");
     666             :             }
     667           0 :             if( maCurrState.meLineJoin == basegfx::B2DLINEJOIN_MITER )
     668           0 :                 xAttrs->AddAttribute( "draw:stroke-linejoin", "miter");
     669           0 :             else if( maCurrState.meLineJoin == basegfx::B2DLINEJOIN_ROUND )
     670           0 :                 xAttrs->AddAttribute( "draw:stroke-linejoin", "round");
     671           0 :             else if( maCurrState.meLineJoin == basegfx::B2DLINEJOIN_BEVEL )
     672           0 :                 xAttrs->AddAttribute( "draw:stroke-linejoin", "bevel");
     673           0 :             if( maCurrState.mnStrokeOpacity*maCurrState.mnOpacity != 1.0 )
     674             :                 xAttrs->AddAttribute( "svg:stroke-opacity",
     675           0 :                                       OUString::valueOf(100.0*maCurrState.mnStrokeOpacity*maCurrState.mnOpacity)+"%");
     676             :         }
     677             : 
     678           0 :         mxDocumentHandler->startElement( "style:graphic-properties", xUnoAttrs );
     679           0 :         mxDocumentHandler->endElement( "style:graphic-properties" );
     680           0 :         mxDocumentHandler->endElement( "style:style" );
     681             : 
     682           0 :         return true; // newly written
     683             :     }
     684             : 
     685           0 :     void writeStyle(const uno::Reference<xml::dom::XElement>& xElem, const sal_Int32 nTagId)
     686             :     {
     687             :         SAL_INFO ("svg", "writeStyle xElem " << xElem->getTagName());
     688             : 
     689           0 :         sal_Int32 nStyleId=0;
     690           0 :         if( writeStyle(maCurrState, nTagId) )
     691           0 :             nStyleId = mnCurrStateId;
     692             :         else
     693           0 :             nStyleId = mrStates.find(maCurrState)->mnStyleId;
     694             : 
     695           0 :         xElem->setAttribute("internal-style-ref",
     696             :                             OUString::valueOf(
     697             :                                 nStyleId)
     698           0 :                             +"$0");
     699           0 :     }
     700             : 
     701           0 :     void push()
     702             :     {
     703           0 :         maParentStates.push_back(maCurrState);
     704           0 :     }
     705             : 
     706           0 :     void pop()
     707             :     {
     708           0 :         maParentStates.pop_back();
     709           0 :     }
     710             : 
     711           0 :     void parseLinearGradientData( Gradient& io_rCurrGradient,
     712             :                                   const sal_Int32 nGradientNumber,
     713             :                                   const sal_Int32 nTokenId,
     714             :                                   const OUString& sValue )
     715             :     {
     716           0 :         switch(nTokenId)
     717             :         {
     718             :             case XML_GRADIENTTRANSFORM:
     719             :             {
     720             :                 OString aValueUtf8( sValue.getStr(),
     721             :                                          sValue.getLength(),
     722           0 :                                          RTL_TEXTENCODING_UTF8 );
     723           0 :                 parseTransform(aValueUtf8.getStr(),io_rCurrGradient.maTransform);
     724           0 :                 break;
     725             :             }
     726             :             case XML_X1:
     727           0 :                 io_rCurrGradient.maCoords.linear.mfX1 = convLength(sValue,maCurrState,'h');
     728           0 :                 break;
     729             :             case XML_X2:
     730           0 :                 io_rCurrGradient.maCoords.linear.mfX2 = convLength(sValue,maCurrState,'h');
     731           0 :                 break;
     732             :             case XML_Y1:
     733           0 :                 io_rCurrGradient.maCoords.linear.mfY1 = convLength(sValue,maCurrState,'v');
     734           0 :                 break;
     735             :             case XML_Y2:
     736           0 :                 io_rCurrGradient.maCoords.linear.mfY2 = convLength(sValue,maCurrState,'v');
     737           0 :                 break;
     738             :             case XML_ID:
     739           0 :                 maGradientIdMap.insert(std::make_pair(sValue,nGradientNumber));
     740           0 :                 break;
     741             :             case XML_GRADIENTUNITS:
     742           0 :                 if (getTokenId(sValue) == XML_OBJECTBOUNDINGBOX)
     743           0 :                     io_rCurrGradient.mbBoundingBoxUnits = true;
     744             :                 else
     745           0 :                     io_rCurrGradient.mbBoundingBoxUnits = false;
     746           0 :                 break;
     747             :             default:
     748           0 :                 break;
     749             :         }
     750           0 :     }
     751             : 
     752           0 :     void parseRadialGradientData( Gradient& io_rCurrGradient,
     753             :                                   const sal_Int32 nGradientNumber,
     754             :                                   const sal_Int32 nTokenId,
     755             :                                   const OUString& sValue )
     756             :     {
     757           0 :         switch(nTokenId)
     758             :         {
     759             :             case XML_GRADIENTTRANSFORM:
     760             :             {
     761             :                 OString aValueUtf8( sValue.getStr(),
     762             :                                          sValue.getLength(),
     763           0 :                                          RTL_TEXTENCODING_UTF8 );
     764           0 :                 parseTransform(aValueUtf8.getStr(),io_rCurrGradient.maTransform);
     765           0 :                 break;
     766             :             }
     767             :             case XML_CX:
     768           0 :                 io_rCurrGradient.maCoords.radial.mfCX = convLength(sValue,maCurrState,'h');
     769           0 :                 break;
     770             :             case XML_CY:
     771           0 :                 io_rCurrGradient.maCoords.radial.mfCY = convLength(sValue,maCurrState,'v');
     772           0 :                 break;
     773             :             case XML_FX:
     774           0 :                 io_rCurrGradient.maCoords.radial.mfFX = convLength(sValue,maCurrState,'h');
     775           0 :                 break;
     776             :             case XML_FY:
     777           0 :                 io_rCurrGradient.maCoords.radial.mfFY = convLength(sValue,maCurrState,'v');
     778           0 :                 break;
     779             :             case XML_R:
     780           0 :                 io_rCurrGradient.maCoords.radial.mfR = convLength(sValue,maCurrState,'r');
     781           0 :                 break;
     782             :             case XML_ID:
     783           0 :                 maGradientIdMap.insert(std::make_pair(sValue,nGradientNumber));
     784           0 :                 break;
     785             :             case XML_GRADIENTUNITS:
     786           0 :                 if (getTokenId(sValue) == XML_OBJECTBOUNDINGBOX)
     787           0 :                     io_rCurrGradient.mbBoundingBoxUnits = true;
     788             :                 else
     789           0 :                     io_rCurrGradient.mbBoundingBoxUnits = false;
     790           0 :                 break;
     791             :             default:
     792           0 :                 break;
     793             :         }
     794           0 :     }
     795             : 
     796           0 :     void parseGradientStop( GradientStop& io_rGradientStop,
     797             :                             const sal_Int32 nStopNumber,
     798             :                             const sal_Int32 nTokenId,
     799             :                             const OUString& sValue )
     800             :     {
     801           0 :         switch(nTokenId)
     802             :         {
     803             :             case XML_HREF:
     804             :             {
     805           0 :                 ElementRefMapType::iterator aFound=maStopIdMap.end();
     806           0 :                 if ( sValue.copy(0,1) == "#" )
     807           0 :                     aFound = maStopIdMap.find(sValue.copy(1));
     808             :                 else
     809           0 :                     aFound = maStopIdMap.find(sValue);
     810             : 
     811           0 :                 if( aFound != maStopIdMap.end() )
     812           0 :                     io_rGradientStop =  maGradientStopVector[aFound->second];
     813           0 :                 break;
     814             :             }
     815             :             case XML_ID:
     816           0 :                 maStopIdMap.insert(std::make_pair(sValue,nStopNumber));
     817           0 :                 break;
     818             :             case XML_OFFSET:
     819           0 :                 io_rGradientStop.mnStopPosition = sValue.toDouble();
     820           0 :                 break;
     821             :             case XML_STYLE:
     822           0 :                 parseStyle( sValue );
     823           0 :                 break;
     824             :             default:
     825           0 :                 break;
     826             :         }
     827           0 :     }
     828             : 
     829           0 :     void parseAttribute( const sal_Int32      nTokenId,
     830             :                          const OUString& sValue )
     831             :     {
     832             :         OString aValueUtf8( sValue.getStr(),
     833             :                                  sValue.getLength(),
     834           0 :                                  RTL_TEXTENCODING_UTF8 );
     835           0 :         switch(nTokenId)
     836             :         {
     837             :             case XML_WIDTH:
     838             :             {
     839             :                 const double fViewPortWidth(
     840           0 :                     convLength(sValue,maCurrState,'h'));
     841             : 
     842             :                 maCurrState.maViewport.expand(
     843           0 :                     basegfx::B2DTuple(fViewPortWidth,0.0));
     844           0 :                 break;
     845             :             }
     846             :             case XML_HEIGHT:
     847             :             {
     848             :                 const double fViewPortHeight(
     849           0 :                     convLength(sValue,maCurrState,'v'));
     850             : 
     851             :                 maCurrState.maViewport.expand(
     852           0 :                     basegfx::B2DTuple(0.0,fViewPortHeight));
     853           0 :                 break;
     854             :             }
     855             :             case XML_VIEWBOX:
     856             :             {
     857             :                 // TODO(F1): preserveAspectRatio
     858             :                 parseViewBox(
     859             :                     aValueUtf8.getStr(),
     860           0 :                     maCurrState.maViewBox);
     861           0 :                 break;
     862             :             }
     863             :             case XML_FILL_RULE:
     864             :             {
     865           0 :                 if( aValueUtf8 == "evenodd" )
     866           0 :                     maCurrState.meFillRule = EVEN_ODD;
     867           0 :                 else if( aValueUtf8 == "nonzero" )
     868           0 :                     maCurrState.meFillRule = NON_ZERO;
     869           0 :                 else if( aValueUtf8 == "inherit" )
     870           0 :                     maCurrState.meFillRule = maParentStates.back().meFillRule;
     871           0 :                 break;
     872             :             }
     873             :             case XML_OPACITY:
     874           0 :                 if( aValueUtf8 == "inherit" )
     875           0 :                     maCurrState.mnOpacity = maParentStates.back().mnOpacity;
     876             :                 else
     877           0 :                     maCurrState.mnOpacity = aValueUtf8.toDouble();
     878           0 :                 break;
     879             :             case XML_FILL_OPACITY:
     880           0 :                 if( aValueUtf8 == "inherit" )
     881           0 :                     maCurrState.mnFillOpacity = maParentStates.back().mnFillOpacity;
     882             :                 else {
     883           0 :                     maCurrState.mnFillOpacity = aValueUtf8.toDouble();
     884           0 :                     if( maCurrState.mnFillOpacity > 1 )
     885           0 :                         maCurrState.mnFillOpacity = 1;
     886             :                 }
     887           0 :                 break;
     888             :             case XML_STROKE_WIDTH:
     889             :             {
     890           0 :                 if( aValueUtf8 == "inherit" )
     891           0 :                     maCurrState.mnStrokeWidth = maParentStates.back().mnStrokeWidth;
     892             :                 else
     893           0 :                     maCurrState.mnStrokeWidth = convLength(sValue,maCurrState,'r');
     894           0 :                 break;
     895             :             }
     896             :             case XML_STROKE_LINECAP:
     897             :             {
     898           0 :                 if( aValueUtf8 == "butt" )
     899           0 :                     maCurrState.meLineCap = BUTT;
     900           0 :                 else if( aValueUtf8 == "round" )
     901           0 :                     maCurrState.meLineCap = ROUND;
     902           0 :                 else if( aValueUtf8 == "square" )
     903           0 :                     maCurrState.meLineCap = RECT;
     904           0 :                 else if( aValueUtf8 == "inherit" )
     905           0 :                     maCurrState.meLineCap = maParentStates.back().meLineCap;
     906           0 :                 break;
     907             :             }
     908             :             case XML_STROKE_LINEJOIN:
     909             :             {
     910           0 :                 if( aValueUtf8 == "miter" )
     911           0 :                     maCurrState.meLineJoin = basegfx::B2DLINEJOIN_MITER;
     912           0 :                 else if( aValueUtf8 == "round" )
     913           0 :                     maCurrState.meLineJoin = basegfx::B2DLINEJOIN_ROUND;
     914           0 :                 else if( aValueUtf8 == "bevel" )
     915           0 :                     maCurrState.meLineJoin = basegfx::B2DLINEJOIN_BEVEL;
     916           0 :                 else if( aValueUtf8 == "inherit" )
     917           0 :                     maCurrState.meLineJoin = maParentStates.back().meLineJoin;
     918           0 :                 break;
     919             :             }
     920             :             case XML_STROKE_MITERLIMIT:
     921             :             {
     922           0 :                 if( aValueUtf8 == "inherit" )
     923           0 :                     maCurrState.mnMiterLimit = maParentStates.back().mnMiterLimit;
     924             :                 else
     925           0 :                     maCurrState.mnMiterLimit = aValueUtf8.toDouble();
     926           0 :                 break;
     927             :             }
     928             :             case XML_STROKE_DASHOFFSET:
     929             :             {
     930           0 :                 if( aValueUtf8 == "inherit" )
     931           0 :                     maCurrState.mnDashOffset = maParentStates.back().mnDashOffset;
     932             :                 else
     933           0 :                     maCurrState.mnDashOffset = convLength(sValue,maCurrState,'r');
     934           0 :                 break;
     935             :             }
     936             :             case XML_STROKE_DASHARRAY:
     937             :             {
     938           0 :                 if( aValueUtf8 == "none" )
     939             :                 {
     940           0 :                     maCurrState.maDashArray.clear();
     941           0 :                     maCurrState.meStrokeType = SOLID;
     942             :                 }
     943           0 :                 else if( aValueUtf8 == "inherit" )
     944           0 :                     maCurrState.maDashArray = maParentStates.back().maDashArray;
     945             :                 else
     946             :                 {
     947             :                     parseDashArray(aValueUtf8.getStr(),
     948           0 :                                    maCurrState.maDashArray);
     949           0 :                     maCurrState.meStrokeType = DASH;
     950             :                 }
     951           0 :                 break;
     952             :             }
     953             :             case XML_STROKE_OPACITY:
     954           0 :                 if( aValueUtf8 == "inherit" )
     955           0 :                     maCurrState.mnStrokeOpacity = maParentStates.back().mnStrokeOpacity;
     956             :                 else
     957           0 :                     maCurrState.mnStrokeOpacity = aValueUtf8.toDouble();
     958           0 :                 break;
     959             :             case XML_FILL:
     960             :             {
     961           0 :                 const State& rParent( maParentStates.back() );
     962             :                 parsePaint( sValue,
     963             :                             aValueUtf8.getStr(),
     964             :                             maCurrState.meFillType,
     965             :                             maCurrState.maFillColor,
     966             :                             maCurrState.maFillGradient,
     967             :                             rParent.meFillType,
     968             :                             rParent.maFillColor,
     969           0 :                             rParent.maFillGradient );
     970           0 :                 break;
     971             :             }
     972             :             case XML_STROKE:
     973             :             {
     974           0 :                 const State& rParent( maParentStates.back() );
     975             :                 parsePaint( sValue,
     976             :                             aValueUtf8.getStr(),
     977             :                             maCurrState.meStrokeType,
     978             :                             maCurrState.maStrokeColor,
     979             :                             maCurrState.maStrokeGradient,
     980             :                             rParent.meStrokeType,
     981             :                             rParent.maStrokeColor,
     982           0 :                             rParent.maStrokeGradient );
     983           0 :                 break;
     984             :             }
     985             :             case XML_COLOR:
     986             :             {
     987           0 :                 if( aValueUtf8 == "inherit" )
     988           0 :                     maCurrState.maCurrentColor = maParentStates.back().maCurrentColor;
     989             :                 else
     990           0 :                     parseColor(aValueUtf8.getStr(), maCurrState.maCurrentColor);
     991           0 :                 break;
     992             :             }
     993             :             case XML_TRANSFORM:
     994             :             {
     995           0 :                 basegfx::B2DHomMatrix aTransform;
     996           0 :                 parseTransform(aValueUtf8.getStr(),aTransform);
     997           0 :                 maCurrState.maTransform = maCurrState.maTransform*aTransform;
     998           0 :                 break;
     999             :             }
    1000             :             case XML_FONT_FAMILY:
    1001           0 :                 maCurrState.maFontFamily=sValue;
    1002           0 :                 break;
    1003             :             case XML_FONT_SIZE:
    1004           0 :                 maCurrState.mnFontSize=convLength(sValue,maCurrState,'v');
    1005           0 :                 break;
    1006             :             case XML_FONT_STYLE:
    1007           0 :                 parseFontStyle(maCurrState,sValue,aValueUtf8.getStr());
    1008           0 :                 break;
    1009             :             case XML_FONT_WEIGHT:
    1010           0 :                 maCurrState.mnFontWeight=sValue.toDouble();
    1011           0 :                 break;
    1012             :             case XML_FONT_VARIANT:
    1013           0 :                 parseFontVariant(maCurrState,sValue,aValueUtf8.getStr());
    1014           0 :                 break;
    1015             :             case XML_TEXT_ANCHOR:
    1016           0 :                 parseTextAlign(maCurrState,aValueUtf8.getStr());
    1017           0 :                 break;
    1018             :             case XML_STOP_COLOR:
    1019           0 :                 if( maGradientVector.empty() ||
    1020           0 :                     maGradientVector.back().maStops.empty() )
    1021           0 :                     break;
    1022             :                 parseColor( aValueUtf8.getStr(),
    1023             :                             maGradientStopVector[
    1024           0 :                                 maGradientVector.back().maStops.back()].maStopColor );
    1025           0 :                 break;
    1026             :             case XML_STOP_OPACITY:
    1027           0 :                 if( maGradientVector.empty() ||
    1028           0 :                     maGradientVector.back().maStops.empty() )
    1029           0 :                     break;
    1030             :                 parseOpacity( aValueUtf8.getStr(),
    1031             :                               maGradientStopVector[
    1032           0 :                                   maGradientVector.back().maStops.back()].maStopColor );
    1033           0 :                 break;
    1034             :             default:
    1035             :                 SAL_INFO("svg", "unhandled token " << getTokenName(nTokenId));
    1036           0 :                 break;
    1037           0 :         }
    1038           0 :     }
    1039             : 
    1040           0 :     void parseStyle( const OUString& sValue )
    1041             :     {
    1042             :         // split individual style attributes
    1043           0 :         sal_Int32 nIndex=0, nDummyIndex=0;
    1044           0 :         OUString aCurrToken;
    1045           0 :         do
    1046             :         {
    1047           0 :             aCurrToken=sValue.getToken(0,';',nIndex);
    1048             : 
    1049           0 :             if( !aCurrToken.isEmpty() )
    1050             :             {
    1051             :                 // split attrib & value
    1052           0 :                 nDummyIndex=0;
    1053             :                 OUString aCurrAttrib(
    1054           0 :                     aCurrToken.getToken(0,':',nDummyIndex).trim());
    1055             :                 OSL_ASSERT(nDummyIndex!=-1);
    1056           0 :                 nDummyIndex=0;
    1057             :                 OUString aCurrValue(
    1058           0 :                     aCurrToken.getToken(1,':',nDummyIndex).trim());
    1059             :                 OSL_ASSERT(nDummyIndex==-1);
    1060             : 
    1061             :                 // recurse into normal attribute parsing
    1062             :                 parseAttribute( getTokenId(aCurrAttrib),
    1063           0 :                                 aCurrValue );
    1064             :             }
    1065             :         }
    1066           0 :         while( nIndex != -1 );
    1067           0 :     }
    1068             : 
    1069           0 :     void parseFontStyle( State&               io_rInitialState,
    1070             :                          const OUString& rValue,
    1071             :                          const char*          sValue )
    1072             :     {
    1073           0 :         if( strcmp(sValue,"inherit") != 0 )
    1074           0 :             io_rInitialState.maFontStyle = rValue;
    1075           0 :     }
    1076             : 
    1077           0 :     void parseFontVariant( State&               io_rInitialState,
    1078             :                            const OUString& rValue,
    1079             :                            const char*          sValue )
    1080             :     {
    1081           0 :         if( strcmp(sValue,"inherit") != 0 )
    1082           0 :             io_rInitialState.maFontVariant = rValue;
    1083           0 :     }
    1084             : 
    1085           0 :     void parseTextAlign( State&      io_rInitialState,
    1086             :                          const char* sValue )
    1087             :     {
    1088           0 :         if( strcmp(sValue,"start") == 0 )
    1089           0 :             io_rInitialState.meTextAnchor = BEFORE;
    1090           0 :         else if( strcmp(sValue,"middle") == 0 )
    1091           0 :             io_rInitialState.meTextAnchor = CENTER;
    1092           0 :         else if( strcmp(sValue,"end") == 0 )
    1093           0 :             io_rInitialState.meTextAnchor = AFTER;
    1094             :         // keep current val for sValue == "inherit"
    1095           0 :     }
    1096             : 
    1097           0 :     void parsePaint( const OUString& rValue,
    1098             :                      const char*      sValue,
    1099             :                      PaintType&       rType,
    1100             :                      ARGBColor&       rColor,
    1101             :                      Gradient&        rGradient,
    1102             :                      const PaintType& rInheritType,
    1103             :                      const ARGBColor& rInheritColor,
    1104             :                      const Gradient&  rInheritGradient )
    1105             :     {
    1106           0 :         std::pair<const char*,const char*> aPaintUri((const char*)NULL,(const char*)NULL);
    1107             :         std::pair<ARGBColor,bool>          aColor(maCurrState.maCurrentColor,
    1108           0 :                                                   false);
    1109           0 :         if( strcmp(sValue,"none") == 0 )
    1110           0 :             rType = NONE;
    1111           0 :         else if( strcmp(sValue,"currentColor") == 0 )
    1112             :         {
    1113           0 :             rType = SOLID;
    1114           0 :             rColor = maCurrState.maCurrentColor;
    1115             :         }
    1116           0 :         else if( strcmp(sValue,"inherit") == 0)
    1117             :         {
    1118           0 :             rType = rInheritType;
    1119           0 :             rColor = rInheritColor;
    1120           0 :             rGradient = rInheritGradient;
    1121             :         }
    1122           0 :         else if( parsePaintUri(aPaintUri,aColor,sValue) )
    1123             :         {
    1124           0 :             if( aPaintUri.first != aPaintUri.second )
    1125             :             {
    1126             :                 // assuming gradient. assumption does not hold generally
    1127           0 :                 if( strstr(sValue,")") && rValue.getLength() > 5 )
    1128             :                 {
    1129           0 :                     ElementRefMapType::iterator aRes;
    1130           0 :                     if( (aRes=maGradientIdMap.find(
    1131           0 :                              rValue.copy(aPaintUri.first-sValue,
    1132           0 :                                          aPaintUri.second-aPaintUri.first))) != maGradientIdMap.end() )
    1133             :                     {
    1134           0 :                         rGradient = maGradientVector[aRes->second];
    1135           0 :                         rType = GRADIENT;
    1136             :                     }
    1137             :                 }
    1138             :             }
    1139           0 :             else if( aColor.second )
    1140             :             {
    1141           0 :                 rType = SOLID;
    1142           0 :                 rColor = aColor.first;
    1143             :             }
    1144             :             else
    1145             :             {
    1146           0 :                 rType = NONE;
    1147             :             }
    1148             :         }
    1149             :         else
    1150             :         {
    1151           0 :             rType = SOLID;
    1152           0 :             parseColor(sValue,rColor);
    1153             :         }
    1154           0 :     }
    1155             : 
    1156             :     sal_Int32                                  mnCurrStateId;
    1157             :     State                                      maCurrState;
    1158             :     std::vector<State>                         maParentStates;
    1159             :     StatePool&                                 mrStates;
    1160             :     StateMap&                                  mrStateMap;
    1161             :     uno::Reference<xml::sax::XDocumentHandler> mxDocumentHandler;
    1162             :     std::vector< Gradient >                    maGradientVector;
    1163             :     std::vector< GradientStop >                maGradientStopVector;
    1164             :     ElementRefMapType                          maGradientIdMap;
    1165             :     ElementRefMapType                          maStopIdMap;
    1166             : };
    1167             : 
    1168             : /// Annotate svg styles with unique references to state pool
    1169           0 : static void annotateStyles( StatePool&                                        rStatePool,
    1170             :                             StateMap&                                         rStateMap,
    1171             :                             const State&                                       rInitialState,
    1172             :                             const uno::Reference<xml::dom::XElement>          xElem,
    1173             :                             const uno::Reference<xml::sax::XDocumentHandler>& xDocHdl )
    1174             : {
    1175           0 :     AnnotatingVisitor aVisitor(rStatePool,rStateMap,rInitialState,xDocHdl);
    1176           0 :     visitElements(aVisitor, xElem);
    1177           0 : }
    1178             : 
    1179           0 : struct ShapeWritingVisitor
    1180             : {
    1181           0 :     ShapeWritingVisitor(StatePool&                                        /*rStatePool*/,
    1182             :                         StateMap&                                         rStateMap,
    1183             :                         const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler) :
    1184             :         mrStateMap(rStateMap),
    1185             :         mxDocumentHandler(xDocumentHandler),
    1186           0 :         mnShapeNum(0)
    1187           0 :     {}
    1188             : 
    1189           0 :     void operator()( const uno::Reference<xml::dom::XElement>& )
    1190             :     {
    1191           0 :     }
    1192             : 
    1193           0 :     void operator()( const uno::Reference<xml::dom::XElement>&      xElem,
    1194             :                      const uno::Reference<xml::dom::XNamedNodeMap>& xAttributes )
    1195             :     {
    1196           0 :         rtl::Reference<SvXMLAttributeList> xAttrs( new SvXMLAttributeList() );
    1197           0 :         uno::Reference<xml::sax::XAttributeList> xUnoAttrs( xAttrs.get() );
    1198             : 
    1199           0 :         sal_Int32 nDummyIndex(0);
    1200             :         OUString sStyleId(
    1201           0 :             xElem->getAttribute("internal-style-ref").getToken(
    1202           0 :                     0,'$',nDummyIndex));
    1203             :         StateMap::iterator pOrigState=mrStateMap.find(
    1204           0 :             sStyleId.toInt32());
    1205             : 
    1206           0 :         if( pOrigState == mrStateMap.end() )
    1207           0 :             return; // non-exportable element, e.g. linearGradient
    1208             : 
    1209           0 :         maCurrState = pOrigState->second;
    1210             : 
    1211           0 :         const sal_Int32 nTokenId(getTokenId(xElem->getNodeName()));
    1212           0 :         switch(nTokenId)
    1213             :         {
    1214             :             case XML_LINE:
    1215             :             {
    1216             :                 // collect attributes
    1217           0 :                 const sal_Int32 nNumAttrs( xAttributes->getLength() );
    1218           0 :                 OUString sAttributeValue;
    1219           0 :                 double x1=0.0,y1=0.0,x2=0.0,y2=0.0;
    1220           0 :                 for( sal_Int32 i=0; i<nNumAttrs; ++i )
    1221             :                 {
    1222           0 :                     sAttributeValue = xAttributes->item(i)->getNodeValue();
    1223             :                     const sal_Int32 nAttribId(
    1224           0 :                         getTokenId(xAttributes->item(i)->getNodeName()));
    1225           0 :                     switch(nAttribId)
    1226             :                     {
    1227             :                         case XML_X1:
    1228           0 :                             x1= convLength(sAttributeValue,maCurrState,'h');
    1229           0 :                             break;
    1230             :                         case XML_X2:
    1231           0 :                             x2 = convLength(sAttributeValue,maCurrState,'h');
    1232           0 :                             break;
    1233             :                         case XML_Y1:
    1234           0 :                             y1 = convLength(sAttributeValue,maCurrState,'v');
    1235           0 :                             break;
    1236             :                         case XML_Y2:
    1237           0 :                             y2 = convLength(sAttributeValue,maCurrState,'v');
    1238           0 :                             break;
    1239             :                         default:
    1240             :                             // skip
    1241           0 :                             break;
    1242             :                     }
    1243             :                 }
    1244             : 
    1245           0 :                 if ( x1 != x2 || y1 != y2 ) {
    1246           0 :                     OUString sLinePath = "M"+OUString::valueOf(x1)+","
    1247           0 :                         +OUString::valueOf(y1)+"L"+OUString::valueOf(x2)+","
    1248           0 :                         +OUString::valueOf(y2);
    1249           0 :                     basegfx::B2DPolyPolygon aPoly;
    1250           0 :                     basegfx::tools::importFromSvgD(aPoly, sLinePath);
    1251             : 
    1252             :                     writePathShape(xAttrs,
    1253             :                                    xUnoAttrs,
    1254             :                                    xElem,
    1255             :                                    sStyleId,
    1256           0 :                                    basegfx::B2DPolyPolygon(aPoly));
    1257             :                 }
    1258             : 
    1259           0 :                 break;
    1260             :             }
    1261             :             case XML_POLYGON:
    1262             :             case XML_POLYLINE:
    1263             :             {
    1264           0 :                 OUString sPoints = xElem->hasAttribute("points") ? xElem->getAttribute("points") : "";
    1265           0 :                 basegfx::B2DPolygon aPoly;
    1266           0 :                 basegfx::tools::importFromSvgPoints(aPoly, sPoints);
    1267           0 :                 if( nTokenId == XML_POLYGON || maCurrState.meFillType != NONE )
    1268           0 :                     aPoly.setClosed(true);
    1269             : 
    1270             :                 writePathShape(xAttrs,
    1271             :                                xUnoAttrs,
    1272             :                                xElem,
    1273             :                                sStyleId,
    1274           0 :                                basegfx::B2DPolyPolygon(aPoly));
    1275           0 :                 break;
    1276             :             }
    1277             :             case XML_RECT:
    1278             :             {
    1279             :                 // collect attributes
    1280           0 :                 const sal_Int32 nNumAttrs( xAttributes->getLength() );
    1281           0 :                 OUString sAttributeValue;
    1282           0 :                 bool bRxSeen=false, bRySeen=false;
    1283           0 :                 double x=0.0,y=0.0,width=0.0,height=0.0,rx=0.0,ry=0.0;
    1284           0 :                 for( sal_Int32 i=0; i<nNumAttrs; ++i )
    1285             :                 {
    1286           0 :                     sAttributeValue = xAttributes->item(i)->getNodeValue();
    1287             :                     const sal_Int32 nAttribId(
    1288           0 :                                               getTokenId(xAttributes->item(i)->getNodeName()));
    1289           0 :                     switch(nAttribId)
    1290             :                     {
    1291             :                     case XML_X:
    1292           0 :                         x = convLength(sAttributeValue,maCurrState,'h');
    1293           0 :                         break;
    1294             :                     case XML_Y:
    1295           0 :                         y = convLength(sAttributeValue,maCurrState,'v');
    1296           0 :                         break;
    1297             :                     case XML_WIDTH:
    1298           0 :                         width = convLength(sAttributeValue,maCurrState,'h');
    1299           0 :                         break;
    1300             :                     case XML_HEIGHT:
    1301           0 :                         height = convLength(sAttributeValue,maCurrState,'v');
    1302           0 :                         break;
    1303             :                     case XML_RX:
    1304           0 :                         rx = convLength(sAttributeValue,maCurrState,'h');
    1305           0 :                         bRxSeen=true;
    1306           0 :                         break;
    1307             :                     case XML_RY:
    1308           0 :                         ry = convLength(sAttributeValue,maCurrState,'v');
    1309           0 :                         bRySeen=true;
    1310           0 :                         break;
    1311             :                     default:
    1312             :                         // skip
    1313           0 :                         break;
    1314             :                     }
    1315             :                 }
    1316             : 
    1317           0 :                 if ( (width > 0) && (height > 0) ) {
    1318           0 :                     if( bRxSeen && !bRySeen )
    1319           0 :                         ry = rx;
    1320           0 :                     else if( bRySeen && !bRxSeen )
    1321           0 :                         rx = ry;
    1322             : 
    1323           0 :                     basegfx::B2DPolygon aPoly;
    1324           0 :                     aPoly = basegfx::tools::createPolygonFromRect(
    1325             :                                                                   basegfx::B2DRange(x,y,x+width,y+height),
    1326           0 :                                                                   rx/(0.5*width), ry/(0.5*height) );
    1327             : 
    1328             :                     writePathShape(xAttrs,
    1329             :                                    xUnoAttrs,
    1330             :                                    xElem,
    1331             :                                    sStyleId,
    1332           0 :                                    basegfx::B2DPolyPolygon(aPoly));
    1333             :                 }
    1334           0 :                 break;
    1335             :             }
    1336             :             case XML_PATH:
    1337             :             {
    1338           0 :                 OUString sPath = xElem->hasAttribute("d") ? xElem->getAttribute("d") : "";
    1339           0 :                 basegfx::B2DPolyPolygon aPoly;
    1340           0 :                 basegfx::tools::importFromSvgD(aPoly, sPath);
    1341             : 
    1342             :                 writePathShape(xAttrs,
    1343             :                                xUnoAttrs,
    1344             :                                xElem,
    1345             :                                sStyleId,
    1346           0 :                                aPoly);
    1347           0 :                 break;
    1348             :             }
    1349             :             case XML_CIRCLE:
    1350             :             {
    1351             :                 // collect attributes
    1352           0 :                 const sal_Int32 nNumAttrs( xAttributes->getLength() );
    1353           0 :                 OUString sAttributeValue;
    1354           0 :                 double cx=0.0,cy=0.0,r=0.0;
    1355           0 :                 for( sal_Int32 i=0; i<nNumAttrs; ++i )
    1356             :                 {
    1357           0 :                     sAttributeValue = xAttributes->item(i)->getNodeValue();
    1358             :                     const sal_Int32 nAttribId(
    1359           0 :                         getTokenId(xAttributes->item(i)->getNodeName()));
    1360           0 :                     switch(nAttribId)
    1361             :                     {
    1362             :                         case XML_CX:
    1363           0 :                             cx = convLength(sAttributeValue,maCurrState,'h');
    1364           0 :                             break;
    1365             :                         case XML_CY:
    1366           0 :                             cy = convLength(sAttributeValue,maCurrState,'v');
    1367           0 :                             break;
    1368             :                         case XML_R:
    1369           0 :                             r = convLength(sAttributeValue,maCurrState,'r');
    1370             :                         default:
    1371             :                             // skip
    1372           0 :                             break;
    1373             :                     }
    1374             :                 }
    1375             : 
    1376           0 :                 if ( r > 0 )
    1377             :                     writeEllipseShape(xAttrs,
    1378             :                                       xUnoAttrs,
    1379             :                                       xElem,
    1380             :                                       sStyleId,
    1381           0 :                                       basegfx::B2DEllipse(basegfx::B2DPoint(cx, cy), basegfx::B2DTuple(r,r)));
    1382           0 :                 break;
    1383             :             }
    1384             :             case XML_ELLIPSE:
    1385             :             {
    1386             :                 // collect attributes
    1387           0 :                 const sal_Int32 nNumAttrs( xAttributes->getLength() );
    1388           0 :                 OUString sAttributeValue;
    1389           0 :                 double cx=0.0,cy=0.0,rx=0.0, ry=0.0;
    1390           0 :                 for( sal_Int32 i=0; i<nNumAttrs; ++i )
    1391             :                 {
    1392           0 :                     sAttributeValue = xAttributes->item(i)->getNodeValue();
    1393             :                     const sal_Int32 nAttribId(
    1394           0 :                         getTokenId(xAttributes->item(i)->getNodeName()));
    1395           0 :                     switch(nAttribId)
    1396             :                     {
    1397             :                         case XML_CX:
    1398           0 :                             cx = convLength(sAttributeValue,maCurrState,'h');
    1399           0 :                             break;
    1400             :                         case XML_CY:
    1401           0 :                             cy = convLength(sAttributeValue,maCurrState,'v');
    1402           0 :                             break;
    1403             :                         case XML_RX:
    1404           0 :                             rx = convLength(sAttributeValue,maCurrState,'h');
    1405           0 :                             break;
    1406             :                         case XML_RY:
    1407           0 :                             ry = convLength(sAttributeValue,maCurrState,'v');
    1408             :                         default:
    1409             :                             // skip
    1410           0 :                             break;
    1411             :                     }
    1412             :                 }
    1413             : 
    1414           0 :                 if ( rx > 0 && ry > 0 )
    1415             :                     writeEllipseShape(xAttrs,
    1416             :                                       xUnoAttrs,
    1417             :                                       xElem,
    1418             :                                       sStyleId,
    1419           0 :                                       basegfx::B2DEllipse(basegfx::B2DPoint(cx, cy), basegfx::B2DTuple(rx,ry)));
    1420           0 :                 break;
    1421             :             }
    1422             :             case XML_IMAGE:
    1423             :             {
    1424             :                 // collect attributes
    1425           0 :                 const sal_Int32 nNumAttrs( xAttributes->getLength() );
    1426           0 :                 OUString sAttributeValue;
    1427           0 :                 double x=0.0,y=0.0,width=0.0,height=0.0;
    1428           0 :                 for( sal_Int32 i=0; i<nNumAttrs; ++i )
    1429             :                 {
    1430           0 :                     sAttributeValue = xAttributes->item(i)->getNodeValue();
    1431             :                     const sal_Int32 nAttribId(
    1432           0 :                         getTokenId(xAttributes->item(i)->getNodeName()));
    1433           0 :                     switch(nAttribId)
    1434             :                     {
    1435             :                         case XML_X:
    1436           0 :                             x = convLength(sAttributeValue,maCurrState,'h');
    1437           0 :                             break;
    1438             :                         case XML_Y:
    1439           0 :                             y = convLength(sAttributeValue,maCurrState,'v');
    1440           0 :                             break;
    1441             :                         case XML_WIDTH:
    1442           0 :                             width = convLength(sAttributeValue,maCurrState,'h');
    1443           0 :                             break;
    1444             :                         case XML_HEIGHT:
    1445           0 :                             height = convLength(sAttributeValue,maCurrState,'v');
    1446           0 :                             break;
    1447             :                         default:
    1448             :                             // skip
    1449           0 :                             break;
    1450             :                     }
    1451             :                 }
    1452             : 
    1453           0 :                 OUString sValue = xElem->hasAttribute("href") ? xElem->getAttribute("href") : "";
    1454           0 :                 OString aValueUtf8( sValue.getStr(), sValue.getLength(), RTL_TEXTENCODING_UTF8 );
    1455           0 :                 std::string sLinkValue;
    1456           0 :                 parseXlinkHref(aValueUtf8.getStr(), sLinkValue);
    1457             : 
    1458           0 :                 if (!sLinkValue.empty())
    1459           0 :                     writeBinaryData(xAttrs, xUnoAttrs, xElem, basegfx::B2DRange(x,y,x+width,y+height), sLinkValue);
    1460           0 :                 break;
    1461             :             }
    1462             :             case XML_TEXT:
    1463             :             {
    1464             :                 // collect text from all TEXT_NODE children into sText
    1465           0 :                 OUStringBuffer sText;
    1466             :                 visitChildren(boost::bind(
    1467             :                                   (OUStringBuffer& (OUStringBuffer::*)(const OUString& str))&OUStringBuffer::append,
    1468             :                                   boost::ref(sText),
    1469             :                                   boost::bind(&xml::dom::XNode::getNodeValue,
    1470           0 :                                               _1)),
    1471             :                               xElem,
    1472           0 :                               xml::dom::NodeType_TEXT_NODE);
    1473             : 
    1474             :                 // collect attributes
    1475           0 :                 const sal_Int32 nNumAttrs( xAttributes->getLength() );
    1476           0 :                 OUString sAttributeValue;
    1477           0 :                 double x=0.0,y=0.0;
    1478           0 :                 for( sal_Int32 i=0; i<nNumAttrs; ++i )
    1479             :                 {
    1480           0 :                     sAttributeValue = xAttributes->item(i)->getNodeValue();
    1481             :                     const sal_Int32 nAttribId(
    1482           0 :                         getTokenId(xAttributes->item(i)->getNodeName()));
    1483           0 :                     switch(nAttribId)
    1484             :                     {
    1485             :                         case XML_X:
    1486           0 :                             x = convLength(sAttributeValue,maCurrState,'h');
    1487           0 :                             break;
    1488             :                         case XML_Y:
    1489           0 :                             y = convLength(sAttributeValue,maCurrState,'v');
    1490           0 :                             break;
    1491             :                         default:
    1492             :                             // skip
    1493           0 :                             break;
    1494             :                     }
    1495             :                 }
    1496             : 
    1497             :                 // actually export text
    1498           0 :                 xAttrs->Clear();
    1499             : 
    1500             : 
    1501             :                 // extract basic transformations out of CTM
    1502           0 :                 basegfx::B2DTuple aScale, aTranslate;
    1503             :                 double fRotate, fShearX;
    1504           0 :                 if (maCurrState.maCTM.decompose(aScale, aTranslate, fRotate, fShearX))
    1505             :                 {
    1506             :                     // some heuristic attempts to have text output
    1507             :                     // baseline-relative
    1508           0 :                     y -= 2.0*maCurrState.mnFontSize/aScale.getX()/3.0;
    1509             :                     // apply transform
    1510           0 :                     x *= aScale.getX();
    1511           0 :                     y *= aScale.getY();
    1512           0 :                     x += aTranslate.getX();
    1513           0 :                     y += aTranslate.getY();
    1514             :                 }
    1515             :                 else {
    1516             :                     // some heuristic attempts to have text output
    1517             :                     // baseline-relative
    1518           0 :                     y -= 2.0*maCurrState.mnFontSize/3.0;
    1519             :                 }
    1520             : 
    1521           0 :                 xAttrs->AddAttribute( "svg:x", OUString::valueOf(pt2mm(x))+"mm");
    1522           0 :                 xAttrs->AddAttribute( "svg:y", OUString::valueOf(pt2mm(y))+"mm");
    1523           0 :                 xAttrs->AddAttribute( "draw:style-name", "svggraphicstyle"+sStyleId );
    1524             : 
    1525           0 :                 mxDocumentHandler->startElement("draw:frame", xUnoAttrs);
    1526             : 
    1527           0 :                 xAttrs->Clear();
    1528           0 :                 mxDocumentHandler->startElement("draw:text-box", xUnoAttrs);
    1529           0 :                 xAttrs->AddAttribute( "text:style-name", "svgparagraphstyle"+sStyleId);
    1530           0 :                 mxDocumentHandler->startElement("text:p", xUnoAttrs);
    1531             : 
    1532           0 :                 xAttrs->Clear();
    1533           0 :                 xAttrs->AddAttribute( "text:style-name", "svgtextstyle"+sStyleId);
    1534           0 :                 mxDocumentHandler->startElement("text:span", xUnoAttrs);
    1535             : 
    1536           0 :                 xAttrs->Clear();
    1537           0 :                 mxDocumentHandler->characters(sText.makeStringAndClear());
    1538           0 :                 mxDocumentHandler->endElement("text:span");
    1539           0 :                 mxDocumentHandler->endElement("text:p");
    1540           0 :                 mxDocumentHandler->endElement("draw:text-box");
    1541           0 :                 mxDocumentHandler->endElement("draw:frame");
    1542           0 :                 break;
    1543             :             }
    1544           0 :         }
    1545             :     }
    1546             : 
    1547           0 :     void push()
    1548           0 :     {}
    1549             : 
    1550           0 :     void pop()
    1551           0 :     {}
    1552             : 
    1553           0 :     void writeBinaryData( rtl::Reference<SvXMLAttributeList>&           xAttrs,
    1554             :                         const uno::Reference<xml::sax::XAttributeList>& xUnoAttrs,
    1555             :                         const uno::Reference<xml::dom::XElement>&       /* xElem */,
    1556             :                         const basegfx::B2DRange&                        rShapeBounds,
    1557             :                         const std::string&                              data)
    1558             :     {
    1559           0 :         xAttrs->Clear();
    1560           0 :         xAttrs->AddAttribute( "svg:x", OUString::valueOf(pt2mm(rShapeBounds.getMinX()))+"mm");
    1561           0 :         xAttrs->AddAttribute( "svg:y", OUString::valueOf(pt2mm(rShapeBounds.getMinY()))+"mm");
    1562           0 :         xAttrs->AddAttribute( "svg:width", OUString::valueOf(pt2mm(rShapeBounds.getWidth()))+"mm");
    1563           0 :         xAttrs->AddAttribute( "svg:height", OUString::valueOf(pt2mm(rShapeBounds.getHeight()))+"mm");
    1564             : 
    1565           0 :         mxDocumentHandler->startElement("draw:frame", xUnoAttrs);
    1566             : 
    1567           0 :         xAttrs->Clear();
    1568           0 :         mxDocumentHandler->startElement("draw:image", xUnoAttrs);
    1569             : 
    1570           0 :         mxDocumentHandler->startElement("office:binary-data", xUnoAttrs);
    1571             : 
    1572           0 :         mxDocumentHandler->characters(OUString::createFromAscii(data.c_str()));
    1573             : 
    1574           0 :         mxDocumentHandler->endElement("office:binary-data");
    1575             : 
    1576           0 :         mxDocumentHandler->endElement("draw:image");
    1577             : 
    1578           0 :         mxDocumentHandler->endElement("draw:frame");
    1579           0 :     }
    1580             : 
    1581             : 
    1582             :     void writeTransformAttribute(const basegfx::B2DHomMatrix rMatrix, rtl::Reference<SvXMLAttributeList>& xAttrs)
    1583             :     {
    1584             :         basegfx::B2DTuple rScale, rTranslate;
    1585             :         double rRotate, rShearX;
    1586             :         OUString sTransformValue;
    1587             :         if (!rMatrix.decompose(rScale, rTranslate, rRotate, rShearX))
    1588             :             return;
    1589             :         if (rScale.getX() != 1.0 || rScale.getY() != 1.0)
    1590             :             sTransformValue += "scale("+OUString::valueOf(rScale.getX())+" "
    1591             :                  +OUString::valueOf(rScale.getY())+") ";
    1592             :         if (rTranslate.getX() != 0.0f || rTranslate.getY() != 0.0f)
    1593             :             sTransformValue += "translate("+OUString::valueOf(rTranslate.getX()/100.0f)+"mm "
    1594             :                  +OUString::valueOf(rTranslate.getY()/100.0f)+"mm) ";
    1595             :         if (rRotate != 0.0f)
    1596             :             sTransformValue += "rotate("+OUString::valueOf(rRotate)+") ";
    1597             : 
    1598             :         if (rShearX != 0.0f)
    1599             :             sTransformValue += "skewX("+OUString::valueOf(rShearX)+") ";
    1600             :         if (sTransformValue.isEmpty())
    1601             :             return;
    1602             :         xAttrs->AddAttribute( "draw:transform", sTransformValue);
    1603             :     }
    1604             : 
    1605           0 :     void writeEllipseShape( rtl::Reference<SvXMLAttributeList>&          xAttrs,
    1606             :                          const uno::Reference<xml::sax::XAttributeList>& xUnoAttrs,
    1607             :                          const uno::Reference<xml::dom::XElement>&       xElem,
    1608             :                          const OUString&                            rStyleId,
    1609             :                          const basegfx::B2DEllipse&                      rEllipse)
    1610             :     {
    1611           0 :         State aState = maCurrState;
    1612             : 
    1613           0 :         xAttrs->Clear();
    1614             : 
    1615             :         basegfx::B2DPolygon aPoly = basegfx::tools::createPolygonFromEllipse(rEllipse.getB2DEllipseCenter(),
    1616           0 :             rEllipse.getB2DEllipseRadius().getX(), rEllipse.getB2DEllipseRadius().getY());
    1617           0 :         writePathShape(xAttrs, xUnoAttrs, xElem, rStyleId, basegfx::B2DPolyPolygon(aPoly));
    1618             : 
    1619           0 :     }
    1620             : 
    1621           0 :     void writePathShape( rtl::Reference<SvXMLAttributeList>&             xAttrs,
    1622             :                          const uno::Reference<xml::sax::XAttributeList>& xUnoAttrs,
    1623             :                          const uno::Reference<xml::dom::XElement>&       xElem,
    1624             :                          const OUString&                            rStyleId,
    1625             :                          const basegfx::B2DPolyPolygon&                  rPoly )
    1626             :     {
    1627             :         // we might need to split up polypolygon into multiple path
    1628             :         // shapes (e.g. when emulating line stroking)
    1629           0 :         std::vector<basegfx::B2DPolyPolygon> aPolys(1,rPoly);
    1630           0 :         State aState = maCurrState;
    1631           0 :         OUString aStyleId(rStyleId);
    1632             : 
    1633           0 :         xAttrs->Clear();
    1634             : 
    1635             :         OSL_TRACE("writePath - the CTM is: %f %f %f %f %f %f",
    1636             :                   maCurrState.maCTM.get(0,0),
    1637             :                   maCurrState.maCTM.get(0,1),
    1638             :                   maCurrState.maCTM.get(0,2),
    1639             :                   maCurrState.maCTM.get(1,0),
    1640             :                   maCurrState.maCTM.get(1,1),
    1641             :                   maCurrState.maCTM.get(1,2));
    1642             : 
    1643             :         // TODO(F2): separate out shear, rotate etc.
    1644             :         // apply transformation to polygon, to keep draw
    1645             :         // import in 100th mm
    1646             :         std::for_each(aPolys.begin(),aPolys.end(),
    1647             :                       boost::bind(&basegfx::B2DPolyPolygon::transform,
    1648           0 :                                   _1,boost::cref(aState.maCTM)));
    1649             : 
    1650           0 :         for( sal_uInt32 i=0; i<aPolys.size(); ++i )
    1651             :         {
    1652             :             const basegfx::B2DRange aBounds(
    1653           0 :                 aPolys[i].areControlPointsUsed() ?
    1654             :                 basegfx::tools::getRange(
    1655           0 :                     basegfx::tools::adaptiveSubdivideByAngle(aPolys[i])) :
    1656           0 :                 basegfx::tools::getRange(aPolys[i]));
    1657             :             fillShapeProperties(xAttrs,
    1658             :                                 xElem,
    1659             :                                 aBounds,
    1660           0 :                                 "svggraphicstyle"+aStyleId);
    1661             : 
    1662             :             // force path coordinates to 100th millimeter, after
    1663             :             // putting polygon data at origin (ODF viewbox
    1664             :             // calculations largely untested codepaths, as OOo always
    1665             :             // writes "0 0 w h" viewboxes)
    1666           0 :             basegfx::B2DHomMatrix aNormalize;
    1667           0 :             aNormalize.translate(-aBounds.getMinX(),-aBounds.getMinY());
    1668           0 :             aNormalize.scale(2540.0/72.0,2540.0/72.0);
    1669           0 :             aPolys[i].transform(aNormalize);
    1670             : 
    1671             :             xAttrs->AddAttribute( "svg:d", basegfx::tools::exportToSvgD(
    1672           0 :                 aPolys[i],
    1673             :                 false,   // no relative coords. causes rounding errors
    1674           0 :                 false )); // no quad bezier detection. crashes older versions.
    1675           0 :             mxDocumentHandler->startElement("draw:path", xUnoAttrs);
    1676           0 :             mxDocumentHandler->endElement("draw:path");
    1677           0 :         }
    1678           0 :     }
    1679             : 
    1680           0 :     void fillShapeProperties( rtl::Reference<SvXMLAttributeList>&       xAttrs,
    1681             :                               const uno::Reference<xml::dom::XElement>& /* xElem */,
    1682             :                               const basegfx::B2DRange&                  rShapeBounds,
    1683             :                               const OUString&                      rStyleName )
    1684             :     {
    1685           0 :         xAttrs->AddAttribute( "draw:z-index", OUString::valueOf( mnShapeNum++ ));
    1686           0 :         xAttrs->AddAttribute( "draw:style-name", rStyleName);
    1687           0 :         xAttrs->AddAttribute( "svg:width", OUString::valueOf(pt2mm(rShapeBounds.getWidth()))+"mm");
    1688           0 :         xAttrs->AddAttribute( "svg:height", OUString::valueOf(pt2mm(rShapeBounds.getHeight()))+"mm");
    1689             : 
    1690             :         // OOo expects the viewbox to be in 100th of mm
    1691             :         xAttrs->AddAttribute( "svg:viewBox",
    1692             :             "0 0 "
    1693           0 :             + OUString::valueOf(
    1694           0 :                 basegfx::fround(pt100thmm(rShapeBounds.getWidth())) )
    1695           0 :             + " "
    1696           0 :             + OUString::valueOf(
    1697           0 :                 basegfx::fround(pt100thmm(rShapeBounds.getHeight())) ));
    1698             : 
    1699             :         // TODO(F1): decompose transformation in calling code, and use
    1700             :         // transform attribute here
    1701             :         // writeTranslate(maCurrState.maCTM, xAttrs);
    1702           0 :         xAttrs->AddAttribute( "svg:x", OUString::valueOf(pt2mm(rShapeBounds.getMinX()))+"mm");
    1703           0 :         xAttrs->AddAttribute( "svg:y", OUString::valueOf(pt2mm(rShapeBounds.getMinY()))+"mm");
    1704           0 :     }
    1705             : 
    1706             :     State                                      maCurrState;
    1707             :     StateMap&                                  mrStateMap;
    1708             :     uno::Reference<xml::sax::XDocumentHandler> mxDocumentHandler;
    1709             :     sal_Int32                                  mnShapeNum;
    1710             : };
    1711             : 
    1712             : /// Write out shapes from DOM tree
    1713           0 : static void writeShapes( StatePool&                                        rStatePool,
    1714             :                          StateMap&                                         rStateMap,
    1715             :                          const uno::Reference<xml::dom::XElement>          xElem,
    1716             :                          const uno::Reference<xml::sax::XDocumentHandler>& xDocHdl )
    1717             : {
    1718           0 :     ShapeWritingVisitor aVisitor(rStatePool,rStateMap,xDocHdl);
    1719           0 :     visitElements(aVisitor, xElem);
    1720           0 : }
    1721             : 
    1722             : } // namespace
    1723             : 
    1724           0 : struct OfficeStylesWritingVisitor
    1725             : {
    1726           0 :     OfficeStylesWritingVisitor( StateMap&                                         rStateMap,
    1727             :                                 const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler) :
    1728             :         mrStateMap(rStateMap),
    1729           0 :         mxDocumentHandler(xDocumentHandler)
    1730           0 :     {}
    1731           0 :     void operator()( const uno::Reference<xml::dom::XElement>& /*xElem*/ )
    1732             :     {
    1733           0 :     }
    1734           0 :     void operator()( const uno::Reference<xml::dom::XElement>&      xElem,
    1735             :                      const uno::Reference<xml::dom::XNamedNodeMap>& /*xAttributes*/ )
    1736             :     {
    1737           0 :         rtl::Reference<SvXMLAttributeList> xAttrs( new SvXMLAttributeList() );
    1738           0 :         uno::Reference<xml::sax::XAttributeList> xUnoAttrs( xAttrs.get() );
    1739             : 
    1740           0 :         sal_Int32 nDummyIndex(0);
    1741             :         OUString sStyleId(
    1742           0 :             xElem->getAttribute("internal-style-ref").getToken(
    1743           0 :                     0,'$',nDummyIndex));
    1744             :         StateMap::iterator pOrigState=mrStateMap.find(
    1745           0 :             sStyleId.toInt32());
    1746             : 
    1747           0 :         if( pOrigState == mrStateMap.end() )
    1748           0 :             return; // non-exportable element, e.g. linearGradient
    1749             : 
    1750           0 :         maCurrState = pOrigState->second;
    1751             : 
    1752           0 :         if( maCurrState.meStrokeType == DASH )
    1753             :         {
    1754             :             sal_Int32 dots1, dots2;
    1755             :             double dots1_length, dots2_length, dash_distance;
    1756           0 :             SvgDashArray2Odf( &dots1, &dots1_length, &dots2, &dots2_length, &dash_distance );
    1757             : 
    1758           0 :             xAttrs->Clear();
    1759           0 :             xAttrs->AddAttribute( "draw:name", "dash"+sStyleId );
    1760           0 :             xAttrs->AddAttribute( "draw:display-name", "dash"+sStyleId );
    1761           0 :             xAttrs->AddAttribute( "draw:style", "rect" );
    1762           0 :             if ( dots1>0 ) {
    1763           0 :                 xAttrs->AddAttribute( "draw:dots1", OUString::valueOf(dots1) );
    1764           0 :                 xAttrs->AddAttribute( "draw:dots1-length", OUString::valueOf(pt2mm(convLength( OUString::valueOf(dots1_length), maCurrState, 'h' )))+"mm" );
    1765             :             }
    1766           0 :             xAttrs->AddAttribute( "draw:distance", OUString::valueOf(pt2mm(convLength( OUString::valueOf(dash_distance), maCurrState, 'h' )))+"mm" );
    1767           0 :             if ( dots2>0 ) {
    1768           0 :                 xAttrs->AddAttribute( "draw:dots2", OUString::valueOf(dots2) );
    1769           0 :                 xAttrs->AddAttribute( "draw:dots2-length", OUString::valueOf(pt2mm(convLength( OUString::valueOf(dots2_length), maCurrState, 'h' )))+"mm" );
    1770             :             }
    1771             : 
    1772           0 :             mxDocumentHandler->startElement( "draw:stroke-dash", xUnoAttrs);
    1773           0 :             mxDocumentHandler->endElement( "draw:stroke-dash" );
    1774           0 :         }
    1775             :     }
    1776             : 
    1777           0 :     void SvgDashArray2Odf( sal_Int32 *dots1, double *dots1_length, sal_Int32 *dots2, double *dots2_length, double *dash_distance )
    1778             :     {
    1779           0 :         *dots1 = 0;
    1780           0 :         *dots1_length = 0;
    1781           0 :         *dots2 = 0;
    1782           0 :         *dots2_length = 0;
    1783           0 :         *dash_distance = 0;
    1784             : 
    1785           0 :         if( maCurrState.maDashArray.size() == 0 ) {
    1786           0 :             return;
    1787             :         }
    1788             : 
    1789           0 :         double effective_dasharray_size = maCurrState.maDashArray.size();
    1790           0 :         if( maCurrState.maDashArray.size() % 2 == 1 )
    1791           0 :             effective_dasharray_size = maCurrState.maDashArray.size()*2;
    1792             : 
    1793           0 :         *dash_distance = maCurrState.maDashArray[1%maCurrState.maDashArray.size()];
    1794           0 :         sal_Int32 dist_count = 1;
    1795           0 :         for( int i=3; i<effective_dasharray_size; i+=2 ) {
    1796           0 :             *dash_distance = ((dist_count * *dash_distance) + maCurrState.maDashArray[i%maCurrState.maDashArray.size()])/(dist_count+1);
    1797           0 :             ++dist_count;
    1798             :         }
    1799             : 
    1800           0 :         *dots1 = 1;
    1801           0 :         *dots1_length = maCurrState.maDashArray[0];
    1802           0 :         int i=2;
    1803           0 :         while( ( i<effective_dasharray_size ) && ( maCurrState.maDashArray[i%maCurrState.maDashArray.size()] == *dots1_length ) ) {
    1804           0 :             ++(*dots1);
    1805           0 :             i += 2;
    1806             :         }
    1807           0 :         if( i<effective_dasharray_size ) {
    1808           0 :             *dots2 = 1;
    1809           0 :             *dots2_length = maCurrState.maDashArray[i];
    1810           0 :             i+=2;
    1811           0 :             while( ( i<effective_dasharray_size ) && ( maCurrState.maDashArray[i%maCurrState.maDashArray.size()] == *dots2_length ) ) {
    1812           0 :                 ++(*dots2);
    1813           0 :                 i += 2;
    1814             :             }
    1815             :         }
    1816             : 
    1817             :         SAL_INFO("svg", "SvgDashArray2Odf " << *dash_distance << " " << *dots1 << " " << *dots1_length << " " << *dots2 << " " << *dots2_length );
    1818             : 
    1819           0 :         return;
    1820             :     }
    1821             : 
    1822           0 :     void push() {}
    1823           0 :     void pop()  {}
    1824             : 
    1825             :     State                                      maCurrState;
    1826             :     StateMap&                                  mrStateMap;
    1827             :     uno::Reference<xml::sax::XDocumentHandler> mxDocumentHandler;
    1828             : };
    1829             : 
    1830           0 : static void writeOfficeStyles(  StateMap&                                         rStateMap,
    1831             :                                 const uno::Reference<xml::dom::XElement>          xElem,
    1832             :                                 const uno::Reference<xml::sax::XDocumentHandler>& xDocHdl )
    1833             : {
    1834           0 :     OfficeStylesWritingVisitor aVisitor( rStateMap, xDocHdl );
    1835           0 :     visitElements( aVisitor, xElem );
    1836           0 : }
    1837             : 
    1838             : #if OSL_DEBUG_LEVEL > 2
    1839             : struct DumpingVisitor
    1840             : {
    1841             :     void operator()( const uno::Reference<xml::dom::XElement>& xElem )
    1842             :     {
    1843             :         OSL_TRACE("name: %s",
    1844             :                   OUStringToOString(
    1845             :                       xElem->getTagName(),
    1846             :                       RTL_TEXTENCODING_UTF8 ).getStr());
    1847             :     }
    1848             : 
    1849             :     void operator()( const uno::Reference<xml::dom::XElement>&      xElem,
    1850             :                      const uno::Reference<xml::dom::XNamedNodeMap>& xAttributes )
    1851             :     {
    1852             :         OSL_TRACE("name: %s",
    1853             :                   OUStringToOString(
    1854             :                       xElem->getTagName(),
    1855             :                       RTL_TEXTENCODING_UTF8 ).getStr());
    1856             :         const sal_Int32 nNumAttrs( xAttributes->getLength() );
    1857             :         for( sal_Int32 i=0; i<nNumAttrs; ++i )
    1858             :         {
    1859             :             OSL_TRACE(" %s=%s",
    1860             :                       OUStringToOString(
    1861             :                           xAttributes->item(i)->getNodeName(),
    1862             :                           RTL_TEXTENCODING_UTF8 ).getStr(),
    1863             :                       OUStringToOString(
    1864             :                           xAttributes->item(i)->getNodeValue(),
    1865             :                           RTL_TEXTENCODING_UTF8 ).getStr());
    1866             :         }
    1867             :     }
    1868             : 
    1869             :     void push() {}
    1870             :     void pop()  {}
    1871             : };
    1872             : 
    1873             : static void dumpTree( const uno::Reference<xml::dom::XElement> xElem )
    1874             : {
    1875             :     DumpingVisitor aVisitor;
    1876             :     visitElements(aVisitor, xElem);
    1877             : }
    1878             : #endif
    1879             : 
    1880             : 
    1881           0 : SVGReader::SVGReader(const uno::Reference<uno::XComponentContext>&     xContext,
    1882             :                      const uno::Reference<io::XInputStream>&           xInputStream,
    1883             :                      const uno::Reference<xml::sax::XDocumentHandler>& xDocumentHandler) :
    1884             :     m_xContext( xContext ),
    1885             :     m_xInputStream( xInputStream ),
    1886           0 :     m_xDocumentHandler( xDocumentHandler )
    1887             : {
    1888           0 : }
    1889             : 
    1890           0 : sal_Bool SVGReader::parseAndConvert()
    1891             : {
    1892           0 :     uno::Reference<xml::dom::XDocumentBuilder> xDomBuilder = xml::dom::DocumentBuilder::create(m_xContext);
    1893             : 
    1894             :     uno::Reference<xml::dom::XDocument> xDom(
    1895           0 :         xDomBuilder->parse(m_xInputStream),
    1896           0 :         uno::UNO_QUERY_THROW );
    1897             : 
    1898           0 :     uno::Reference<xml::dom::XElement> xDocElem( xDom->getDocumentElement(),
    1899           0 :                                                  uno::UNO_QUERY_THROW );
    1900             : 
    1901             :     // the root state for svg document
    1902           0 :     State aInitialState;
    1903             : 
    1904             :     /////////////////////////////////////////////////////////////////
    1905             :     // doc boilerplate
    1906             :     /////////////////////////////////////////////////////////////////
    1907             : 
    1908           0 :     m_xDocumentHandler->startDocument();
    1909             : 
    1910             :     // get the document dimensions
    1911             : 
    1912             :     // if the "width" and "height" attributes are missing, inkscape fakes
    1913             :     // A4 portrait for. Let's do the same.
    1914           0 :     if (!xDocElem->hasAttribute("width"))
    1915           0 :         xDocElem->setAttribute("width", "210mm");
    1916           0 :     if (!xDocElem->hasAttribute("height"))
    1917           0 :         xDocElem->setAttribute("height", "297mm");
    1918             : 
    1919           0 :     double fViewPortWidth( pt2mm(convLength(xDocElem->getAttribute("width"),aInitialState,'h')) );
    1920           0 :     double fViewPortHeight( pt2mm(convLength(xDocElem->getAttribute("height"),aInitialState,'v')) );
    1921             : 
    1922             :     // document prolog
    1923           0 :     rtl::Reference<SvXMLAttributeList> xAttrs( new SvXMLAttributeList() );
    1924           0 :     uno::Reference<xml::sax::XAttributeList> xUnoAttrs( xAttrs.get() );
    1925             : 
    1926           0 :     xAttrs->AddAttribute( "xmlns:office", OASIS_STR "office:1.0" );
    1927           0 :     xAttrs->AddAttribute( "xmlns:style", OASIS_STR "style:1.0" );
    1928           0 :     xAttrs->AddAttribute( "xmlns:text", OASIS_STR "text:1.0" );
    1929           0 :     xAttrs->AddAttribute( "xmlns:svg", OASIS_STR "svg-compatible:1.0" );
    1930           0 :     xAttrs->AddAttribute( "xmlns:table", OASIS_STR "table:1.0" );
    1931           0 :     xAttrs->AddAttribute( "xmlns:draw", OASIS_STR "drawing:1.0" );
    1932           0 :     xAttrs->AddAttribute( "xmlns:fo", OASIS_STR "xsl-fo-compatible:1.0" );
    1933           0 :     xAttrs->AddAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink");
    1934           0 :     xAttrs->AddAttribute( "xmlns:dc", "http://purl.org/dc/elements/1.1/");
    1935           0 :     xAttrs->AddAttribute( "xmlns:number", OASIS_STR "datastyle:1.0" );
    1936           0 :     xAttrs->AddAttribute( "xmlns:presentation", OASIS_STR "presentation:1.0" );
    1937           0 :     xAttrs->AddAttribute( "xmlns:math", "http://www.w3.org/1998/Math/MathML");
    1938           0 :     xAttrs->AddAttribute( "xmlns:form", OASIS_STR "form:1.0" );
    1939           0 :     xAttrs->AddAttribute( "xmlns:script", OASIS_STR "script:1.0" );
    1940           0 :     xAttrs->AddAttribute( "xmlns:dom", "http://www.w3.org/2001/xml-events");
    1941           0 :     xAttrs->AddAttribute( "xmlns:xforms", "http://www.w3.org/2002/xforms");
    1942           0 :     xAttrs->AddAttribute( "xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
    1943           0 :     xAttrs->AddAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
    1944           0 :     xAttrs->AddAttribute( "office:version", "1.0");
    1945           0 :     xAttrs->AddAttribute( "office:mimetype", "application/vnd.oasis.opendocument.graphics");
    1946             : 
    1947           0 :     m_xDocumentHandler->startElement( "office:document", xUnoAttrs );
    1948             : 
    1949           0 :     xAttrs->Clear();
    1950             : 
    1951           0 :     m_xDocumentHandler->startElement( "office:settings", xUnoAttrs);
    1952             : 
    1953           0 :     xAttrs->AddAttribute( "config:name", "ooo:view-settings");
    1954           0 :     m_xDocumentHandler->startElement( "config:config-item-set", xUnoAttrs);
    1955             : 
    1956           0 :     xAttrs->Clear();
    1957             : 
    1958           0 :     xAttrs->AddAttribute( "config:name", "VisibleAreaTop");
    1959           0 :     xAttrs->AddAttribute( "config:type", "int");
    1960           0 :     m_xDocumentHandler->startElement( "config:config-item", xUnoAttrs);
    1961             : 
    1962           0 :     m_xDocumentHandler->characters( "0" );
    1963             : 
    1964           0 :     m_xDocumentHandler->endElement( "config:config-item" );
    1965             : 
    1966           0 :     xAttrs->Clear();
    1967             : 
    1968           0 :     xAttrs->AddAttribute( "config:name", "VisibleAreaLeft" );
    1969           0 :     xAttrs->AddAttribute( "config:type", "int" );
    1970           0 :     m_xDocumentHandler->startElement( "config:config-item" , xUnoAttrs);
    1971             : 
    1972           0 :     m_xDocumentHandler->characters( "0" );
    1973             : 
    1974           0 :     m_xDocumentHandler->endElement( "config:config-item" );
    1975             : 
    1976           0 :     xAttrs->Clear();
    1977             : 
    1978           0 :     xAttrs->AddAttribute( "config:name" , "VisibleAreaWidth" );
    1979           0 :     xAttrs->AddAttribute( "config:type" , "int" );
    1980           0 :     m_xDocumentHandler->startElement( "config:config-item" , xUnoAttrs);
    1981             : 
    1982           0 :     sal_Int64 iWidth = sal_Int64(fViewPortWidth);
    1983           0 :     m_xDocumentHandler->characters( OUString::valueOf(iWidth) );
    1984             : 
    1985           0 :     m_xDocumentHandler->endElement( "config:config-item" );
    1986             : 
    1987           0 :     xAttrs->Clear();
    1988             : 
    1989           0 :     xAttrs->AddAttribute( "config:name", "VisibleAreaHeight" );
    1990           0 :     xAttrs->AddAttribute( "config:type", "int" );
    1991           0 :     m_xDocumentHandler->startElement( "config:config-item", xUnoAttrs);
    1992             : 
    1993           0 :     sal_Int64 iHeight = sal_Int64(fViewPortHeight);
    1994           0 :     m_xDocumentHandler->characters( OUString::valueOf(iHeight) );
    1995             : 
    1996           0 :     m_xDocumentHandler->endElement( "config:config-item" );
    1997             : 
    1998           0 :     m_xDocumentHandler->endElement( "config:config-item-set" );
    1999             : 
    2000           0 :     m_xDocumentHandler->endElement( "office:settings" );
    2001             : 
    2002           0 :     xAttrs->Clear();
    2003             : 
    2004           0 :     m_xDocumentHandler->startElement( "office:automatic-styles",
    2005           0 :                                       xUnoAttrs );
    2006             : 
    2007           0 :     xAttrs->AddAttribute( "style:name", "pagelayout1");
    2008           0 :     m_xDocumentHandler->startElement( "style:page-layout", xUnoAttrs );
    2009             :     // TODO(Q3): this is super-ugly. In-place container come to mind.
    2010           0 :     xAttrs->Clear();
    2011             : 
    2012             :     // make page viewport-width times viewport-height mm large - add
    2013             :     // 5% border at every side
    2014           0 :     xAttrs->AddAttribute( "fo:margin-top", "0mm");
    2015           0 :     xAttrs->AddAttribute( "fo:margin-bottom", "0mm");
    2016           0 :     xAttrs->AddAttribute( "fo:margin-left", "0mm");
    2017           0 :     xAttrs->AddAttribute( "fo:margin-right", "0mm");
    2018           0 :     xAttrs->AddAttribute( "fo:page-width", OUString::valueOf(fViewPortWidth)+"mm");
    2019           0 :     xAttrs->AddAttribute( "fo:page-height", OUString::valueOf(fViewPortHeight)+"mm");
    2020             :     xAttrs->AddAttribute( "style:print-orientation",
    2021           0 :         fViewPortWidth > fViewPortHeight ? OUString("landscape") : OUString("portrait") );
    2022           0 :     m_xDocumentHandler->startElement( "style:page-layout-properties", xUnoAttrs );
    2023           0 :     m_xDocumentHandler->endElement( "style:page-layout-properties" );
    2024           0 :     m_xDocumentHandler->endElement( "style:page-layout" );
    2025             : 
    2026           0 :     xAttrs->Clear();
    2027           0 :     xAttrs->AddAttribute( "style:name", "pagestyle1" );
    2028           0 :     xAttrs->AddAttribute( "style:family", "drawing-page" );
    2029           0 :     m_xDocumentHandler->startElement( "style:style", xUnoAttrs );
    2030             : 
    2031           0 :     xAttrs->Clear();
    2032           0 :     xAttrs->AddAttribute( "draw:background-size", "border");
    2033           0 :     xAttrs->AddAttribute( "draw:fill", "none");
    2034           0 :     m_xDocumentHandler->startElement( "style:drawing-page-properties", xUnoAttrs );
    2035           0 :     m_xDocumentHandler->endElement( "style:drawing-page-properties" );
    2036           0 :     m_xDocumentHandler->endElement( "style:style" );
    2037             : 
    2038           0 :     StatePool aStatePool;
    2039           0 :     StateMap  aStateMap;
    2040             :     annotateStyles(aStatePool,aStateMap,aInitialState,
    2041           0 :                    xDocElem,m_xDocumentHandler);
    2042             : 
    2043             : #if OSL_DEBUG_LEVEL > 2
    2044             :     dumpTree(xDocElem);
    2045             : #endif
    2046             : 
    2047           0 :     m_xDocumentHandler->endElement( "office:automatic-styles" );
    2048             : 
    2049             :     ////////////////////////////////////////////////////////////////////
    2050             : 
    2051           0 :     xAttrs->Clear();
    2052           0 :     m_xDocumentHandler->startElement( "office:styles", xUnoAttrs);
    2053             :     writeOfficeStyles( aStateMap,
    2054             :                        xDocElem,
    2055           0 :                        m_xDocumentHandler);
    2056           0 :     m_xDocumentHandler->endElement( "office:styles" );
    2057             : 
    2058             :     ////////////////////////////////////////////////////////////////////
    2059             : 
    2060           0 :     m_xDocumentHandler->startElement( "office:master-styles", xUnoAttrs );
    2061           0 :     xAttrs->Clear();
    2062           0 :     xAttrs->AddAttribute( "style:name", "Default");
    2063           0 :     xAttrs->AddAttribute( "style:page-layout-name", "pagelayout1");
    2064           0 :     xAttrs->AddAttribute( "draw:style-name", "pagestyle1");
    2065           0 :     m_xDocumentHandler->startElement( "style:master-page", xUnoAttrs );
    2066           0 :     m_xDocumentHandler->endElement( "style:master-page" );
    2067             : 
    2068           0 :     m_xDocumentHandler->endElement( "office:master-styles" );
    2069             : 
    2070             :     ////////////////////////////////////////////////////////////////////
    2071             : 
    2072           0 :     xAttrs->Clear();
    2073           0 :     m_xDocumentHandler->startElement( "office:body", xUnoAttrs );
    2074           0 :     m_xDocumentHandler->startElement( "office:drawing", xUnoAttrs );
    2075             : 
    2076           0 :     xAttrs->Clear();
    2077           0 :     xAttrs->AddAttribute( "draw:master-page-name", "Default");
    2078           0 :     xAttrs->AddAttribute( "draw:style-name", "pagestyle1");
    2079           0 :     m_xDocumentHandler->startElement("draw:page", xUnoAttrs);
    2080             : 
    2081             :     // write out all shapes
    2082             :     writeShapes(aStatePool,
    2083             :                 aStateMap,
    2084             :                 xDocElem,
    2085           0 :                 m_xDocumentHandler);
    2086             : 
    2087           0 :     m_xDocumentHandler->endElement( "draw:page" );
    2088           0 :     m_xDocumentHandler->endElement( "office:drawing" );
    2089           0 :     m_xDocumentHandler->endElement( "office:body" );
    2090           0 :     m_xDocumentHandler->endElement( "office:document" );
    2091           0 :     m_xDocumentHandler->endDocument();
    2092             : 
    2093           0 :     return sal_True;
    2094             : }
    2095             : 
    2096           0 : } // namespace svgi
    2097             : 
    2098             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10