1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include "svgreader.hxx"
11 #include <xmloff/attrlist.hxx>
12 #include "gfxtypes.hxx"
14 #include "parserfragments.hxx"
15 #include "tokenmap.hxx"
16 #include "b2dellipse.hxx"
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>
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>
45 #include <boost/bind.hpp>
46 #include <boost/unordered_set.hpp>
50 #define OASIS_STR "urn:oasis:names:tc:opendocument:xmlns:"
52 using namespace ::com::sun::star
;
59 /** visits all children of the specified type with the given functor
61 template<typename Func
> void visitChildren(const Func
& rFunc
,
62 const uno::Reference
<xml::dom::XElement
> xElem
,
63 xml::dom::NodeType eChildType
)
65 uno::Reference
<xml::dom::XNodeList
> xChildren( xElem
->getChildNodes() );
66 const sal_Int32
nNumNodes( xChildren
->getLength() );
67 for( sal_Int32 i
=0; i
<nNumNodes
; ++i
)
69 SAL_INFO("svg", "node type: " << sal::static_int_cast
<sal_uInt32
>(xChildren
->item(i
)->getNodeType()) << " tag name " << xChildren
->item(i
)->getNodeName() << " value |" << xChildren
->item(i
)->getNodeValue() << "|");
70 if( xChildren
->item(i
)->getNodeType() == eChildType
)
71 rFunc( *xChildren
->item(i
).get() );
75 /** Visit all elements of the given tree (in-order traversal)
77 Given functor is called for every element, and passed the
78 element's attributes, if any
80 template<typename Func
> void visitElements(Func
& rFunc
,
81 const uno::Reference
<xml::dom::XElement
> xElem
)
83 if( xElem
->hasAttributes() )
84 rFunc(xElem
,xElem
->getAttributes());
88 // notify children processing
91 // recurse over children
92 uno::Reference
<xml::dom::XNodeList
> xChildren( xElem
->getChildNodes() );
93 const sal_Int32
nNumNodes( xChildren
->getLength() );
94 for( sal_Int32 i
=0; i
<nNumNodes
; ++i
)
96 if( xChildren
->item(i
)->getNodeType() == xml::dom::NodeType_ELEMENT_NODE
)
98 uno::Reference
<xml::dom::XElement
>(
100 uno::UNO_QUERY_THROW
) );
103 // children processing done
107 template<typename value_type
> value_type
square(value_type v
)
112 double colorDiffSquared(const ARGBColor
& rCol1
, const ARGBColor
& rCol2
)
115 square(rCol1
.a
-rCol2
.a
)
116 + square(rCol1
.r
-rCol2
.r
)
117 + square(rCol1
.g
-rCol2
.g
)
118 + square(rCol1
.b
-rCol2
.b
);
121 typedef std::map
<OUString
,sal_Size
> ElementRefMapType
;
123 struct AnnotatingVisitor
125 AnnotatingVisitor(StatePool
& rStatePool
,
127 const State
& rInitialState
,
128 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
) :
132 mrStates(rStatePool
),
133 mrStateMap(rStateMap
),
134 mxDocumentHandler(xDocumentHandler
),
136 maGradientStopVector()
138 maParentStates
.push_back(rInitialState
);
141 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
)
143 const sal_Int32
nTagId(getTokenId(xElem
->getTagName()));
144 if (nTagId
!= XML_TEXT
)
147 maCurrState
= maParentStates
.back();
148 maCurrState
.maTransform
.identity();
149 maCurrState
.maViewBox
.reset();
150 // if necessary, serialize to automatic-style section
151 writeStyle(xElem
,nTagId
);
154 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
,
155 const uno::Reference
<xml::dom::XNamedNodeMap
>& xAttributes
)
157 const sal_Int32
nTagId(getTokenId(xElem
->getTagName()));
160 case XML_LINEARGRADIENT
:
162 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
163 maGradientVector
.push_back(Gradient(Gradient::LINEAR
));
165 // do we have a reference to a parent gradient? parse
166 // that first, as it sets our defaults here (manually
167 // tracking default state on each Gradient variable is
168 // much more overhead)
169 uno::Reference
<xml::dom::XNode
> xNode(xAttributes
->getNamedItem("href"));
172 const OUString
sValue(xNode
->getNodeValue());
173 ElementRefMapType::iterator aFound
=maGradientIdMap
.end();
174 if ( sValue
.copy(0,1) == "#" )
175 aFound
= maGradientIdMap
.find(sValue
.copy(1));
177 aFound
= maGradientIdMap
.find(sValue
);
179 if( aFound
!= maGradientIdMap
.end() )
180 maGradientVector
.back() = maGradientVector
[aFound
->second
];
183 // do that after dereferencing, to prevent hyperlinked
184 // gradient to clobber our Id again
185 maGradientVector
.back().mnId
= maGradientVector
.size()-1;
186 maGradientVector
.back().meType
= Gradient::LINEAR
; // has been clobbered as well
188 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
190 parseLinearGradientData( maGradientVector
.back(),
191 maGradientVector
.size()-1,
192 getTokenId(xAttributes
->item(i
)->getNodeName()),
193 xAttributes
->item(i
)->getNodeValue() );
197 case XML_RADIALGRADIENT
:
199 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
200 maGradientVector
.push_back(Gradient(Gradient::RADIAL
));
202 // do we have a reference to a parent gradient? parse
203 // that first, as it sets our defaults here (manually
204 // tracking default state on each Gradient variable is
205 // much more overhead)
206 uno::Reference
<xml::dom::XNode
> xNode(xAttributes
->getNamedItem("href"));
209 const OUString
sValue(xNode
->getNodeValue());
210 ElementRefMapType::iterator aFound
=maGradientIdMap
.end();
211 if ( sValue
.copy(0,1) == "#" )
212 aFound
= maGradientIdMap
.find(sValue
.copy(1));
214 aFound
= maGradientIdMap
.find(sValue
);
216 if( aFound
!= maGradientIdMap
.end() )
217 maGradientVector
.back() = maGradientVector
[aFound
->second
];
220 // do that after dereferencing, to prevent hyperlinked
221 // gradient to clobber our Id again
222 maGradientVector
.back().mnId
= maGradientVector
.size()-1;
223 maGradientVector
.back().meType
= Gradient::RADIAL
; // has been clobbered as well
225 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
227 parseRadialGradientData( maGradientVector
.back(),
228 maGradientVector
.size()-1,
229 getTokenId(xAttributes
->item(i
)->getNodeName()),
230 xAttributes
->item(i
)->getNodeValue() );
236 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
237 maGradientStopVector
.push_back(GradientStop());
238 maGradientVector
.back().maStops
.push_back(maGradientStopVector
.size()-1);
239 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
241 parseGradientStop( maGradientStopVector
.back(),
242 maGradientStopVector
.size()-1,
243 getTokenId(xAttributes
->item(i
)->getNodeName()),
244 xAttributes
->item(i
)->getNodeValue() );
250 // init state. inherit defaults from parent.
251 maCurrState
= maParentStates
.back();
252 maCurrState
.maTransform
.identity();
253 maCurrState
.maViewBox
.reset();
255 // scan for style info
256 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
257 OUString sAttributeValue
;
258 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
260 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
261 const sal_Int32
nTokenId(
262 getTokenId(xAttributes
->item(i
)->getNodeName()));
263 if( XML_STYLE
== nTokenId
)
264 parseStyle(sAttributeValue
);
266 parseAttribute(nTokenId
,
270 // all attributes parsed, can calc total CTM now
271 basegfx::B2DHomMatrix aLocalTransform
;
272 if( !maCurrState
.maViewBox
.isEmpty() &&
273 maCurrState
.maViewBox
.getWidth() != 0.0 &&
274 maCurrState
.maViewBox
.getHeight() != 0.0 )
276 // transform aViewBox into viewport, keep aspect ratio
277 aLocalTransform
.translate(-maCurrState
.maViewBox
.getMinX(),
278 -maCurrState
.maViewBox
.getMinY());
279 double scaleW
= maCurrState
.maViewport
.getWidth()/maCurrState
.maViewBox
.getWidth();
280 double scaleH
= maCurrState
.maViewport
.getHeight()/maCurrState
.maViewBox
.getHeight();
281 double scale
= (scaleW
< scaleH
) ? scaleW
: scaleH
;
282 aLocalTransform
.scale(scale
,scale
);
284 maCurrState
.maCTM
= maCurrState
.maCTM
*maCurrState
.maTransform
*aLocalTransform
;
286 OSL_TRACE("annotateStyle - CTM is: %f %f %f %f %f %f",
287 maCurrState
.maCTM
.get(0,0),
288 maCurrState
.maCTM
.get(0,1),
289 maCurrState
.maCTM
.get(0,2),
290 maCurrState
.maCTM
.get(1,0),
291 maCurrState
.maCTM
.get(1,1),
292 maCurrState
.maCTM
.get(1,2));
294 // if necessary, serialize to automatic-style section
295 writeStyle(xElem
,nTagId
);
300 OUString
getStyleName( const char* sPrefix
, sal_Int32 nId
)
302 return OUString::createFromAscii(sPrefix
)+OUString::valueOf(nId
);
305 bool hasGradientOpacity( const Gradient
& rGradient
)
308 (rGradient
.maStops
.size() > 1) &&
309 (maGradientStopVector
[
310 rGradient
.maStops
[0]].maStopColor
.a
!= 1.0 ||
311 maGradientStopVector
[
312 rGradient
.maStops
[1]].maStopColor
.a
!= 1.0);
317 explicit StopSorter( const std::vector
< GradientStop
>& rStopVec
) :
321 bool operator()( sal_Size rLHS
, sal_Size rRHS
)
323 return mrStopVec
[rLHS
].mnStopPosition
< mrStopVec
[rRHS
].mnStopPosition
;
326 const std::vector
< GradientStop
>& mrStopVec
;
329 void optimizeGradientStops( Gradient
& rGradient
)
331 // sort for increasing stop position
332 std::sort(rGradient
.maStops
.begin(),rGradient
.maStops
.end(),
333 StopSorter(maGradientStopVector
));
335 if( rGradient
.maStops
.size() < 3 )
338 // join similar colors
339 std::vector
<sal_Size
> aNewStops(1,rGradient
.maStops
.front());
340 for( sal_Size i
=1; i
<rGradient
.maStops
.size(); ++i
)
342 if( maGradientStopVector
[rGradient
.maStops
[i
]].maStopColor
!=
343 maGradientStopVector
[aNewStops
.back()].maStopColor
)
344 aNewStops
.push_back(rGradient
.maStops
[i
]);
347 rGradient
.maStops
= aNewStops
;
348 if (rGradient
.maStops
.size() < 2)
350 return; // can't optimize further...
353 // axial gradient, maybe?
354 if( rGradient
.meType
== Gradient::LINEAR
&&
355 rGradient
.maStops
.size() == 3 &&
356 maGradientStopVector
[rGradient
.maStops
.front()].maStopColor
==
357 maGradientStopVector
[rGradient
.maStops
.back()].maStopColor
)
359 // yep - keep it at that
363 // find out most significant color difference, and limit to
364 // those two stops around this border (metric is
365 // super-simplistic: take euclidean distance of colors, weigh
366 // with stop distance)
367 sal_Size nMaxIndex
=0;
368 double fMaxDistance
=0.0;
369 for( sal_Size i
=1; i
<rGradient
.maStops
.size(); ++i
)
371 const double fCurrDistance(
373 maGradientStopVector
[rGradient
.maStops
[i
-1]].maStopColor
,
374 maGradientStopVector
[rGradient
.maStops
[i
]].maStopColor
) *
375 (square(maGradientStopVector
[rGradient
.maStops
[i
-1]].mnStopPosition
) +
376 square(maGradientStopVector
[rGradient
.maStops
[i
]].mnStopPosition
)) );
378 if( fCurrDistance
> fMaxDistance
)
381 fMaxDistance
= fCurrDistance
;
384 rGradient
.maStops
[0] = rGradient
.maStops
[nMaxIndex
];
385 rGradient
.maStops
[1] = rGradient
.maStops
[nMaxIndex
+1];
386 rGradient
.maStops
.erase(rGradient
.maStops
.begin()+2,rGradient
.maStops
.end());
389 sal_Int8
toByteColor( double val
)
391 // TODO(Q3): duplicated from vcl::unotools
392 return sal::static_int_cast
<sal_Int8
>(
393 basegfx::fround(val
*255.0));
396 OUString
getOdfColor( const ARGBColor
& rColor
)
398 // TODO(Q3): duplicated from pdfimport
399 OUStringBuffer
aBuf( 7 );
400 const sal_uInt8
nRed ( toByteColor(rColor
.r
) );
401 const sal_uInt8
nGreen( toByteColor(rColor
.g
) );
402 const sal_uInt8
nBlue ( toByteColor(rColor
.b
) );
403 aBuf
.append( sal_Unicode('#') );
405 aBuf
.append( sal_Unicode('0') );
406 aBuf
.append( sal_Int32(nRed
), 16 );
408 aBuf
.append( sal_Unicode('0') );
409 aBuf
.append( sal_Int32(nGreen
), 16 );
411 aBuf
.append( sal_Unicode('0') );
412 aBuf
.append( sal_Int32(nBlue
), 16 );
414 // TODO(F3): respect alpha transparency (polygons etc.)
415 OSL_ASSERT(rColor
.a
== 1.0);
417 return aBuf
.makeStringAndClear();
420 OUString
getOdfAlign( TextAlign eAlign
)
422 static OUString
aStart("start");
423 static OUString
aEnd("end");
424 // static OUString aJustify("justify");
425 static OUString
aCenter("center");
438 bool writeStyle(State
& rState
, const sal_Int32 nTagId
)
440 rtl::Reference
<SvXMLAttributeList
> xAttrs( new SvXMLAttributeList() );
441 uno::Reference
<xml::sax::XAttributeList
> xUnoAttrs( xAttrs
.get() );
443 if (XML_TEXT
== nTagId
) {
444 rState
.mbIsText
= true;
445 basegfx::B2DTuple aScale
, aTranslate
;
446 double fRotate
, fShearX
;
447 if (rState
.maCTM
.decompose(aScale
, aTranslate
, fRotate
, fShearX
))
449 rState
.mnFontSize
*= aScale
.getX();
453 std::pair
<StatePool::iterator
,
454 bool> aRes
= mrStates
.insert(rState
);
455 SAL_INFO ("svg", "size " << mrStates
.size() << " id " << const_cast<State
&>(*aRes
.first
).mnStyleId
);
458 return false; // not written
462 // mnStyleId does not take part in hashing/comparison
463 const_cast<State
&>(*aRes
.first
).mnStyleId
= mnCurrStateId
;
464 SAL_INFO ("svg", " --> " << const_cast<State
&>(*aRes
.first
).mnStyleId
);
466 mrStateMap
.insert(std::make_pair(
470 // find two representative stop colors (as ODF only support
472 optimizeGradientStops(rState
.maFillGradient
);
474 if( !mxDocumentHandler
.is() )
475 return true; // cannot write style, svm import case
477 // do we have a gradient fill? then write out gradient as well
478 if( rState
.meFillType
== GRADIENT
&& rState
.maFillGradient
.maStops
.size() > 1 )
480 // TODO(F3): ODF12 supposedly also groks svg:linear/radialGradient. But CL says: nope.
481 xAttrs
->AddAttribute( "draw:name", getStyleName("svggradient", rState
.maFillGradient
.mnId
) );
482 if( rState
.maFillGradient
.meType
== Gradient::LINEAR
)
484 // should the optimizeGradientStops method decide that
485 // this is a three-color gradient, it prolly wanted us
486 // to take axial instead
487 xAttrs
->AddAttribute( "draw:style",
488 rState
.maFillGradient
.maStops
.size() == 3 ?
490 OUString("linear") );
494 xAttrs
->AddAttribute( "draw:style", "ellipsoid" );
495 xAttrs
->AddAttribute( "draw:cx", "50%" );
496 xAttrs
->AddAttribute( "draw:cy", "50%" );
499 basegfx::B2DTuple rScale
, rTranslate
;
500 double rRotate
, rShearX
;
501 if( rState
.maFillGradient
.maTransform
.decompose(rScale
, rTranslate
, rRotate
, rShearX
) )
502 xAttrs
->AddAttribute( "draw:angle",
503 OUString::valueOf(rRotate
*1800.0/M_PI
) );
504 xAttrs
->AddAttribute( "draw:start-color",
506 maGradientStopVector
[
507 rState
.maFillGradient
.maStops
[0]].maStopColor
) );
508 xAttrs
->AddAttribute( "draw:end-color",
510 maGradientStopVector
[
511 rState
.maFillGradient
.maStops
[1]].maStopColor
) );
512 xAttrs
->AddAttribute( "draw:border", "0%" );
513 mxDocumentHandler
->startElement( "draw:gradient", xUnoAttrs
);
514 mxDocumentHandler
->endElement( "draw:gradient" );
516 if( hasGradientOpacity(rState
.maFillGradient
) )
518 // need to write out opacity style as well
520 xAttrs
->AddAttribute( "draw:name", getStyleName("svgopacity", rState
.maFillGradient
.mnId
) );
521 if( rState
.maFillGradient
.meType
== Gradient::LINEAR
)
523 xAttrs
->AddAttribute( "draw:style", "linear" );
527 xAttrs
->AddAttribute( "draw:style", "ellipsoid" );
528 xAttrs
->AddAttribute( "draw:cx", "50%" );
529 xAttrs
->AddAttribute( "draw:cy", "50%" );
532 // modulate gradient opacity with overall fill opacity
533 xAttrs
->AddAttribute( "draw:end",
535 maGradientStopVector
[
536 rState
.maFillGradient
.maStops
[0]].maStopColor
.a
*
537 maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
*100.0)+"%" );
538 xAttrs
->AddAttribute( "draw:start",
540 maGradientStopVector
[
541 rState
.maFillGradient
.maStops
[1]].maStopColor
.a
*
542 maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
*100.0)+"%" );
543 xAttrs
->AddAttribute( "draw:border", "0%" );
544 mxDocumentHandler
->startElement( "draw:opacity", xUnoAttrs
);
545 mxDocumentHandler
->endElement( "draw:opacity" );
549 // serialize to automatic-style section
550 if( nTagId
== XML_TEXT
)
552 // write paragraph style attributes
555 xAttrs
->AddAttribute( "style:name", getStyleName("svgparagraphstyle", mnCurrStateId
) );
556 xAttrs
->AddAttribute( "style:family", "paragraph" );
557 mxDocumentHandler
->startElement( "style:style", xUnoAttrs
);
560 xAttrs
->AddAttribute( "fo:text-align", getOdfAlign(rState
.meTextAnchor
));
562 mxDocumentHandler
->startElement( "style:paragraph-properties", xUnoAttrs
);
563 mxDocumentHandler
->endElement( "style:paragraph-properties" );
564 mxDocumentHandler
->endElement( "style:style" );
566 // write text style attributes
569 xAttrs
->AddAttribute( "style:name", getStyleName("svgtextstyle", mnCurrStateId
) );
570 xAttrs
->AddAttribute( "style:family", "text" );
571 mxDocumentHandler
->startElement( "style:style", xUnoAttrs
);
573 xAttrs
->AddAttribute( "fo:font-family", rState
.maFontFamily
);
574 xAttrs
->AddAttribute( "fo:font-size",
575 OUString::valueOf(pt2mm(rState
.mnFontSize
))+"mm");
576 xAttrs
->AddAttribute( "fo:font-style", rState
.maFontStyle
);
577 xAttrs
->AddAttribute( "fo:font-variant", rState
.maFontVariant
);
578 xAttrs
->AddAttribute( "fo:font-weight",
579 OUString::valueOf(rState
.mnFontWeight
));
580 xAttrs
->AddAttribute( "fo:color", getOdfColor(rState
.maFillColor
));
582 mxDocumentHandler
->startElement( "style:text-properties", xUnoAttrs
);
583 mxDocumentHandler
->endElement( "style:text-properties" );
584 mxDocumentHandler
->endElement( "style:style" );
588 xAttrs
->AddAttribute( "style:name" , getStyleName("svggraphicstyle", mnCurrStateId
) );
589 xAttrs
->AddAttribute( "style:family", "graphic" );
590 mxDocumentHandler
->startElement( "style:style", xUnoAttrs
);
593 // text or shape? if the former, no use in processing any
594 // graphic attributes except stroke color, ODF can do ~nothing
596 if( nTagId
== XML_TEXT
)
598 //xAttrs->AddAttribute( "draw:auto-grow-height", "true");
599 xAttrs
->AddAttribute( "draw:auto-grow-width", "true");
600 xAttrs
->AddAttribute( "draw:textarea-horizontal-align", "left");
601 //xAttrs->AddAttribute( "draw:textarea-vertical-align", "top");
602 xAttrs
->AddAttribute( "fo:min-height", "0cm");
604 xAttrs
->AddAttribute( "fo:padding-top", "0cm");
605 xAttrs
->AddAttribute( "fo:padding-left", "0cm");
606 xAttrs
->AddAttribute( "fo:padding-right", "0cm");
607 xAttrs
->AddAttribute( "fo:padding-bottom", "0cm");
609 // disable any background shape
610 xAttrs
->AddAttribute( "draw:stroke", "none");
611 xAttrs
->AddAttribute( "draw:fill", "none");
615 if( rState
.meFillType
!= NONE
)
617 if( rState
.meFillType
== GRADIENT
)
619 xAttrs
->AddAttribute( "draw:fill", "gradient");
620 xAttrs
->AddAttribute( "draw:fill-gradient-name",
621 getStyleName("svggradient", rState
.maFillGradient
.mnId
) );
622 if( hasGradientOpacity(rState
.maFillGradient
) )
624 // needs transparency gradient as well
625 xAttrs
->AddAttribute( "draw:opacity-name",
626 getStyleName("svgopacity", rState
.maFillGradient
.mnId
) );
628 else if( maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
!= 1.0 )
629 xAttrs
->AddAttribute( "draw:opacity",
630 OUString::valueOf(100.0*maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
)+"%" );
634 xAttrs
->AddAttribute( "draw:fill", "solid");
635 xAttrs
->AddAttribute( "draw:fill-color", getOdfColor(rState
.maFillColor
));
636 if( maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
!= 1.0 )
637 xAttrs
->AddAttribute( "draw:opacity",
638 OUString::valueOf(100.0*maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
)+"%" );
642 xAttrs
->AddAttribute( "draw:fill", "none");
644 if( rState
.meStrokeType
== SOLID
)
646 xAttrs
->AddAttribute( "draw:stroke", "solid");
647 xAttrs
->AddAttribute( "svg:stroke-color", getOdfColor(rState
.maStrokeColor
));
649 else if( rState
.meStrokeType
== DASH
)
651 xAttrs
->AddAttribute( "draw:stroke", "dash");
652 xAttrs
->AddAttribute( "draw:stroke-dash", "dash"+OUString::valueOf(mnCurrStateId
));
653 xAttrs
->AddAttribute( "svg:stroke-color", getOdfColor(rState
.maStrokeColor
));
656 xAttrs
->AddAttribute( "draw:stroke", "none");
658 if( maCurrState
.mnStrokeWidth
!= 0.0 )
660 ::basegfx::B2DVector
aVec(maCurrState
.mnStrokeWidth
,0);
661 aVec
*= maCurrState
.maCTM
;
662 xAttrs
->AddAttribute( "svg:stroke-width", OUString::valueOf( pt2mm(aVec
.getLength()) )+"mm");
664 if( maCurrState
.meLineJoin
== basegfx::B2DLINEJOIN_MITER
)
665 xAttrs
->AddAttribute( "draw:stroke-linejoin", "miter");
666 else if( maCurrState
.meLineJoin
== basegfx::B2DLINEJOIN_ROUND
)
667 xAttrs
->AddAttribute( "draw:stroke-linejoin", "round");
668 else if( maCurrState
.meLineJoin
== basegfx::B2DLINEJOIN_BEVEL
)
669 xAttrs
->AddAttribute( "draw:stroke-linejoin", "bevel");
670 if( maCurrState
.mnStrokeOpacity
*maCurrState
.mnOpacity
!= 1.0 )
671 xAttrs
->AddAttribute( "svg:stroke-opacity",
672 OUString::valueOf(100.0*maCurrState
.mnStrokeOpacity
*maCurrState
.mnOpacity
)+"%");
675 mxDocumentHandler
->startElement( "style:graphic-properties", xUnoAttrs
);
676 mxDocumentHandler
->endElement( "style:graphic-properties" );
677 mxDocumentHandler
->endElement( "style:style" );
679 return true; // newly written
682 void writeStyle(const uno::Reference
<xml::dom::XElement
>& xElem
, const sal_Int32 nTagId
)
684 SAL_INFO ("svg", "writeStyle xElem " << xElem
->getTagName());
686 sal_Int32 nStyleId
=0;
687 if( writeStyle(maCurrState
, nTagId
) )
688 nStyleId
= mnCurrStateId
;
690 nStyleId
= mrStates
.find(maCurrState
)->mnStyleId
;
692 xElem
->setAttribute("internal-style-ref",
700 maParentStates
.push_back(maCurrState
);
705 maParentStates
.pop_back();
708 void parseLinearGradientData( Gradient
& io_rCurrGradient
,
709 const sal_Int32 nGradientNumber
,
710 const sal_Int32 nTokenId
,
711 const OUString
& sValue
)
715 case XML_GRADIENTTRANSFORM
:
717 OString
aValueUtf8( sValue
.getStr(),
719 RTL_TEXTENCODING_UTF8
);
720 parseTransform(aValueUtf8
.getStr(),io_rCurrGradient
.maTransform
);
724 io_rCurrGradient
.maCoords
.linear
.mfX1
= convLength(sValue
,maCurrState
,'h');
727 io_rCurrGradient
.maCoords
.linear
.mfX2
= convLength(sValue
,maCurrState
,'h');
730 io_rCurrGradient
.maCoords
.linear
.mfY1
= convLength(sValue
,maCurrState
,'v');
733 io_rCurrGradient
.maCoords
.linear
.mfY2
= convLength(sValue
,maCurrState
,'v');
736 maGradientIdMap
.insert(std::make_pair(sValue
,nGradientNumber
));
738 case XML_GRADIENTUNITS
:
739 if (getTokenId(sValue
) == XML_OBJECTBOUNDINGBOX
)
740 io_rCurrGradient
.mbBoundingBoxUnits
= true;
742 io_rCurrGradient
.mbBoundingBoxUnits
= false;
749 void parseRadialGradientData( Gradient
& io_rCurrGradient
,
750 const sal_Int32 nGradientNumber
,
751 const sal_Int32 nTokenId
,
752 const OUString
& sValue
)
756 case XML_GRADIENTTRANSFORM
:
758 OString
aValueUtf8( sValue
.getStr(),
760 RTL_TEXTENCODING_UTF8
);
761 parseTransform(aValueUtf8
.getStr(),io_rCurrGradient
.maTransform
);
765 io_rCurrGradient
.maCoords
.radial
.mfCX
= convLength(sValue
,maCurrState
,'h');
768 io_rCurrGradient
.maCoords
.radial
.mfCY
= convLength(sValue
,maCurrState
,'v');
771 io_rCurrGradient
.maCoords
.radial
.mfFX
= convLength(sValue
,maCurrState
,'h');
774 io_rCurrGradient
.maCoords
.radial
.mfFY
= convLength(sValue
,maCurrState
,'v');
777 io_rCurrGradient
.maCoords
.radial
.mfR
= convLength(sValue
,maCurrState
,'r');
780 maGradientIdMap
.insert(std::make_pair(sValue
,nGradientNumber
));
782 case XML_GRADIENTUNITS
:
783 if (getTokenId(sValue
) == XML_OBJECTBOUNDINGBOX
)
784 io_rCurrGradient
.mbBoundingBoxUnits
= true;
786 io_rCurrGradient
.mbBoundingBoxUnits
= false;
793 void parseGradientStop( GradientStop
& io_rGradientStop
,
794 const sal_Int32 nStopNumber
,
795 const sal_Int32 nTokenId
,
796 const OUString
& sValue
)
802 ElementRefMapType::iterator aFound
=maStopIdMap
.end();
803 if ( sValue
.copy(0,1) == "#" )
804 aFound
= maStopIdMap
.find(sValue
.copy(1));
806 aFound
= maStopIdMap
.find(sValue
);
808 if( aFound
!= maStopIdMap
.end() )
809 io_rGradientStop
= maGradientStopVector
[aFound
->second
];
813 maStopIdMap
.insert(std::make_pair(sValue
,nStopNumber
));
816 io_rGradientStop
.mnStopPosition
= sValue
.toDouble();
819 parseStyle( sValue
);
826 void parseAttribute( const sal_Int32 nTokenId
,
827 const OUString
& sValue
)
829 OString
aValueUtf8( sValue
.getStr(),
831 RTL_TEXTENCODING_UTF8
);
836 const double fViewPortWidth(
837 convLength(sValue
,maCurrState
,'h'));
839 maCurrState
.maViewport
.expand(
840 basegfx::B2DTuple(fViewPortWidth
,0.0));
845 const double fViewPortHeight(
846 convLength(sValue
,maCurrState
,'v'));
848 maCurrState
.maViewport
.expand(
849 basegfx::B2DTuple(0.0,fViewPortHeight
));
854 // TODO(F1): preserveAspectRatio
857 maCurrState
.maViewBox
);
862 if( aValueUtf8
== "evenodd" )
863 maCurrState
.meFillRule
= EVEN_ODD
;
864 else if( aValueUtf8
== "nonzero" )
865 maCurrState
.meFillRule
= NON_ZERO
;
866 else if( aValueUtf8
== "inherit" )
867 maCurrState
.meFillRule
= maParentStates
.back().meFillRule
;
871 if( aValueUtf8
== "inherit" )
872 maCurrState
.mnOpacity
= maParentStates
.back().mnOpacity
;
874 maCurrState
.mnOpacity
= aValueUtf8
.toDouble();
876 case XML_FILL_OPACITY
:
877 if( aValueUtf8
== "inherit" )
878 maCurrState
.mnFillOpacity
= maParentStates
.back().mnFillOpacity
;
880 maCurrState
.mnFillOpacity
= aValueUtf8
.toDouble();
881 if( maCurrState
.mnFillOpacity
> 1 )
882 maCurrState
.mnFillOpacity
= 1;
885 case XML_STROKE_WIDTH
:
887 if( aValueUtf8
== "inherit" )
888 maCurrState
.mnStrokeWidth
= maParentStates
.back().mnStrokeWidth
;
890 maCurrState
.mnStrokeWidth
= convLength(sValue
,maCurrState
,'r');
893 case XML_STROKE_LINECAP
:
895 if( aValueUtf8
== "butt" )
896 maCurrState
.meLineCap
= BUTT
;
897 else if( aValueUtf8
== "round" )
898 maCurrState
.meLineCap
= ROUND
;
899 else if( aValueUtf8
== "square" )
900 maCurrState
.meLineCap
= RECT
;
901 else if( aValueUtf8
== "inherit" )
902 maCurrState
.meLineCap
= maParentStates
.back().meLineCap
;
905 case XML_STROKE_LINEJOIN
:
907 if( aValueUtf8
== "miter" )
908 maCurrState
.meLineJoin
= basegfx::B2DLINEJOIN_MITER
;
909 else if( aValueUtf8
== "round" )
910 maCurrState
.meLineJoin
= basegfx::B2DLINEJOIN_ROUND
;
911 else if( aValueUtf8
== "bevel" )
912 maCurrState
.meLineJoin
= basegfx::B2DLINEJOIN_BEVEL
;
913 else if( aValueUtf8
== "inherit" )
914 maCurrState
.meLineJoin
= maParentStates
.back().meLineJoin
;
917 case XML_STROKE_MITERLIMIT
:
919 if( aValueUtf8
== "inherit" )
920 maCurrState
.mnMiterLimit
= maParentStates
.back().mnMiterLimit
;
922 maCurrState
.mnMiterLimit
= aValueUtf8
.toDouble();
925 case XML_STROKE_DASHOFFSET
:
927 if( aValueUtf8
== "inherit" )
928 maCurrState
.mnDashOffset
= maParentStates
.back().mnDashOffset
;
930 maCurrState
.mnDashOffset
= convLength(sValue
,maCurrState
,'r');
933 case XML_STROKE_DASHARRAY
:
935 if( aValueUtf8
== "none" )
937 maCurrState
.maDashArray
.clear();
938 maCurrState
.meStrokeType
= SOLID
;
940 else if( aValueUtf8
== "inherit" )
941 maCurrState
.maDashArray
= maParentStates
.back().maDashArray
;
944 parseDashArray(aValueUtf8
.getStr(),
945 maCurrState
.maDashArray
);
946 maCurrState
.meStrokeType
= DASH
;
950 case XML_STROKE_OPACITY
:
951 if( aValueUtf8
== "inherit" )
952 maCurrState
.mnStrokeOpacity
= maParentStates
.back().mnStrokeOpacity
;
954 maCurrState
.mnStrokeOpacity
= aValueUtf8
.toDouble();
958 const State
& rParent( maParentStates
.back() );
961 maCurrState
.meFillType
,
962 maCurrState
.maFillColor
,
963 maCurrState
.maFillGradient
,
966 rParent
.maFillGradient
);
971 const State
& rParent( maParentStates
.back() );
974 maCurrState
.meStrokeType
,
975 maCurrState
.maStrokeColor
,
976 maCurrState
.maStrokeGradient
,
977 rParent
.meStrokeType
,
978 rParent
.maStrokeColor
,
979 rParent
.maStrokeGradient
);
984 if( aValueUtf8
== "inherit" )
985 maCurrState
.maCurrentColor
= maParentStates
.back().maCurrentColor
;
987 parseColor(aValueUtf8
.getStr(), maCurrState
.maCurrentColor
);
992 basegfx::B2DHomMatrix aTransform
;
993 parseTransform(aValueUtf8
.getStr(),aTransform
);
994 maCurrState
.maTransform
= maCurrState
.maTransform
*aTransform
;
997 case XML_FONT_FAMILY
:
998 maCurrState
.maFontFamily
=sValue
;
1001 maCurrState
.mnFontSize
=convLength(sValue
,maCurrState
,'v');
1003 case XML_FONT_STYLE
:
1004 parseFontStyle(maCurrState
,sValue
,aValueUtf8
.getStr());
1006 case XML_FONT_WEIGHT
:
1007 maCurrState
.mnFontWeight
=sValue
.toDouble();
1009 case XML_FONT_VARIANT
:
1010 parseFontVariant(maCurrState
,sValue
,aValueUtf8
.getStr());
1012 case XML_TEXT_ANCHOR
:
1013 parseTextAlign(maCurrState
,aValueUtf8
.getStr());
1015 case XML_STOP_COLOR
:
1016 if( maGradientVector
.empty() ||
1017 maGradientVector
.back().maStops
.empty() )
1019 parseColor( aValueUtf8
.getStr(),
1020 maGradientStopVector
[
1021 maGradientVector
.back().maStops
.back()].maStopColor
);
1023 case XML_STOP_OPACITY
:
1024 if( maGradientVector
.empty() ||
1025 maGradientVector
.back().maStops
.empty() )
1027 parseOpacity( aValueUtf8
.getStr(),
1028 maGradientStopVector
[
1029 maGradientVector
.back().maStops
.back()].maStopColor
);
1032 SAL_INFO("svg", "unhandled token " << getTokenName(nTokenId
));
1037 void parseStyle( const OUString
& sValue
)
1039 // split individual style attributes
1040 sal_Int32 nIndex
=0, nDummyIndex
=0;
1041 OUString aCurrToken
;
1044 aCurrToken
=sValue
.getToken(0,';',nIndex
);
1046 if( !aCurrToken
.isEmpty() )
1048 // split attrib & value
1050 OUString
aCurrAttrib(
1051 aCurrToken
.getToken(0,':',nDummyIndex
).trim());
1052 OSL_ASSERT(nDummyIndex
!=-1);
1054 OUString
aCurrValue(
1055 aCurrToken
.getToken(1,':',nDummyIndex
).trim());
1056 OSL_ASSERT(nDummyIndex
==-1);
1058 // recurse into normal attribute parsing
1059 parseAttribute( getTokenId(aCurrAttrib
),
1063 while( nIndex
!= -1 );
1066 void parseFontStyle( State
& io_rInitialState
,
1067 const OUString
& rValue
,
1068 const char* sValue
)
1070 if( strcmp(sValue
,"inherit") != 0 )
1071 io_rInitialState
.maFontStyle
= rValue
;
1074 void parseFontVariant( State
& io_rInitialState
,
1075 const OUString
& rValue
,
1076 const char* sValue
)
1078 if( strcmp(sValue
,"inherit") != 0 )
1079 io_rInitialState
.maFontVariant
= rValue
;
1082 void parseTextAlign( State
& io_rInitialState
,
1083 const char* sValue
)
1085 if( strcmp(sValue
,"start") == 0 )
1086 io_rInitialState
.meTextAnchor
= BEFORE
;
1087 else if( strcmp(sValue
,"middle") == 0 )
1088 io_rInitialState
.meTextAnchor
= CENTER
;
1089 else if( strcmp(sValue
,"end") == 0 )
1090 io_rInitialState
.meTextAnchor
= AFTER
;
1091 // keep current val for sValue == "inherit"
1094 void parsePaint( const OUString
& rValue
,
1098 Gradient
& rGradient
,
1099 const PaintType
& rInheritType
,
1100 const ARGBColor
& rInheritColor
,
1101 const Gradient
& rInheritGradient
)
1103 std::pair
<const char*,const char*> aPaintUri((const char*)NULL
,(const char*)NULL
);
1104 std::pair
<ARGBColor
,bool> aColor(maCurrState
.maCurrentColor
,
1106 if( strcmp(sValue
,"none") == 0 )
1108 else if( strcmp(sValue
,"currentColor") == 0 )
1111 rColor
= maCurrState
.maCurrentColor
;
1113 else if( strcmp(sValue
,"inherit") == 0)
1115 rType
= rInheritType
;
1116 rColor
= rInheritColor
;
1117 rGradient
= rInheritGradient
;
1119 else if( parsePaintUri(aPaintUri
,aColor
,sValue
) )
1121 if( aPaintUri
.first
!= aPaintUri
.second
)
1123 // assuming gradient. assumption does not hold generally
1124 if( strstr(sValue
,")") && rValue
.getLength() > 5 )
1126 ElementRefMapType::iterator aRes
;
1127 if( (aRes
=maGradientIdMap
.find(
1128 rValue
.copy(aPaintUri
.first
-sValue
,
1129 aPaintUri
.second
-aPaintUri
.first
))) != maGradientIdMap
.end() )
1131 rGradient
= maGradientVector
[aRes
->second
];
1136 else if( aColor
.second
)
1139 rColor
= aColor
.first
;
1149 parseColor(sValue
,rColor
);
1153 sal_Int32 mnCurrStateId
;
1155 std::vector
<State
> maParentStates
;
1156 StatePool
& mrStates
;
1157 StateMap
& mrStateMap
;
1158 uno::Reference
<xml::sax::XDocumentHandler
> mxDocumentHandler
;
1159 std::vector
< Gradient
> maGradientVector
;
1160 std::vector
< GradientStop
> maGradientStopVector
;
1161 ElementRefMapType maGradientIdMap
;
1162 ElementRefMapType maStopIdMap
;
1165 /// Annotate svg styles with unique references to state pool
1166 static void annotateStyles( StatePool
& rStatePool
,
1167 StateMap
& rStateMap
,
1168 const State
& rInitialState
,
1169 const uno::Reference
<xml::dom::XElement
> xElem
,
1170 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocHdl
)
1172 AnnotatingVisitor
aVisitor(rStatePool
,rStateMap
,rInitialState
,xDocHdl
);
1173 visitElements(aVisitor
, xElem
);
1176 struct ShapeWritingVisitor
1178 ShapeWritingVisitor(StatePool
& /*rStatePool*/,
1179 StateMap
& rStateMap
,
1180 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
) :
1181 mrStateMap(rStateMap
),
1182 mxDocumentHandler(xDocumentHandler
),
1186 void operator()( const uno::Reference
<xml::dom::XElement
>& )
1190 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
,
1191 const uno::Reference
<xml::dom::XNamedNodeMap
>& xAttributes
)
1193 rtl::Reference
<SvXMLAttributeList
> xAttrs( new SvXMLAttributeList() );
1194 uno::Reference
<xml::sax::XAttributeList
> xUnoAttrs( xAttrs
.get() );
1196 sal_Int32
nDummyIndex(0);
1198 xElem
->getAttribute("internal-style-ref").getToken(
1199 0,'$',nDummyIndex
));
1200 StateMap::iterator pOrigState
=mrStateMap
.find(
1201 sStyleId
.toInt32());
1203 if( pOrigState
== mrStateMap
.end() )
1204 return; // non-exportable element, e.g. linearGradient
1206 maCurrState
= pOrigState
->second
;
1208 const sal_Int32
nTokenId(getTokenId(xElem
->getNodeName()));
1213 // collect attributes
1214 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1215 OUString sAttributeValue
;
1216 double x1
=0.0,y1
=0.0,x2
=0.0,y2
=0.0;
1217 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1219 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1220 const sal_Int32
nAttribId(
1221 getTokenId(xAttributes
->item(i
)->getNodeName()));
1225 x1
= convLength(sAttributeValue
,maCurrState
,'h');
1228 x2
= convLength(sAttributeValue
,maCurrState
,'h');
1231 y1
= convLength(sAttributeValue
,maCurrState
,'v');
1234 y2
= convLength(sAttributeValue
,maCurrState
,'v');
1242 if ( x1
!= x2
|| y1
!= y2
) {
1243 OUString sLinePath
= "M"+OUString::valueOf(x1
)+","
1244 +OUString::valueOf(y1
)+"L"+OUString::valueOf(x2
)+","
1245 +OUString::valueOf(y2
);
1246 basegfx::B2DPolyPolygon aPoly
;
1247 basegfx::tools::importFromSvgD(aPoly
, sLinePath
);
1249 writePathShape(xAttrs
,
1253 basegfx::B2DPolyPolygon(aPoly
));
1261 OUString sPoints
= xElem
->hasAttribute("points") ? xElem
->getAttribute("points") : "";
1262 basegfx::B2DPolygon aPoly
;
1263 basegfx::tools::importFromSvgPoints(aPoly
, sPoints
);
1264 if( nTokenId
== XML_POLYGON
|| maCurrState
.meFillType
!= NONE
)
1265 aPoly
.setClosed(true);
1267 writePathShape(xAttrs
,
1271 basegfx::B2DPolyPolygon(aPoly
));
1276 // collect attributes
1277 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1278 OUString sAttributeValue
;
1279 bool bRxSeen
=false, bRySeen
=false;
1280 double x
=0.0,y
=0.0,width
=0.0,height
=0.0,rx
=0.0,ry
=0.0;
1281 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1283 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1284 const sal_Int32
nAttribId(
1285 getTokenId(xAttributes
->item(i
)->getNodeName()));
1289 x
= convLength(sAttributeValue
,maCurrState
,'h');
1292 y
= convLength(sAttributeValue
,maCurrState
,'v');
1295 width
= convLength(sAttributeValue
,maCurrState
,'h');
1298 height
= convLength(sAttributeValue
,maCurrState
,'v');
1301 rx
= convLength(sAttributeValue
,maCurrState
,'h');
1305 ry
= convLength(sAttributeValue
,maCurrState
,'v');
1314 if ( (width
> 0) && (height
> 0) ) {
1315 if( bRxSeen
&& !bRySeen
)
1317 else if( bRySeen
&& !bRxSeen
)
1320 basegfx::B2DPolygon aPoly
;
1321 aPoly
= basegfx::tools::createPolygonFromRect(
1322 basegfx::B2DRange(x
,y
,x
+width
,y
+height
),
1323 rx
/(0.5*width
), ry
/(0.5*height
) );
1325 writePathShape(xAttrs
,
1329 basegfx::B2DPolyPolygon(aPoly
));
1335 OUString sPath
= xElem
->hasAttribute("d") ? xElem
->getAttribute("d") : "";
1336 basegfx::B2DPolyPolygon aPoly
;
1337 basegfx::tools::importFromSvgD(aPoly
, sPath
);
1339 writePathShape(xAttrs
,
1348 // collect attributes
1349 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1350 OUString sAttributeValue
;
1351 double cx
=0.0,cy
=0.0,r
=0.0;
1352 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1354 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1355 const sal_Int32
nAttribId(
1356 getTokenId(xAttributes
->item(i
)->getNodeName()));
1360 cx
= convLength(sAttributeValue
,maCurrState
,'h');
1363 cy
= convLength(sAttributeValue
,maCurrState
,'v');
1366 r
= convLength(sAttributeValue
,maCurrState
,'r');
1374 writeEllipseShape(xAttrs
,
1378 basegfx::B2DEllipse(basegfx::B2DPoint(cx
, cy
), basegfx::B2DTuple(r
,r
)));
1383 // collect attributes
1384 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1385 OUString sAttributeValue
;
1386 double cx
=0.0,cy
=0.0,rx
=0.0, ry
=0.0;
1387 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1389 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1390 const sal_Int32
nAttribId(
1391 getTokenId(xAttributes
->item(i
)->getNodeName()));
1395 cx
= convLength(sAttributeValue
,maCurrState
,'h');
1398 cy
= convLength(sAttributeValue
,maCurrState
,'v');
1401 rx
= convLength(sAttributeValue
,maCurrState
,'h');
1404 ry
= convLength(sAttributeValue
,maCurrState
,'v');
1411 if ( rx
> 0 && ry
> 0 )
1412 writeEllipseShape(xAttrs
,
1416 basegfx::B2DEllipse(basegfx::B2DPoint(cx
, cy
), basegfx::B2DTuple(rx
,ry
)));
1421 // collect attributes
1422 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1423 OUString sAttributeValue
;
1424 double x
=0.0, y
=0.0, width
=0.0, height
=0.0;
1425 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1427 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1428 const sal_Int32
nAttribId(
1429 getTokenId(xAttributes
->item(i
)->getNodeName()));
1433 x
= convLength(sAttributeValue
,maCurrState
,'h');
1436 y
= convLength(sAttributeValue
,maCurrState
,'v');
1439 width
= convLength(sAttributeValue
,maCurrState
,'h');
1442 height
= convLength(sAttributeValue
,maCurrState
,'v');
1449 // extract basic transformations out of CTM
1450 basegfx::B2DTuple aScale
, aTranslate
;
1451 double fRotate
, fShearX
;
1452 if (maCurrState
.maCTM
.decompose(aScale
, aTranslate
, fRotate
, fShearX
))
1456 width
*= aScale
.getX();
1458 height
*= aScale
.getY();
1459 x
+= aTranslate
.getX();
1460 y
+= aTranslate
.getY();
1464 OUString sValue
= xElem
->hasAttribute("href") ? xElem
->getAttribute("href") : "";
1465 OString
aValueUtf8( sValue
.getStr(), sValue
.getLength(), RTL_TEXTENCODING_UTF8
);
1466 std::string sLinkValue
;
1467 parseXlinkHref(aValueUtf8
.getStr(), sLinkValue
);
1469 if (!sLinkValue
.empty())
1470 writeBinaryData(xAttrs
, xUnoAttrs
, xElem
, basegfx::B2DRange(x
,y
,x
+width
,y
+height
), sLinkValue
);
1475 // collect text from all TEXT_NODE children into sText
1476 OUStringBuffer sText
;
1477 visitChildren(boost::bind(
1478 (OUStringBuffer
& (OUStringBuffer::*)(const OUString
& str
))&OUStringBuffer::append
,
1480 boost::bind(&xml::dom::XNode::getNodeValue
,
1483 xml::dom::NodeType_TEXT_NODE
);
1485 // collect attributes
1486 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1487 OUString sAttributeValue
;
1489 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1491 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1492 const sal_Int32
nAttribId(
1493 getTokenId(xAttributes
->item(i
)->getNodeName()));
1497 x
= convLength(sAttributeValue
,maCurrState
,'h');
1500 y
= convLength(sAttributeValue
,maCurrState
,'v');
1508 // actually export text
1512 // extract basic transformations out of CTM
1513 basegfx::B2DTuple aScale
, aTranslate
;
1514 double fRotate
, fShearX
;
1515 if (maCurrState
.maCTM
.decompose(aScale
, aTranslate
, fRotate
, fShearX
))
1517 // some heuristic attempts to have text output
1518 // baseline-relative
1519 y
-= 2.0*maCurrState
.mnFontSize
/aScale
.getX()/3.0;
1523 x
+= aTranslate
.getX();
1524 y
+= aTranslate
.getY();
1528 // some heuristic attempts to have text output
1529 // baseline-relative
1530 y
-= 2.0*maCurrState
.mnFontSize
/3.0;
1533 xAttrs
->AddAttribute( "svg:x", OUString::valueOf(pt2mm(x
))+"mm");
1534 xAttrs
->AddAttribute( "svg:y", OUString::valueOf(pt2mm(y
))+"mm");
1535 xAttrs
->AddAttribute( "draw:style-name", "svggraphicstyle"+sStyleId
);
1537 mxDocumentHandler
->startElement("draw:frame", xUnoAttrs
);
1540 mxDocumentHandler
->startElement("draw:text-box", xUnoAttrs
);
1541 xAttrs
->AddAttribute( "text:style-name", "svgparagraphstyle"+sStyleId
);
1542 mxDocumentHandler
->startElement("text:p", xUnoAttrs
);
1545 xAttrs
->AddAttribute( "text:style-name", "svgtextstyle"+sStyleId
);
1546 mxDocumentHandler
->startElement("text:span", xUnoAttrs
);
1549 mxDocumentHandler
->characters(sText
.makeStringAndClear());
1550 mxDocumentHandler
->endElement("text:span");
1551 mxDocumentHandler
->endElement("text:p");
1552 mxDocumentHandler
->endElement("draw:text-box");
1553 mxDocumentHandler
->endElement("draw:frame");
1565 void writeBinaryData( rtl::Reference
<SvXMLAttributeList
>& xAttrs
,
1566 const uno::Reference
<xml::sax::XAttributeList
>& xUnoAttrs
,
1567 const uno::Reference
<xml::dom::XElement
>& /* xElem */,
1568 const basegfx::B2DRange
& rShapeBounds
,
1569 const std::string
& data
)
1572 xAttrs
->AddAttribute( "svg:x", OUString::valueOf(pt2mm(rShapeBounds
.getMinX()))+"mm");
1573 xAttrs
->AddAttribute( "svg:y", OUString::valueOf(pt2mm(rShapeBounds
.getMinY()))+"mm");
1574 xAttrs
->AddAttribute( "svg:width", OUString::valueOf(pt2mm(rShapeBounds
.getWidth()))+"mm");
1575 xAttrs
->AddAttribute( "svg:height", OUString::valueOf(pt2mm(rShapeBounds
.getHeight()))+"mm");
1577 mxDocumentHandler
->startElement("draw:frame", xUnoAttrs
);
1580 mxDocumentHandler
->startElement("draw:image", xUnoAttrs
);
1582 mxDocumentHandler
->startElement("office:binary-data", xUnoAttrs
);
1584 mxDocumentHandler
->characters(OUString::createFromAscii(data
.c_str()));
1586 mxDocumentHandler
->endElement("office:binary-data");
1588 mxDocumentHandler
->endElement("draw:image");
1590 mxDocumentHandler
->endElement("draw:frame");
1594 void writeTransformAttribute(const basegfx::B2DHomMatrix rMatrix
, rtl::Reference
<SvXMLAttributeList
>& xAttrs
)
1596 basegfx::B2DTuple rScale
, rTranslate
;
1597 double rRotate
, rShearX
;
1598 OUString sTransformValue
;
1599 if (!rMatrix
.decompose(rScale
, rTranslate
, rRotate
, rShearX
))
1601 if (rScale
.getX() != 1.0 || rScale
.getY() != 1.0)
1602 sTransformValue
+= "scale("+OUString::valueOf(rScale
.getX())+" "
1603 +OUString::valueOf(rScale
.getY())+") ";
1604 if (rTranslate
.getX() != 0.0f
|| rTranslate
.getY() != 0.0f
)
1605 sTransformValue
+= "translate("+OUString::valueOf(rTranslate
.getX()/100.0f
)+"mm "
1606 +OUString::valueOf(rTranslate
.getY()/100.0f
)+"mm) ";
1607 if (rRotate
!= 0.0f
)
1608 sTransformValue
+= "rotate("+OUString::valueOf(rRotate
)+") ";
1610 if (rShearX
!= 0.0f
)
1611 sTransformValue
+= "skewX("+OUString::valueOf(rShearX
)+") ";
1612 if (sTransformValue
.isEmpty())
1614 xAttrs
->AddAttribute( "draw:transform", sTransformValue
);
1617 void writeEllipseShape( rtl::Reference
<SvXMLAttributeList
>& xAttrs
,
1618 const uno::Reference
<xml::sax::XAttributeList
>& xUnoAttrs
,
1619 const uno::Reference
<xml::dom::XElement
>& xElem
,
1620 const OUString
& rStyleId
,
1621 const basegfx::B2DEllipse
& rEllipse
)
1623 State aState
= maCurrState
;
1627 basegfx::B2DPolygon aPoly
= basegfx::tools::createPolygonFromEllipse(rEllipse
.getB2DEllipseCenter(),
1628 rEllipse
.getB2DEllipseRadius().getX(), rEllipse
.getB2DEllipseRadius().getY());
1629 writePathShape(xAttrs
, xUnoAttrs
, xElem
, rStyleId
, basegfx::B2DPolyPolygon(aPoly
));
1633 void writePathShape( rtl::Reference
<SvXMLAttributeList
>& xAttrs
,
1634 const uno::Reference
<xml::sax::XAttributeList
>& xUnoAttrs
,
1635 const uno::Reference
<xml::dom::XElement
>& xElem
,
1636 const OUString
& rStyleId
,
1637 const basegfx::B2DPolyPolygon
& rPoly
)
1639 // we might need to split up polypolygon into multiple path
1640 // shapes (e.g. when emulating line stroking)
1641 std::vector
<basegfx::B2DPolyPolygon
> aPolys(1,rPoly
);
1642 State aState
= maCurrState
;
1643 OUString
aStyleId(rStyleId
);
1647 OSL_TRACE("writePath - the CTM is: %f %f %f %f %f %f",
1648 maCurrState
.maCTM
.get(0,0),
1649 maCurrState
.maCTM
.get(0,1),
1650 maCurrState
.maCTM
.get(0,2),
1651 maCurrState
.maCTM
.get(1,0),
1652 maCurrState
.maCTM
.get(1,1),
1653 maCurrState
.maCTM
.get(1,2));
1655 // TODO(F2): separate out shear, rotate etc.
1656 // apply transformation to polygon, to keep draw
1657 // import in 100th mm
1658 std::for_each(aPolys
.begin(),aPolys
.end(),
1659 boost::bind(&basegfx::B2DPolyPolygon::transform
,
1660 _1
,boost::cref(aState
.maCTM
)));
1662 for( sal_uInt32 i
=0; i
<aPolys
.size(); ++i
)
1664 const basegfx::B2DRange
aBounds(
1665 aPolys
[i
].areControlPointsUsed() ?
1666 basegfx::tools::getRange(
1667 basegfx::tools::adaptiveSubdivideByAngle(aPolys
[i
])) :
1668 basegfx::tools::getRange(aPolys
[i
]));
1669 fillShapeProperties(xAttrs
,
1672 "svggraphicstyle"+aStyleId
);
1674 // force path coordinates to 100th millimeter, after
1675 // putting polygon data at origin (ODF viewbox
1676 // calculations largely untested codepaths, as OOo always
1677 // writes "0 0 w h" viewboxes)
1678 basegfx::B2DHomMatrix aNormalize
;
1679 aNormalize
.translate(-aBounds
.getMinX(),-aBounds
.getMinY());
1680 aNormalize
.scale(2540.0/72.0,2540.0/72.0);
1681 aPolys
[i
].transform(aNormalize
);
1683 xAttrs
->AddAttribute( "svg:d", basegfx::tools::exportToSvgD(
1685 false, // no relative coords. causes rounding errors
1686 false )); // no quad bezier detection. crashes older versions.
1687 mxDocumentHandler
->startElement("draw:path", xUnoAttrs
);
1688 mxDocumentHandler
->endElement("draw:path");
1692 void fillShapeProperties( rtl::Reference
<SvXMLAttributeList
>& xAttrs
,
1693 const uno::Reference
<xml::dom::XElement
>& /* xElem */,
1694 const basegfx::B2DRange
& rShapeBounds
,
1695 const OUString
& rStyleName
)
1697 xAttrs
->AddAttribute( "draw:z-index", OUString::valueOf( mnShapeNum
++ ));
1698 xAttrs
->AddAttribute( "draw:style-name", rStyleName
);
1699 xAttrs
->AddAttribute( "svg:width", OUString::valueOf(pt2mm(rShapeBounds
.getWidth()))+"mm");
1700 xAttrs
->AddAttribute( "svg:height", OUString::valueOf(pt2mm(rShapeBounds
.getHeight()))+"mm");
1702 // OOo expects the viewbox to be in 100th of mm
1703 xAttrs
->AddAttribute( "svg:viewBox",
1705 + OUString::valueOf(
1706 basegfx::fround(pt100thmm(rShapeBounds
.getWidth())) )
1708 + OUString::valueOf(
1709 basegfx::fround(pt100thmm(rShapeBounds
.getHeight())) ));
1711 // TODO(F1): decompose transformation in calling code, and use
1712 // transform attribute here
1713 // writeTranslate(maCurrState.maCTM, xAttrs);
1714 xAttrs
->AddAttribute( "svg:x", OUString::valueOf(pt2mm(rShapeBounds
.getMinX()))+"mm");
1715 xAttrs
->AddAttribute( "svg:y", OUString::valueOf(pt2mm(rShapeBounds
.getMinY()))+"mm");
1719 StateMap
& mrStateMap
;
1720 uno::Reference
<xml::sax::XDocumentHandler
> mxDocumentHandler
;
1721 sal_Int32 mnShapeNum
;
1724 /// Write out shapes from DOM tree
1725 static void writeShapes( StatePool
& rStatePool
,
1726 StateMap
& rStateMap
,
1727 const uno::Reference
<xml::dom::XElement
> xElem
,
1728 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocHdl
)
1730 ShapeWritingVisitor
aVisitor(rStatePool
,rStateMap
,xDocHdl
);
1731 visitElements(aVisitor
, xElem
);
1736 struct OfficeStylesWritingVisitor
1738 OfficeStylesWritingVisitor( StateMap
& rStateMap
,
1739 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
) :
1740 mrStateMap(rStateMap
),
1741 mxDocumentHandler(xDocumentHandler
)
1743 void operator()( const uno::Reference
<xml::dom::XElement
>& /*xElem*/ )
1746 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
,
1747 const uno::Reference
<xml::dom::XNamedNodeMap
>& /*xAttributes*/ )
1749 rtl::Reference
<SvXMLAttributeList
> xAttrs( new SvXMLAttributeList() );
1750 uno::Reference
<xml::sax::XAttributeList
> xUnoAttrs( xAttrs
.get() );
1752 sal_Int32
nDummyIndex(0);
1754 xElem
->getAttribute("internal-style-ref").getToken(
1755 0,'$',nDummyIndex
));
1756 StateMap::iterator pOrigState
=mrStateMap
.find(
1757 sStyleId
.toInt32());
1759 if( pOrigState
== mrStateMap
.end() )
1760 return; // non-exportable element, e.g. linearGradient
1762 maCurrState
= pOrigState
->second
;
1764 if( maCurrState
.meStrokeType
== DASH
)
1766 sal_Int32 dots1
, dots2
;
1767 double dots1_length
, dots2_length
, dash_distance
;
1768 SvgDashArray2Odf( &dots1
, &dots1_length
, &dots2
, &dots2_length
, &dash_distance
);
1771 xAttrs
->AddAttribute( "draw:name", "dash"+sStyleId
);
1772 xAttrs
->AddAttribute( "draw:display-name", "dash"+sStyleId
);
1773 xAttrs
->AddAttribute( "draw:style", "rect" );
1775 xAttrs
->AddAttribute( "draw:dots1", OUString::valueOf(dots1
) );
1776 xAttrs
->AddAttribute( "draw:dots1-length", OUString::valueOf(pt2mm(convLength( OUString::valueOf(dots1_length
), maCurrState
, 'h' )))+"mm" );
1778 xAttrs
->AddAttribute( "draw:distance", OUString::valueOf(pt2mm(convLength( OUString::valueOf(dash_distance
), maCurrState
, 'h' )))+"mm" );
1780 xAttrs
->AddAttribute( "draw:dots2", OUString::valueOf(dots2
) );
1781 xAttrs
->AddAttribute( "draw:dots2-length", OUString::valueOf(pt2mm(convLength( OUString::valueOf(dots2_length
), maCurrState
, 'h' )))+"mm" );
1784 mxDocumentHandler
->startElement( "draw:stroke-dash", xUnoAttrs
);
1785 mxDocumentHandler
->endElement( "draw:stroke-dash" );
1789 void SvgDashArray2Odf( sal_Int32
*dots1
, double *dots1_length
, sal_Int32
*dots2
, double *dots2_length
, double *dash_distance
)
1797 if( maCurrState
.maDashArray
.size() == 0 ) {
1801 double effective_dasharray_size
= maCurrState
.maDashArray
.size();
1802 if( maCurrState
.maDashArray
.size() % 2 == 1 )
1803 effective_dasharray_size
= maCurrState
.maDashArray
.size()*2;
1805 *dash_distance
= maCurrState
.maDashArray
[1%maCurrState
.maDashArray
.size()];
1806 sal_Int32 dist_count
= 1;
1807 for( int i
=3; i
<effective_dasharray_size
; i
+=2 ) {
1808 *dash_distance
= ((dist_count
* *dash_distance
) + maCurrState
.maDashArray
[i
%maCurrState
.maDashArray
.size()])/(dist_count
+1);
1813 *dots1_length
= maCurrState
.maDashArray
[0];
1815 while( ( i
<effective_dasharray_size
) && ( maCurrState
.maDashArray
[i
%maCurrState
.maDashArray
.size()] == *dots1_length
) ) {
1819 if( i
<effective_dasharray_size
) {
1821 *dots2_length
= maCurrState
.maDashArray
[i
];
1823 while( ( i
<effective_dasharray_size
) && ( maCurrState
.maDashArray
[i
%maCurrState
.maDashArray
.size()] == *dots2_length
) ) {
1829 SAL_INFO("svg", "SvgDashArray2Odf " << *dash_distance
<< " " << *dots1
<< " " << *dots1_length
<< " " << *dots2
<< " " << *dots2_length
);
1838 StateMap
& mrStateMap
;
1839 uno::Reference
<xml::sax::XDocumentHandler
> mxDocumentHandler
;
1842 static void writeOfficeStyles( StateMap
& rStateMap
,
1843 const uno::Reference
<xml::dom::XElement
> xElem
,
1844 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocHdl
)
1846 OfficeStylesWritingVisitor
aVisitor( rStateMap
, xDocHdl
);
1847 visitElements( aVisitor
, xElem
);
1850 #if OSL_DEBUG_LEVEL > 2
1851 struct DumpingVisitor
1853 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
)
1855 OSL_TRACE("name: %s",
1857 xElem
->getTagName(),
1858 RTL_TEXTENCODING_UTF8
).getStr());
1861 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
,
1862 const uno::Reference
<xml::dom::XNamedNodeMap
>& xAttributes
)
1864 OSL_TRACE("name: %s",
1866 xElem
->getTagName(),
1867 RTL_TEXTENCODING_UTF8
).getStr());
1868 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1869 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1873 xAttributes
->item(i
)->getNodeName(),
1874 RTL_TEXTENCODING_UTF8
).getStr(),
1876 xAttributes
->item(i
)->getNodeValue(),
1877 RTL_TEXTENCODING_UTF8
).getStr());
1885 static void dumpTree( const uno::Reference
<xml::dom::XElement
> xElem
)
1887 DumpingVisitor aVisitor
;
1888 visitElements(aVisitor
, xElem
);
1893 SVGReader::SVGReader(const uno::Reference
<lang::XMultiServiceFactory
>& xServiceFactory
,
1894 const uno::Reference
<io::XInputStream
>& xInputStream
,
1895 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
) :
1896 m_xServiceFactory( xServiceFactory
),
1897 m_xInputStream( xInputStream
),
1898 m_xDocumentHandler( xDocumentHandler
)
1902 sal_Bool
SVGReader::parseAndConvert()
1904 uno::Reference
<xml::dom::XDocumentBuilder
> xDomBuilder(xml::dom::DocumentBuilder::create(comphelper::getComponentContext(m_xServiceFactory
)));
1906 uno::Reference
<xml::dom::XDocument
> xDom(
1907 xDomBuilder
->parse(m_xInputStream
),
1908 uno::UNO_QUERY_THROW
);
1910 uno::Reference
<xml::dom::XElement
> xDocElem( xDom
->getDocumentElement(),
1911 uno::UNO_QUERY_THROW
);
1913 // the root state for svg document
1914 State aInitialState
;
1916 /////////////////////////////////////////////////////////////////
1918 /////////////////////////////////////////////////////////////////
1920 m_xDocumentHandler
->startDocument();
1922 // get the document dimensions
1924 // if the "width" and "height" attributes are missing, inkscape fakes
1925 // A4 portrait for. Let's do the same.
1926 if (!xDocElem
->hasAttribute("width"))
1927 xDocElem
->setAttribute("width", "210mm");
1928 if (!xDocElem
->hasAttribute("height"))
1929 xDocElem
->setAttribute("height", "297mm");
1931 double fViewPortWidth( pt2mm(convLength(xDocElem
->getAttribute("width"),aInitialState
,'h')) );
1932 double fViewPortHeight( pt2mm(convLength(xDocElem
->getAttribute("height"),aInitialState
,'v')) );
1935 rtl::Reference
<SvXMLAttributeList
> xAttrs( new SvXMLAttributeList() );
1936 uno::Reference
<xml::sax::XAttributeList
> xUnoAttrs( xAttrs
.get() );
1938 xAttrs
->AddAttribute( "xmlns:office", OASIS_STR
"office:1.0" );
1939 xAttrs
->AddAttribute( "xmlns:style", OASIS_STR
"style:1.0" );
1940 xAttrs
->AddAttribute( "xmlns:text", OASIS_STR
"text:1.0" );
1941 xAttrs
->AddAttribute( "xmlns:svg", OASIS_STR
"svg-compatible:1.0" );
1942 xAttrs
->AddAttribute( "xmlns:table", OASIS_STR
"table:1.0" );
1943 xAttrs
->AddAttribute( "xmlns:draw", OASIS_STR
"drawing:1.0" );
1944 xAttrs
->AddAttribute( "xmlns:fo", OASIS_STR
"xsl-fo-compatible:1.0" );
1945 xAttrs
->AddAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink");
1946 xAttrs
->AddAttribute( "xmlns:dc", "http://purl.org/dc/elements/1.1/");
1947 xAttrs
->AddAttribute( "xmlns:number", OASIS_STR
"datastyle:1.0" );
1948 xAttrs
->AddAttribute( "xmlns:presentation", OASIS_STR
"presentation:1.0" );
1949 xAttrs
->AddAttribute( "xmlns:math", "http://www.w3.org/1998/Math/MathML");
1950 xAttrs
->AddAttribute( "xmlns:form", OASIS_STR
"form:1.0" );
1951 xAttrs
->AddAttribute( "xmlns:script", OASIS_STR
"script:1.0" );
1952 xAttrs
->AddAttribute( "xmlns:dom", "http://www.w3.org/2001/xml-events");
1953 xAttrs
->AddAttribute( "xmlns:xforms", "http://www.w3.org/2002/xforms");
1954 xAttrs
->AddAttribute( "xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
1955 xAttrs
->AddAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
1956 xAttrs
->AddAttribute( "office:version", "1.0");
1957 xAttrs
->AddAttribute( "office:mimetype", "application/vnd.oasis.opendocument.graphics");
1959 m_xDocumentHandler
->startElement( "office:document", xUnoAttrs
);
1963 m_xDocumentHandler
->startElement( "office:settings", xUnoAttrs
);
1965 xAttrs
->AddAttribute( "config:name", "ooo:view-settings");
1966 m_xDocumentHandler
->startElement( "config:config-item-set", xUnoAttrs
);
1970 xAttrs
->AddAttribute( "config:name", "VisibleAreaTop");
1971 xAttrs
->AddAttribute( "config:type", "int");
1972 m_xDocumentHandler
->startElement( "config:config-item", xUnoAttrs
);
1974 m_xDocumentHandler
->characters( "0" );
1976 m_xDocumentHandler
->endElement( "config:config-item" );
1980 xAttrs
->AddAttribute( "config:name", "VisibleAreaLeft" );
1981 xAttrs
->AddAttribute( "config:type", "int" );
1982 m_xDocumentHandler
->startElement( "config:config-item" , xUnoAttrs
);
1984 m_xDocumentHandler
->characters( "0" );
1986 m_xDocumentHandler
->endElement( "config:config-item" );
1990 xAttrs
->AddAttribute( "config:name" , "VisibleAreaWidth" );
1991 xAttrs
->AddAttribute( "config:type" , "int" );
1992 m_xDocumentHandler
->startElement( "config:config-item" , xUnoAttrs
);
1994 sal_Int64 iWidth
= sal_Int64(fViewPortWidth
);
1995 m_xDocumentHandler
->characters( OUString::valueOf(iWidth
) );
1997 m_xDocumentHandler
->endElement( "config:config-item" );
2001 xAttrs
->AddAttribute( "config:name", "VisibleAreaHeight" );
2002 xAttrs
->AddAttribute( "config:type", "int" );
2003 m_xDocumentHandler
->startElement( "config:config-item", xUnoAttrs
);
2005 sal_Int64 iHeight
= sal_Int64(fViewPortHeight
);
2006 m_xDocumentHandler
->characters( OUString::valueOf(iHeight
) );
2008 m_xDocumentHandler
->endElement( "config:config-item" );
2010 m_xDocumentHandler
->endElement( "config:config-item-set" );
2012 m_xDocumentHandler
->endElement( "office:settings" );
2016 m_xDocumentHandler
->startElement( "office:automatic-styles",
2019 xAttrs
->AddAttribute( "style:name", "pagelayout1");
2020 m_xDocumentHandler
->startElement( "style:page-layout", xUnoAttrs
);
2021 // TODO(Q3): this is super-ugly. In-place container come to mind.
2024 // make page viewport-width times viewport-height mm large - add
2025 // 5% border at every side
2026 xAttrs
->AddAttribute( "fo:margin-top", "0mm");
2027 xAttrs
->AddAttribute( "fo:margin-bottom", "0mm");
2028 xAttrs
->AddAttribute( "fo:margin-left", "0mm");
2029 xAttrs
->AddAttribute( "fo:margin-right", "0mm");
2030 xAttrs
->AddAttribute( "fo:page-width", OUString::valueOf(fViewPortWidth
)+"mm");
2031 xAttrs
->AddAttribute( "fo:page-height", OUString::valueOf(fViewPortHeight
)+"mm");
2032 xAttrs
->AddAttribute( "style:print-orientation",
2033 fViewPortWidth
> fViewPortHeight
? OUString("landscape") : OUString("portrait") );
2034 m_xDocumentHandler
->startElement( "style:page-layout-properties", xUnoAttrs
);
2035 m_xDocumentHandler
->endElement( "style:page-layout-properties" );
2036 m_xDocumentHandler
->endElement( "style:page-layout" );
2039 xAttrs
->AddAttribute( "style:name", "pagestyle1" );
2040 xAttrs
->AddAttribute( "style:family", "drawing-page" );
2041 m_xDocumentHandler
->startElement( "style:style", xUnoAttrs
);
2044 xAttrs
->AddAttribute( "draw:background-size", "border");
2045 xAttrs
->AddAttribute( "draw:fill", "none");
2046 m_xDocumentHandler
->startElement( "style:drawing-page-properties", xUnoAttrs
);
2047 m_xDocumentHandler
->endElement( "style:drawing-page-properties" );
2048 m_xDocumentHandler
->endElement( "style:style" );
2050 StatePool aStatePool
;
2052 annotateStyles(aStatePool
,aStateMap
,aInitialState
,
2053 xDocElem
,m_xDocumentHandler
);
2055 #if OSL_DEBUG_LEVEL > 2
2059 m_xDocumentHandler
->endElement( "office:automatic-styles" );
2061 ////////////////////////////////////////////////////////////////////
2064 m_xDocumentHandler
->startElement( "office:styles", xUnoAttrs
);
2065 writeOfficeStyles( aStateMap
,
2067 m_xDocumentHandler
);
2068 m_xDocumentHandler
->endElement( "office:styles" );
2070 ////////////////////////////////////////////////////////////////////
2072 m_xDocumentHandler
->startElement( "office:master-styles", xUnoAttrs
);
2074 xAttrs
->AddAttribute( "style:name", "Default");
2075 xAttrs
->AddAttribute( "style:page-layout-name", "pagelayout1");
2076 xAttrs
->AddAttribute( "draw:style-name", "pagestyle1");
2077 m_xDocumentHandler
->startElement( "style:master-page", xUnoAttrs
);
2078 m_xDocumentHandler
->endElement( "style:master-page" );
2080 m_xDocumentHandler
->endElement( "office:master-styles" );
2082 ////////////////////////////////////////////////////////////////////
2085 m_xDocumentHandler
->startElement( "office:body", xUnoAttrs
);
2086 m_xDocumentHandler
->startElement( "office:drawing", xUnoAttrs
);
2089 xAttrs
->AddAttribute( "draw:master-page-name", "Default");
2090 xAttrs
->AddAttribute( "draw:style-name", "pagestyle1");
2091 m_xDocumentHandler
->startElement("draw:page", xUnoAttrs
);
2093 // write out all shapes
2094 writeShapes(aStatePool
,
2097 m_xDocumentHandler
);
2099 m_xDocumentHandler
->endElement( "draw:page" );
2100 m_xDocumentHandler
->endElement( "office:drawing" );
2101 m_xDocumentHandler
->endElement( "office:body" );
2102 m_xDocumentHandler
->endElement( "office:document" );
2103 m_xDocumentHandler
->endDocument();
2110 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */