LCOV - code coverage report
Current view: top level - filter/source/svg - svgreader.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 0 1009 0.0 %
Date: 2014-04-11 Functions: 0 55 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10