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

Generated by: LCOV version 1.10