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

Generated by: LCOV version 1.11