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

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

Generated by: LCOV version 1.10