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>
49 #define OASIS_STR "urn:oasis:names:tc:opendocument:xmlns:"
51 using namespace ::com::sun::star
;
55 enum SvgiVisitorCaller
{STYLE_ANNOTATOR
, SHAPE_WRITER
, STYLE_WRITER
};
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
>& rElem
,
63 xml::dom::NodeType eChildType
)
65 uno::Reference
<xml::dom::XNodeList
> xChildren( rElem
->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
>& rElem
,
82 SvgiVisitorCaller eCaller
)
84 if( rElem
->hasAttributes() )
85 rFunc(rElem
, rElem
->getAttributes());
89 // notify children processing
92 // recurse over children
93 if (eCaller
== SHAPE_WRITER
&& rElem
->getTagName() == "defs") {
96 uno::Reference
<xml::dom::XNodeList
> xChildren( rElem
->getChildNodes() );
97 const sal_Int32
nNumNodes( xChildren
->getLength() );
98 for( sal_Int32 i
=0; i
<nNumNodes
; ++i
)
100 if( xChildren
->item(i
)->getNodeType() == xml::dom::NodeType_ELEMENT_NODE
)
101 visitElements( rFunc
,
102 uno::Reference
<xml::dom::XElement
>(
104 uno::UNO_QUERY_THROW
),
108 // children processing done
112 template<typename value_type
> value_type
square(value_type v
)
117 double colorDiffSquared(const ARGBColor
& rCol1
, const ARGBColor
& rCol2
)
120 square(rCol1
.a
-rCol2
.a
)
121 + square(rCol1
.r
-rCol2
.r
)
122 + square(rCol1
.g
-rCol2
.g
)
123 + square(rCol1
.b
-rCol2
.b
);
126 typedef std::map
<OUString
,sal_Size
> ElementRefMapType
;
128 struct AnnotatingVisitor
130 AnnotatingVisitor(StatePool
& rStatePool
,
132 const State
& rInitialState
,
133 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
) :
137 mrStates(rStatePool
),
138 mrStateMap(rStateMap
),
139 mxDocumentHandler(xDocumentHandler
),
141 maGradientStopVector()
143 maParentStates
.push_back(rInitialState
);
146 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
)
148 const sal_Int32
nTagId(getTokenId(xElem
->getTagName()));
149 if (nTagId
!= XML_TEXT
)
152 maCurrState
= maParentStates
.back();
153 maCurrState
.maTransform
.identity();
154 maCurrState
.maViewBox
.reset();
155 // if necessary, serialize to automatic-style section
156 writeStyle(xElem
,nTagId
);
159 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
,
160 const uno::Reference
<xml::dom::XNamedNodeMap
>& xAttributes
)
162 const sal_Int32
nTagId(getTokenId(xElem
->getTagName()));
165 case XML_LINEARGRADIENT
:
167 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
168 maGradientVector
.push_back(Gradient(Gradient::LINEAR
));
170 // do we have a reference to a parent gradient? parse
171 // that first, as it sets our defaults here (manually
172 // tracking default state on each Gradient variable is
173 // much more overhead)
174 uno::Reference
<xml::dom::XNode
> xNode(xAttributes
->getNamedItem("href"));
177 const OUString
sValue(xNode
->getNodeValue());
178 ElementRefMapType::iterator aFound
=maGradientIdMap
.end();
179 if ( sValue
.copy(0,1) == "#" )
180 aFound
= maGradientIdMap
.find(sValue
.copy(1));
182 aFound
= maGradientIdMap
.find(sValue
);
184 if( aFound
!= maGradientIdMap
.end() )
185 maGradientVector
.back() = maGradientVector
[aFound
->second
];
188 // do that after dereferencing, to prevent hyperlinked
189 // gradient to clobber our Id again
190 maGradientVector
.back().mnId
= maGradientVector
.size()-1;
191 maGradientVector
.back().meType
= Gradient::LINEAR
; // has been clobbered as well
193 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
195 parseLinearGradientData( maGradientVector
.back(),
196 maGradientVector
.size()-1,
197 getTokenId(xAttributes
->item(i
)->getNodeName()),
198 xAttributes
->item(i
)->getNodeValue() );
202 case XML_RADIALGRADIENT
:
204 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
205 maGradientVector
.push_back(Gradient(Gradient::RADIAL
));
207 // do we have a reference to a parent gradient? parse
208 // that first, as it sets our defaults here (manually
209 // tracking default state on each Gradient variable is
210 // much more overhead)
211 uno::Reference
<xml::dom::XNode
> xNode(xAttributes
->getNamedItem("href"));
214 const OUString
sValue(xNode
->getNodeValue());
215 ElementRefMapType::iterator aFound
=maGradientIdMap
.end();
216 if ( sValue
.copy(0,1) == "#" )
217 aFound
= maGradientIdMap
.find(sValue
.copy(1));
219 aFound
= maGradientIdMap
.find(sValue
);
221 if( aFound
!= maGradientIdMap
.end() )
222 maGradientVector
.back() = maGradientVector
[aFound
->second
];
225 // do that after dereferencing, to prevent hyperlinked
226 // gradient to clobber our Id again
227 maGradientVector
.back().mnId
= maGradientVector
.size()-1;
228 maGradientVector
.back().meType
= Gradient::RADIAL
; // has been clobbered as well
230 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
232 parseRadialGradientData( maGradientVector
.back(),
233 maGradientVector
.size()-1,
234 getTokenId(xAttributes
->item(i
)->getNodeName()),
235 xAttributes
->item(i
)->getNodeValue() );
241 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
242 maGradientStopVector
.push_back(GradientStop());
243 maGradientVector
.back().maStops
.push_back(maGradientStopVector
.size()-1);
244 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
246 parseGradientStop( maGradientStopVector
.back(),
247 maGradientStopVector
.size()-1,
248 getTokenId(xAttributes
->item(i
)->getNodeName()),
249 xAttributes
->item(i
)->getNodeValue() );
255 // init state. inherit defaults from parent.
256 maCurrState
= maParentStates
.back();
257 maCurrState
.maTransform
.identity();
258 maCurrState
.maViewBox
.reset();
260 // scan for style info
261 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
262 OUString sAttributeValue
;
263 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
265 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
266 const sal_Int32
nTokenId(
267 getTokenId(xAttributes
->item(i
)->getNodeName()));
268 if( XML_STYLE
== nTokenId
)
269 parseStyle(sAttributeValue
);
271 parseAttribute(nTokenId
,
275 // all attributes parsed, can calc total CTM now
276 basegfx::B2DHomMatrix aLocalTransform
;
277 if( !maCurrState
.maViewBox
.isEmpty() &&
278 maCurrState
.maViewBox
.getWidth() != 0.0 &&
279 maCurrState
.maViewBox
.getHeight() != 0.0 )
281 // transform aViewBox into viewport, keep aspect ratio
282 aLocalTransform
.translate(-maCurrState
.maViewBox
.getMinX(),
283 -maCurrState
.maViewBox
.getMinY());
284 double scaleW
= maCurrState
.maViewport
.getWidth()/maCurrState
.maViewBox
.getWidth();
285 double scaleH
= maCurrState
.maViewport
.getHeight()/maCurrState
.maViewBox
.getHeight();
286 double scale
= (scaleW
< scaleH
) ? scaleW
: scaleH
;
287 aLocalTransform
.scale(scale
,scale
);
289 maCurrState
.maCTM
= maCurrState
.maCTM
*maCurrState
.maTransform
*aLocalTransform
;
291 OSL_TRACE("annotateStyle - CTM is: %f %f %f %f %f %f",
292 maCurrState
.maCTM
.get(0,0),
293 maCurrState
.maCTM
.get(0,1),
294 maCurrState
.maCTM
.get(0,2),
295 maCurrState
.maCTM
.get(1,0),
296 maCurrState
.maCTM
.get(1,1),
297 maCurrState
.maCTM
.get(1,2));
299 // if necessary, serialize to automatic-style section
300 writeStyle(xElem
,nTagId
);
305 static OUString
getStyleName( const char* sPrefix
, sal_Int32 nId
)
307 return OUString::createFromAscii(sPrefix
)+OUString::number(nId
);
310 bool hasGradientOpacity( const Gradient
& rGradient
)
313 (rGradient
.maStops
.size() > 1) &&
314 (maGradientStopVector
[
315 rGradient
.maStops
[0]].maStopColor
.a
!= 1.0 ||
316 maGradientStopVector
[
317 rGradient
.maStops
[1]].maStopColor
.a
!= 1.0);
322 explicit StopSorter( const std::vector
< GradientStop
>& rStopVec
) :
326 bool operator()( sal_Size rLHS
, sal_Size rRHS
)
328 return mrStopVec
[rLHS
].mnStopPosition
< mrStopVec
[rRHS
].mnStopPosition
;
331 const std::vector
< GradientStop
>& mrStopVec
;
334 void optimizeGradientStops( Gradient
& rGradient
)
336 // sort for increasing stop position
337 std::sort(rGradient
.maStops
.begin(),rGradient
.maStops
.end(),
338 StopSorter(maGradientStopVector
));
340 if( rGradient
.maStops
.size() < 3 )
343 // join similar colors
344 std::vector
<sal_Size
> aNewStops(1,rGradient
.maStops
.front());
345 for( sal_Size i
=1; i
<rGradient
.maStops
.size(); ++i
)
347 if( maGradientStopVector
[rGradient
.maStops
[i
]].maStopColor
!=
348 maGradientStopVector
[aNewStops
.back()].maStopColor
)
349 aNewStops
.push_back(rGradient
.maStops
[i
]);
352 rGradient
.maStops
= aNewStops
;
353 if (rGradient
.maStops
.size() < 2)
355 return; // can't optimize further...
358 // axial gradient, maybe?
359 if( rGradient
.meType
== Gradient::LINEAR
&&
360 rGradient
.maStops
.size() == 3 &&
361 maGradientStopVector
[rGradient
.maStops
.front()].maStopColor
==
362 maGradientStopVector
[rGradient
.maStops
.back()].maStopColor
)
364 // yep - keep it at that
368 // find out most significant color difference, and limit to
369 // those two stops around this border (metric is
370 // super-simplistic: take euclidean distance of colors, weigh
371 // with stop distance)
372 sal_Size nMaxIndex
=0;
373 double fMaxDistance
=0.0;
374 for( sal_Size i
=1; i
<rGradient
.maStops
.size(); ++i
)
376 const double fCurrDistance(
378 maGradientStopVector
[rGradient
.maStops
[i
-1]].maStopColor
,
379 maGradientStopVector
[rGradient
.maStops
[i
]].maStopColor
) *
380 (square(maGradientStopVector
[rGradient
.maStops
[i
-1]].mnStopPosition
) +
381 square(maGradientStopVector
[rGradient
.maStops
[i
]].mnStopPosition
)) );
383 if( fCurrDistance
> fMaxDistance
)
386 fMaxDistance
= fCurrDistance
;
389 rGradient
.maStops
[0] = rGradient
.maStops
[nMaxIndex
];
390 rGradient
.maStops
[1] = rGradient
.maStops
[nMaxIndex
+1];
391 rGradient
.maStops
.erase(rGradient
.maStops
.begin()+2,rGradient
.maStops
.end());
394 static sal_Int8
toByteColor( double val
)
396 // TODO(Q3): duplicated from vcl::unotools
397 return sal::static_int_cast
<sal_Int8
>(
398 basegfx::fround(val
*255.0));
401 static OUString
getOdfColor( const ARGBColor
& rColor
)
403 // TODO(Q3): duplicated from pdfimport
404 OUStringBuffer
aBuf( 7 );
405 const sal_uInt8
nRed ( toByteColor(rColor
.r
) );
406 const sal_uInt8
nGreen( toByteColor(rColor
.g
) );
407 const sal_uInt8
nBlue ( toByteColor(rColor
.b
) );
411 aBuf
.append( sal_Int32(nRed
), 16 );
414 aBuf
.append( sal_Int32(nGreen
), 16 );
417 aBuf
.append( sal_Int32(nBlue
), 16 );
419 // TODO(F3): respect alpha transparency (polygons etc.)
420 OSL_ASSERT(rColor
.a
== 1.0);
422 return aBuf
.makeStringAndClear();
425 static OUString
getOdfAlign( TextAlign eAlign
)
427 static const char aStart
[] = "start";
428 static const char aEnd
[] = "end";
429 static const char aCenter
[] = "center";
434 return OUString(aStart
);
436 return OUString(aCenter
);
438 return OUString(aEnd
);
442 bool writeStyle(State
& rState
, const sal_Int32 nTagId
)
444 rtl::Reference
<SvXMLAttributeList
> xAttrs( new SvXMLAttributeList() );
445 uno::Reference
<xml::sax::XAttributeList
> xUnoAttrs( xAttrs
.get() );
447 if (XML_TEXT
== nTagId
) {
448 rState
.mbIsText
= true;
449 basegfx::B2DTuple aScale
, aTranslate
;
450 double fRotate
, fShearX
;
451 if (rState
.maCTM
.decompose(aScale
, aTranslate
, fRotate
, fShearX
))
453 rState
.mnFontSize
*= aScale
.getX();
457 std::pair
<StatePool::iterator
,
458 bool> aRes
= mrStates
.insert(rState
);
459 SAL_INFO ("svg", "size " << mrStates
.size() << " id " << const_cast<State
&>(*aRes
.first
).mnStyleId
);
462 return false; // not written
466 // mnStyleId does not take part in hashing/comparison
467 const_cast<State
&>(*aRes
.first
).mnStyleId
= mnCurrStateId
;
468 SAL_INFO ("svg", " --> " << const_cast<State
&>(*aRes
.first
).mnStyleId
);
470 mrStateMap
.insert(std::make_pair(
474 // find two representative stop colors (as ODF only support
476 optimizeGradientStops(rState
.maFillGradient
);
478 if( !mxDocumentHandler
.is() )
479 return true; // cannot write style, svm import case
481 // do we have a gradient fill? then write out gradient as well
482 if( rState
.meFillType
== GRADIENT
&& rState
.maFillGradient
.maStops
.size() > 1 )
484 // TODO(F3): ODF12 supposedly also groks svg:linear/radialGradient. But CL says: nope.
485 xAttrs
->AddAttribute( "draw:name", getStyleName("svggradient", rState
.maFillGradient
.mnId
) );
486 if( rState
.maFillGradient
.meType
== Gradient::LINEAR
)
488 // should the optimizeGradientStops method decide that
489 // this is a three-color gradient, it prolly wanted us
490 // to take axial instead
491 xAttrs
->AddAttribute( "draw:style",
492 rState
.maFillGradient
.maStops
.size() == 3 ?
494 OUString("linear") );
498 xAttrs
->AddAttribute( "draw:style", "ellipsoid" );
499 xAttrs
->AddAttribute( "draw:cx", "50%" );
500 xAttrs
->AddAttribute( "draw:cy", "50%" );
503 basegfx::B2DTuple rScale
, rTranslate
;
504 double rRotate
, rShearX
;
505 if( rState
.maFillGradient
.maTransform
.decompose(rScale
, rTranslate
, rRotate
, rShearX
) )
506 xAttrs
->AddAttribute( "draw:angle",
507 OUString::number(rRotate
*1800.0/M_PI
) );
508 xAttrs
->AddAttribute( "draw:start-color",
510 maGradientStopVector
[
511 rState
.maFillGradient
.maStops
[0]].maStopColor
) );
512 xAttrs
->AddAttribute( "draw:end-color",
514 maGradientStopVector
[
515 rState
.maFillGradient
.maStops
[1]].maStopColor
) );
516 xAttrs
->AddAttribute( "draw:border", "0%" );
517 mxDocumentHandler
->startElement( "draw:gradient", xUnoAttrs
);
518 mxDocumentHandler
->endElement( "draw:gradient" );
520 if( hasGradientOpacity(rState
.maFillGradient
) )
522 // need to write out opacity style as well
524 xAttrs
->AddAttribute( "draw:name", getStyleName("svgopacity", rState
.maFillGradient
.mnId
) );
525 if( rState
.maFillGradient
.meType
== Gradient::LINEAR
)
527 xAttrs
->AddAttribute( "draw:style", "linear" );
531 xAttrs
->AddAttribute( "draw:style", "ellipsoid" );
532 xAttrs
->AddAttribute( "draw:cx", "50%" );
533 xAttrs
->AddAttribute( "draw:cy", "50%" );
536 // modulate gradient opacity with overall fill opacity
537 xAttrs
->AddAttribute( "draw:end",
539 maGradientStopVector
[
540 rState
.maFillGradient
.maStops
[0]].maStopColor
.a
*
541 maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
*100.0)+"%" );
542 xAttrs
->AddAttribute( "draw:start",
544 maGradientStopVector
[
545 rState
.maFillGradient
.maStops
[1]].maStopColor
.a
*
546 maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
*100.0)+"%" );
547 xAttrs
->AddAttribute( "draw:border", "0%" );
548 mxDocumentHandler
->startElement( "draw:opacity", xUnoAttrs
);
549 mxDocumentHandler
->endElement( "draw:opacity" );
553 // serialize to automatic-style section
554 if( nTagId
== XML_TEXT
)
556 // write paragraph style attributes
559 xAttrs
->AddAttribute( "style:name", getStyleName("svgparagraphstyle", mnCurrStateId
) );
560 xAttrs
->AddAttribute( "style:family", "paragraph" );
561 mxDocumentHandler
->startElement( "style:style", xUnoAttrs
);
564 xAttrs
->AddAttribute( "fo:text-align", getOdfAlign(rState
.meTextAnchor
));
566 mxDocumentHandler
->startElement( "style:paragraph-properties", xUnoAttrs
);
567 mxDocumentHandler
->endElement( "style:paragraph-properties" );
568 mxDocumentHandler
->endElement( "style:style" );
570 // write text style attributes
573 xAttrs
->AddAttribute( "style:name", getStyleName("svgtextstyle", mnCurrStateId
) );
574 xAttrs
->AddAttribute( "style:family", "text" );
575 mxDocumentHandler
->startElement( "style:style", xUnoAttrs
);
577 xAttrs
->AddAttribute( "fo:font-family", rState
.maFontFamily
);
578 xAttrs
->AddAttribute( "fo:font-size",
579 OUString::number(pt2mm(rState
.mnFontSize
))+"mm");
580 xAttrs
->AddAttribute( "fo:font-style", rState
.maFontStyle
);
581 xAttrs
->AddAttribute( "fo:font-variant", rState
.maFontVariant
);
582 xAttrs
->AddAttribute( "fo:font-weight",
583 OUString::number(rState
.mnFontWeight
));
584 xAttrs
->AddAttribute( "fo:color", getOdfColor(rState
.maFillColor
));
586 mxDocumentHandler
->startElement( "style:text-properties", xUnoAttrs
);
587 mxDocumentHandler
->endElement( "style:text-properties" );
588 mxDocumentHandler
->endElement( "style:style" );
592 xAttrs
->AddAttribute( "style:name" , getStyleName("svggraphicstyle", mnCurrStateId
) );
593 xAttrs
->AddAttribute( "style:family", "graphic" );
594 mxDocumentHandler
->startElement( "style:style", xUnoAttrs
);
597 // text or shape? if the former, no use in processing any
598 // graphic attributes except stroke color, ODF can do ~nothing
600 if( nTagId
== XML_TEXT
)
602 //xAttrs->AddAttribute( "draw:auto-grow-height", "true");
603 xAttrs
->AddAttribute( "draw:auto-grow-width", "true");
604 xAttrs
->AddAttribute( "draw:textarea-horizontal-align", "left");
605 //xAttrs->AddAttribute( "draw:textarea-vertical-align", "top");
606 xAttrs
->AddAttribute( "fo:min-height", "0cm");
608 xAttrs
->AddAttribute( "fo:padding-top", "0cm");
609 xAttrs
->AddAttribute( "fo:padding-left", "0cm");
610 xAttrs
->AddAttribute( "fo:padding-right", "0cm");
611 xAttrs
->AddAttribute( "fo:padding-bottom", "0cm");
613 // disable any background shape
614 xAttrs
->AddAttribute( "draw:stroke", "none");
615 xAttrs
->AddAttribute( "draw:fill", "none");
619 if( rState
.meFillType
!= NONE
)
621 if( rState
.meFillType
== GRADIENT
)
623 xAttrs
->AddAttribute( "draw:fill", "gradient");
624 xAttrs
->AddAttribute( "draw:fill-gradient-name",
625 getStyleName("svggradient", rState
.maFillGradient
.mnId
) );
626 if( hasGradientOpacity(rState
.maFillGradient
) )
628 // needs transparency gradient as well
629 xAttrs
->AddAttribute( "draw:opacity-name",
630 getStyleName("svgopacity", rState
.maFillGradient
.mnId
) );
632 else if( maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
!= 1.0 )
633 xAttrs
->AddAttribute( "draw:opacity",
634 OUString::number(100.0*maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
)+"%" );
638 xAttrs
->AddAttribute( "draw:fill", "solid");
639 xAttrs
->AddAttribute( "draw:fill-color", getOdfColor(rState
.maFillColor
));
640 if( maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
!= 1.0 )
641 xAttrs
->AddAttribute( "draw:opacity",
642 OUString::number(100.0*maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
)+"%" );
646 xAttrs
->AddAttribute( "draw:fill", "none");
648 if( rState
.meStrokeType
== SOLID
)
650 xAttrs
->AddAttribute( "draw:stroke", "solid");
651 xAttrs
->AddAttribute( "svg:stroke-color", getOdfColor(rState
.maStrokeColor
));
653 else if( rState
.meStrokeType
== DASH
)
655 xAttrs
->AddAttribute( "draw:stroke", "dash");
656 xAttrs
->AddAttribute( "draw:stroke-dash", "dash"+OUString::number(mnCurrStateId
));
657 xAttrs
->AddAttribute( "svg:stroke-color", getOdfColor(rState
.maStrokeColor
));
660 xAttrs
->AddAttribute( "draw:stroke", "none");
662 if( maCurrState
.mnStrokeWidth
!= 0.0 )
664 ::basegfx::B2DVector
aVec(maCurrState
.mnStrokeWidth
,0);
665 aVec
*= maCurrState
.maCTM
;
666 xAttrs
->AddAttribute( "svg:stroke-width", OUString::number( pt2mm(aVec
.getLength()) )+"mm");
668 if( maCurrState
.meLineJoin
== basegfx::B2DLINEJOIN_MITER
)
669 xAttrs
->AddAttribute( "draw:stroke-linejoin", "miter");
670 else if( maCurrState
.meLineJoin
== basegfx::B2DLINEJOIN_ROUND
)
671 xAttrs
->AddAttribute( "draw:stroke-linejoin", "round");
672 else if( maCurrState
.meLineJoin
== basegfx::B2DLINEJOIN_BEVEL
)
673 xAttrs
->AddAttribute( "draw:stroke-linejoin", "bevel");
674 if( maCurrState
.mnStrokeOpacity
*maCurrState
.mnOpacity
!= 1.0 )
675 xAttrs
->AddAttribute( "svg:stroke-opacity",
676 OUString::number(100.0*maCurrState
.mnStrokeOpacity
*maCurrState
.mnOpacity
)+"%");
679 mxDocumentHandler
->startElement( "style:graphic-properties", xUnoAttrs
);
680 mxDocumentHandler
->endElement( "style:graphic-properties" );
681 mxDocumentHandler
->endElement( "style:style" );
683 return true; // newly written
686 void writeStyle(const uno::Reference
<xml::dom::XElement
>& xElem
, const sal_Int32 nTagId
)
688 SAL_INFO ("svg", "writeStyle xElem " << xElem
->getTagName());
690 sal_Int32 nStyleId
=0;
691 if( writeStyle(maCurrState
, nTagId
) )
692 nStyleId
= mnCurrStateId
;
694 nStyleId
= mrStates
.find(maCurrState
)->mnStyleId
;
696 xElem
->setAttribute("internal-style-ref",
704 maParentStates
.push_back(maCurrState
);
709 maParentStates
.pop_back();
712 void parseLinearGradientData( Gradient
& io_rCurrGradient
,
713 const sal_Int32 nGradientNumber
,
714 const sal_Int32 nTokenId
,
715 const OUString
& sValue
)
719 case XML_GRADIENTTRANSFORM
:
721 OString
aValueUtf8( sValue
.getStr(),
723 RTL_TEXTENCODING_UTF8
);
724 parseTransform(aValueUtf8
.getStr(),io_rCurrGradient
.maTransform
);
728 io_rCurrGradient
.maCoords
.linear
.mfX1
= convLength(sValue
,maCurrState
,'h');
731 io_rCurrGradient
.maCoords
.linear
.mfX2
= convLength(sValue
,maCurrState
,'h');
734 io_rCurrGradient
.maCoords
.linear
.mfY1
= convLength(sValue
,maCurrState
,'v');
737 io_rCurrGradient
.maCoords
.linear
.mfY2
= convLength(sValue
,maCurrState
,'v');
740 maGradientIdMap
.insert(std::make_pair(sValue
,nGradientNumber
));
742 case XML_GRADIENTUNITS
:
743 if (getTokenId(sValue
) == XML_OBJECTBOUNDINGBOX
)
744 io_rCurrGradient
.mbBoundingBoxUnits
= true;
746 io_rCurrGradient
.mbBoundingBoxUnits
= false;
753 void parseRadialGradientData( Gradient
& io_rCurrGradient
,
754 const sal_Int32 nGradientNumber
,
755 const sal_Int32 nTokenId
,
756 const OUString
& sValue
)
760 case XML_GRADIENTTRANSFORM
:
762 OString
aValueUtf8( sValue
.getStr(),
764 RTL_TEXTENCODING_UTF8
);
765 parseTransform(aValueUtf8
.getStr(),io_rCurrGradient
.maTransform
);
769 io_rCurrGradient
.maCoords
.radial
.mfCX
= convLength(sValue
,maCurrState
,'h');
772 io_rCurrGradient
.maCoords
.radial
.mfCY
= convLength(sValue
,maCurrState
,'v');
775 io_rCurrGradient
.maCoords
.radial
.mfFX
= convLength(sValue
,maCurrState
,'h');
778 io_rCurrGradient
.maCoords
.radial
.mfFY
= convLength(sValue
,maCurrState
,'v');
781 io_rCurrGradient
.maCoords
.radial
.mfR
= convLength(sValue
,maCurrState
,'r');
784 maGradientIdMap
.insert(std::make_pair(sValue
,nGradientNumber
));
786 case XML_GRADIENTUNITS
:
787 if (getTokenId(sValue
) == XML_OBJECTBOUNDINGBOX
)
788 io_rCurrGradient
.mbBoundingBoxUnits
= true;
790 io_rCurrGradient
.mbBoundingBoxUnits
= false;
797 void parseGradientStop( GradientStop
& io_rGradientStop
,
798 const sal_Int32 nStopNumber
,
799 const sal_Int32 nTokenId
,
800 const OUString
& sValue
)
806 ElementRefMapType::iterator aFound
=maStopIdMap
.end();
807 if ( sValue
.copy(0,1) == "#" )
808 aFound
= maStopIdMap
.find(sValue
.copy(1));
810 aFound
= maStopIdMap
.find(sValue
);
812 if( aFound
!= maStopIdMap
.end() )
813 io_rGradientStop
= maGradientStopVector
[aFound
->second
];
817 maStopIdMap
.insert(std::make_pair(sValue
,nStopNumber
));
820 io_rGradientStop
.mnStopPosition
= sValue
.toDouble();
823 parseStyle( sValue
);
830 void parseAttribute( const sal_Int32 nTokenId
,
831 const OUString
& sValue
)
833 OString
aValueUtf8( sValue
.getStr(),
835 RTL_TEXTENCODING_UTF8
);
840 const double fViewPortWidth(
841 convLength(sValue
,maCurrState
,'h'));
843 maCurrState
.maViewport
.expand(
844 basegfx::B2DTuple(fViewPortWidth
,0.0));
849 const double fViewPortHeight(
850 convLength(sValue
,maCurrState
,'v'));
852 maCurrState
.maViewport
.expand(
853 basegfx::B2DTuple(0.0,fViewPortHeight
));
858 // TODO(F1): preserveAspectRatio
861 maCurrState
.maViewBox
);
866 if( aValueUtf8
== "evenodd" )
867 maCurrState
.meFillRule
= EVEN_ODD
;
868 else if( aValueUtf8
== "nonzero" )
869 maCurrState
.meFillRule
= NON_ZERO
;
870 else if( aValueUtf8
== "inherit" )
871 maCurrState
.meFillRule
= maParentStates
.back().meFillRule
;
875 if( aValueUtf8
== "inherit" )
876 maCurrState
.mnOpacity
= maParentStates
.back().mnOpacity
;
878 maCurrState
.mnOpacity
= aValueUtf8
.toDouble();
880 case XML_FILL_OPACITY
:
881 if( aValueUtf8
== "inherit" )
882 maCurrState
.mnFillOpacity
= maParentStates
.back().mnFillOpacity
;
884 maCurrState
.mnFillOpacity
= aValueUtf8
.toDouble();
885 if( maCurrState
.mnFillOpacity
> 1 )
886 maCurrState
.mnFillOpacity
= 1;
889 case XML_STROKE_WIDTH
:
891 if( aValueUtf8
== "inherit" )
892 maCurrState
.mnStrokeWidth
= maParentStates
.back().mnStrokeWidth
;
894 maCurrState
.mnStrokeWidth
= convLength(sValue
,maCurrState
,'r');
897 case XML_STROKE_LINECAP
:
899 if( aValueUtf8
== "butt" )
900 maCurrState
.meLineCap
= BUTT
;
901 else if( aValueUtf8
== "round" )
902 maCurrState
.meLineCap
= ROUND
;
903 else if( aValueUtf8
== "square" )
904 maCurrState
.meLineCap
= RECT
;
905 else if( aValueUtf8
== "inherit" )
906 maCurrState
.meLineCap
= maParentStates
.back().meLineCap
;
909 case XML_STROKE_LINEJOIN
:
911 if( aValueUtf8
== "miter" )
912 maCurrState
.meLineJoin
= basegfx::B2DLINEJOIN_MITER
;
913 else if( aValueUtf8
== "round" )
914 maCurrState
.meLineJoin
= basegfx::B2DLINEJOIN_ROUND
;
915 else if( aValueUtf8
== "bevel" )
916 maCurrState
.meLineJoin
= basegfx::B2DLINEJOIN_BEVEL
;
917 else if( aValueUtf8
== "inherit" )
918 maCurrState
.meLineJoin
= maParentStates
.back().meLineJoin
;
921 case XML_STROKE_MITERLIMIT
:
923 if( aValueUtf8
== "inherit" )
924 maCurrState
.mnMiterLimit
= maParentStates
.back().mnMiterLimit
;
926 maCurrState
.mnMiterLimit
= aValueUtf8
.toDouble();
929 case XML_STROKE_DASHOFFSET
:
931 if( aValueUtf8
== "inherit" )
932 maCurrState
.mnDashOffset
= maParentStates
.back().mnDashOffset
;
934 maCurrState
.mnDashOffset
= convLength(sValue
,maCurrState
,'r');
937 case XML_STROKE_DASHARRAY
:
939 if( aValueUtf8
== "none" )
941 maCurrState
.maDashArray
.clear();
942 maCurrState
.meStrokeType
= SOLID
;
944 else if( aValueUtf8
== "inherit" )
945 maCurrState
.maDashArray
= maParentStates
.back().maDashArray
;
948 parseDashArray(aValueUtf8
.getStr(),
949 maCurrState
.maDashArray
);
950 maCurrState
.meStrokeType
= DASH
;
954 case XML_STROKE_OPACITY
:
955 if( aValueUtf8
== "inherit" )
956 maCurrState
.mnStrokeOpacity
= maParentStates
.back().mnStrokeOpacity
;
958 maCurrState
.mnStrokeOpacity
= aValueUtf8
.toDouble();
962 const State
& rParent( maParentStates
.back() );
965 maCurrState
.meFillType
,
966 maCurrState
.maFillColor
,
967 maCurrState
.maFillGradient
,
970 rParent
.maFillGradient
);
975 const State
& rParent( maParentStates
.back() );
978 maCurrState
.meStrokeType
,
979 maCurrState
.maStrokeColor
,
980 maCurrState
.maStrokeGradient
,
981 rParent
.meStrokeType
,
982 rParent
.maStrokeColor
,
983 rParent
.maStrokeGradient
);
988 if( aValueUtf8
== "inherit" )
989 maCurrState
.maCurrentColor
= maParentStates
.back().maCurrentColor
;
991 parseColor(aValueUtf8
.getStr(), maCurrState
.maCurrentColor
);
996 basegfx::B2DHomMatrix aTransform
;
997 parseTransform(aValueUtf8
.getStr(),aTransform
);
998 maCurrState
.maTransform
= maCurrState
.maTransform
*aTransform
;
1001 case XML_FONT_FAMILY
:
1002 maCurrState
.maFontFamily
=sValue
;
1005 maCurrState
.mnFontSize
=convLength(sValue
,maCurrState
,'v');
1007 case XML_FONT_STYLE
:
1008 parseFontStyle(maCurrState
,sValue
,aValueUtf8
.getStr());
1010 case XML_FONT_WEIGHT
:
1011 maCurrState
.mnFontWeight
=sValue
.toDouble();
1013 case XML_FONT_VARIANT
:
1014 parseFontVariant(maCurrState
,sValue
,aValueUtf8
.getStr());
1016 case XML_TEXT_ANCHOR
:
1017 parseTextAlign(maCurrState
,aValueUtf8
.getStr());
1019 case XML_STOP_COLOR
:
1020 if( maGradientVector
.empty() ||
1021 maGradientVector
.back().maStops
.empty() )
1023 parseColor( aValueUtf8
.getStr(),
1024 maGradientStopVector
[
1025 maGradientVector
.back().maStops
.back()].maStopColor
);
1027 case XML_STOP_OPACITY
:
1028 if( maGradientVector
.empty() ||
1029 maGradientVector
.back().maStops
.empty() )
1031 parseOpacity( aValueUtf8
.getStr(),
1032 maGradientStopVector
[
1033 maGradientVector
.back().maStops
.back()].maStopColor
);
1035 case XML_TOKEN_INVALID
:
1036 SAL_INFO("svg", "unhandled token");
1039 SAL_INFO("svg", "unhandled token " << getTokenName(nTokenId
));
1044 void parseStyle( const OUString
& sValue
)
1046 // split individual style attributes
1047 sal_Int32 nIndex
=0, nDummyIndex
=0;
1048 OUString aCurrToken
;
1051 aCurrToken
=sValue
.getToken(0,';',nIndex
);
1053 if( !aCurrToken
.isEmpty() )
1055 // split attrib & value
1057 OUString
aCurrAttrib(
1058 aCurrToken
.getToken(0,':',nDummyIndex
).trim());
1059 OSL_ASSERT(nDummyIndex
!=-1);
1061 OUString
aCurrValue(
1062 aCurrToken
.getToken(1,':',nDummyIndex
).trim());
1063 OSL_ASSERT(nDummyIndex
==-1);
1065 // recurse into normal attribute parsing
1066 parseAttribute( getTokenId(aCurrAttrib
),
1070 while( nIndex
!= -1 );
1073 static void parseFontStyle( State
& io_rInitialState
,
1074 const OUString
& rValue
,
1075 const char* sValue
)
1077 if( strcmp(sValue
,"inherit") != 0 )
1078 io_rInitialState
.maFontStyle
= rValue
;
1081 static void parseFontVariant( State
& io_rInitialState
,
1082 const OUString
& rValue
,
1083 const char* sValue
)
1085 if( strcmp(sValue
,"inherit") != 0 )
1086 io_rInitialState
.maFontVariant
= rValue
;
1089 static void parseTextAlign( State
& io_rInitialState
,
1090 const char* sValue
)
1092 if( strcmp(sValue
,"start") == 0 )
1093 io_rInitialState
.meTextAnchor
= BEFORE
;
1094 else if( strcmp(sValue
,"middle") == 0 )
1095 io_rInitialState
.meTextAnchor
= CENTER
;
1096 else if( strcmp(sValue
,"end") == 0 )
1097 io_rInitialState
.meTextAnchor
= AFTER
;
1098 // keep current val for sValue == "inherit"
1101 void parsePaint( const OUString
& rValue
,
1105 Gradient
& rGradient
,
1106 const PaintType
& rInheritType
,
1107 const ARGBColor
& rInheritColor
,
1108 const Gradient
& rInheritGradient
)
1110 std::pair
<const char*,const char*> aPaintUri((const char*)NULL
,(const char*)NULL
);
1111 std::pair
<ARGBColor
,bool> aColor(maCurrState
.maCurrentColor
,
1113 if( strcmp(sValue
,"none") == 0 )
1115 else if( strcmp(sValue
,"currentColor") == 0 )
1118 rColor
= maCurrState
.maCurrentColor
;
1120 else if( strcmp(sValue
,"inherit") == 0)
1122 rType
= rInheritType
;
1123 rColor
= rInheritColor
;
1124 rGradient
= rInheritGradient
;
1126 else if( parsePaintUri(aPaintUri
,aColor
,sValue
) )
1128 if( aPaintUri
.first
!= aPaintUri
.second
)
1130 // assuming gradient. assumption does not hold generally
1131 if( strstr(sValue
,")") && rValue
.getLength() > 5 )
1133 ElementRefMapType::iterator aRes
;
1134 if( (aRes
=maGradientIdMap
.find(
1135 rValue
.copy(aPaintUri
.first
-sValue
,
1136 aPaintUri
.second
-aPaintUri
.first
))) != maGradientIdMap
.end() )
1138 rGradient
= maGradientVector
[aRes
->second
];
1143 else if( aColor
.second
)
1146 rColor
= aColor
.first
;
1156 parseColor(sValue
,rColor
);
1160 sal_Int32 mnCurrStateId
;
1162 std::vector
<State
> maParentStates
;
1163 StatePool
& mrStates
;
1164 StateMap
& mrStateMap
;
1165 uno::Reference
<xml::sax::XDocumentHandler
> mxDocumentHandler
;
1166 std::vector
< Gradient
> maGradientVector
;
1167 std::vector
< GradientStop
> maGradientStopVector
;
1168 ElementRefMapType maGradientIdMap
;
1169 ElementRefMapType maStopIdMap
;
1172 /// Annotate svg styles with unique references to state pool
1173 static void annotateStyles( StatePool
& rStatePool
,
1174 StateMap
& rStateMap
,
1175 const State
& rInitialState
,
1176 const uno::Reference
<xml::dom::XElement
>& rElem
,
1177 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocHdl
)
1179 AnnotatingVisitor
aVisitor(rStatePool
,rStateMap
,rInitialState
,xDocHdl
);
1180 visitElements(aVisitor
, rElem
, STYLE_ANNOTATOR
);
1183 struct ShapeWritingVisitor
1185 ShapeWritingVisitor(StatePool
& /*rStatePool*/,
1186 StateMap
& rStateMap
,
1187 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
) :
1188 mrStateMap(rStateMap
),
1189 mxDocumentHandler(xDocumentHandler
),
1193 void operator()( const uno::Reference
<xml::dom::XElement
>& )
1197 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
,
1198 const uno::Reference
<xml::dom::XNamedNodeMap
>& xAttributes
)
1200 rtl::Reference
<SvXMLAttributeList
> xAttrs( new SvXMLAttributeList() );
1201 uno::Reference
<xml::sax::XAttributeList
> xUnoAttrs( xAttrs
.get() );
1203 sal_Int32
nDummyIndex(0);
1205 xElem
->getAttribute("internal-style-ref").getToken(
1206 0,'$',nDummyIndex
));
1207 StateMap::iterator pOrigState
=mrStateMap
.find(
1208 sStyleId
.toInt32());
1210 if( pOrigState
== mrStateMap
.end() )
1211 return; // non-exportable element, e.g. linearGradient
1213 maCurrState
= pOrigState
->second
;
1215 const sal_Int32
nTokenId(getTokenId(xElem
->getNodeName()));
1220 // collect attributes
1221 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1222 OUString sAttributeValue
;
1223 double x1
=0.0,y1
=0.0,x2
=0.0,y2
=0.0;
1224 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1226 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1227 const sal_Int32
nAttribId(
1228 getTokenId(xAttributes
->item(i
)->getNodeName()));
1232 x1
= convLength(sAttributeValue
,maCurrState
,'h');
1235 x2
= convLength(sAttributeValue
,maCurrState
,'h');
1238 y1
= convLength(sAttributeValue
,maCurrState
,'v');
1241 y2
= convLength(sAttributeValue
,maCurrState
,'v');
1249 if ( x1
!= x2
|| y1
!= y2
) {
1250 OUString sLinePath
= "M"+OUString::number(x1
)+","
1251 +OUString::number(y1
)+"L"+OUString::number(x2
)+","
1252 +OUString::number(y2
);
1253 basegfx::B2DPolyPolygon aPoly
;
1254 basegfx::tools::importFromSvgD(aPoly
, sLinePath
, false, NULL
);
1256 writePathShape(xAttrs
,
1260 basegfx::B2DPolyPolygon(aPoly
));
1268 OUString sPoints
= xElem
->hasAttribute("points") ? xElem
->getAttribute("points") : "";
1269 basegfx::B2DPolygon aPoly
;
1270 (void)basegfx::tools::importFromSvgPoints(aPoly
, sPoints
);
1271 if( nTokenId
== XML_POLYGON
|| maCurrState
.meFillType
!= NONE
)
1272 aPoly
.setClosed(true);
1274 writePathShape(xAttrs
,
1278 basegfx::B2DPolyPolygon(aPoly
));
1283 // collect attributes
1284 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1285 OUString sAttributeValue
;
1286 bool bRxSeen
=false, bRySeen
=false;
1287 double x
=0.0,y
=0.0,width
=0.0,height
=0.0,rx
=0.0,ry
=0.0;
1288 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1290 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1291 const sal_Int32
nAttribId(
1292 getTokenId(xAttributes
->item(i
)->getNodeName()));
1296 x
= convLength(sAttributeValue
,maCurrState
,'h');
1299 y
= convLength(sAttributeValue
,maCurrState
,'v');
1302 width
= convLength(sAttributeValue
,maCurrState
,'h');
1305 height
= convLength(sAttributeValue
,maCurrState
,'v');
1308 rx
= convLength(sAttributeValue
,maCurrState
,'h');
1312 ry
= convLength(sAttributeValue
,maCurrState
,'v');
1321 if ( (width
> 0) && (height
> 0) ) {
1322 if( bRxSeen
&& !bRySeen
)
1324 else if( bRySeen
&& !bRxSeen
)
1327 basegfx::B2DPolygon aPoly
;
1328 aPoly
= basegfx::tools::createPolygonFromRect(
1329 basegfx::B2DRange(x
,y
,x
+width
,y
+height
),
1330 rx
/(0.5*width
), ry
/(0.5*height
) );
1332 writePathShape(xAttrs
,
1336 basegfx::B2DPolyPolygon(aPoly
));
1342 OUString sPath
= xElem
->hasAttribute("d") ? xElem
->getAttribute("d") : "";
1343 basegfx::B2DPolyPolygon aPoly
;
1344 basegfx::tools::importFromSvgD(aPoly
, sPath
, false, NULL
);
1346 if ((maCurrState
.meStrokeType
== NONE
) &&
1347 (maCurrState
.meFillType
!= NONE
) &&
1350 aPoly
.setClosed(true);
1353 writePathShape(xAttrs
,
1362 // collect attributes
1363 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1364 OUString sAttributeValue
;
1365 double cx
=0.0,cy
=0.0,r
=0.0;
1366 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1368 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1369 const sal_Int32
nAttribId(
1370 getTokenId(xAttributes
->item(i
)->getNodeName()));
1374 cx
= convLength(sAttributeValue
,maCurrState
,'h');
1377 cy
= convLength(sAttributeValue
,maCurrState
,'v');
1380 r
= convLength(sAttributeValue
,maCurrState
,'r');
1388 writeEllipseShape(xAttrs
,
1392 basegfx::B2DEllipse(basegfx::B2DPoint(cx
, cy
), basegfx::B2DTuple(r
,r
)));
1397 // collect attributes
1398 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1399 OUString sAttributeValue
;
1400 double cx
=0.0,cy
=0.0,rx
=0.0, ry
=0.0;
1401 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1403 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1404 const sal_Int32
nAttribId(
1405 getTokenId(xAttributes
->item(i
)->getNodeName()));
1409 cx
= convLength(sAttributeValue
,maCurrState
,'h');
1412 cy
= convLength(sAttributeValue
,maCurrState
,'v');
1415 rx
= convLength(sAttributeValue
,maCurrState
,'h');
1418 ry
= convLength(sAttributeValue
,maCurrState
,'v');
1425 if ( rx
> 0 && ry
> 0 )
1426 writeEllipseShape(xAttrs
,
1430 basegfx::B2DEllipse(basegfx::B2DPoint(cx
, cy
), basegfx::B2DTuple(rx
,ry
)));
1435 // collect attributes
1436 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1437 OUString sAttributeValue
;
1438 double x
=0.0, y
=0.0, width
=0.0, height
=0.0;
1439 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1441 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1442 const sal_Int32
nAttribId(
1443 getTokenId(xAttributes
->item(i
)->getNodeName()));
1447 x
= convLength(sAttributeValue
,maCurrState
,'h');
1450 y
= convLength(sAttributeValue
,maCurrState
,'v');
1453 width
= convLength(sAttributeValue
,maCurrState
,'h');
1456 height
= convLength(sAttributeValue
,maCurrState
,'v');
1463 // extract basic transformations out of CTM
1464 basegfx::B2DTuple aScale
, aTranslate
;
1465 double fRotate
, fShearX
;
1466 if (maCurrState
.maCTM
.decompose(aScale
, aTranslate
, fRotate
, fShearX
))
1470 width
*= aScale
.getX();
1472 height
*= aScale
.getY();
1473 x
+= aTranslate
.getX();
1474 y
+= aTranslate
.getY();
1478 OUString sValue
= xElem
->hasAttribute("href") ? xElem
->getAttribute("href") : "";
1479 OString
aValueUtf8( sValue
.getStr(), sValue
.getLength(), RTL_TEXTENCODING_UTF8
);
1480 std::string sLinkValue
;
1481 parseXlinkHref(aValueUtf8
.getStr(), sLinkValue
);
1483 if (!sLinkValue
.empty())
1484 writeBinaryData(xAttrs
, xUnoAttrs
, xElem
, basegfx::B2DRange(x
,y
,x
+width
,y
+height
), sLinkValue
);
1489 // collect text from all TEXT_NODE children into sText
1490 OUStringBuffer sText
;
1491 visitChildren(boost::bind(
1492 (OUStringBuffer
& (OUStringBuffer::*)(const OUString
& str
))&OUStringBuffer::append
,
1494 boost::bind(&xml::dom::XNode::getNodeValue
,
1497 xml::dom::NodeType_TEXT_NODE
);
1499 // collect attributes
1500 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1501 OUString sAttributeValue
;
1503 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1505 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1506 const sal_Int32
nAttribId(
1507 getTokenId(xAttributes
->item(i
)->getNodeName()));
1511 x
= convLength(sAttributeValue
,maCurrState
,'h');
1514 y
= convLength(sAttributeValue
,maCurrState
,'v');
1522 // actually export text
1526 // extract basic transformations out of CTM
1527 basegfx::B2DTuple aScale
, aTranslate
;
1528 double fRotate
, fShearX
;
1529 if (maCurrState
.maCTM
.decompose(aScale
, aTranslate
, fRotate
, fShearX
))
1531 // some heuristic attempts to have text output
1532 // baseline-relative
1533 y
-= 2.0*maCurrState
.mnFontSize
/aScale
.getX()/3.0;
1537 x
+= aTranslate
.getX();
1538 y
+= aTranslate
.getY();
1542 // some heuristic attempts to have text output
1543 // baseline-relative
1544 y
-= 2.0*maCurrState
.mnFontSize
/3.0;
1547 xAttrs
->AddAttribute( "svg:x", OUString::number(pt2mm(x
))+"mm");
1548 xAttrs
->AddAttribute( "svg:y", OUString::number(pt2mm(y
))+"mm");
1549 xAttrs
->AddAttribute( "draw:style-name", "svggraphicstyle"+sStyleId
);
1551 mxDocumentHandler
->startElement("draw:frame", xUnoAttrs
);
1554 mxDocumentHandler
->startElement("draw:text-box", xUnoAttrs
);
1555 xAttrs
->AddAttribute( "text:style-name", "svgparagraphstyle"+sStyleId
);
1556 mxDocumentHandler
->startElement("text:p", xUnoAttrs
);
1559 xAttrs
->AddAttribute( "text:style-name", "svgtextstyle"+sStyleId
);
1560 mxDocumentHandler
->startElement("text:span", xUnoAttrs
);
1563 mxDocumentHandler
->characters(sText
.makeStringAndClear());
1564 mxDocumentHandler
->endElement("text:span");
1565 mxDocumentHandler
->endElement("text:p");
1566 mxDocumentHandler
->endElement("draw:text-box");
1567 mxDocumentHandler
->endElement("draw:frame");
1579 void writeBinaryData( rtl::Reference
<SvXMLAttributeList
>& xAttrs
,
1580 const uno::Reference
<xml::sax::XAttributeList
>& xUnoAttrs
,
1581 const uno::Reference
<xml::dom::XElement
>& /* xElem */,
1582 const basegfx::B2DRange
& rShapeBounds
,
1583 const std::string
& data
)
1586 xAttrs
->AddAttribute( "svg:x", OUString::number(pt2mm(rShapeBounds
.getMinX()))+"mm");
1587 xAttrs
->AddAttribute( "svg:y", OUString::number(pt2mm(rShapeBounds
.getMinY()))+"mm");
1588 xAttrs
->AddAttribute( "svg:width", OUString::number(pt2mm(rShapeBounds
.getWidth()))+"mm");
1589 xAttrs
->AddAttribute( "svg:height", OUString::number(pt2mm(rShapeBounds
.getHeight()))+"mm");
1591 mxDocumentHandler
->startElement("draw:frame", xUnoAttrs
);
1594 mxDocumentHandler
->startElement("draw:image", xUnoAttrs
);
1596 mxDocumentHandler
->startElement("office:binary-data", xUnoAttrs
);
1598 mxDocumentHandler
->characters(OUString::createFromAscii(data
.c_str()));
1600 mxDocumentHandler
->endElement("office:binary-data");
1602 mxDocumentHandler
->endElement("draw:image");
1604 mxDocumentHandler
->endElement("draw:frame");
1608 void writeEllipseShape( rtl::Reference
<SvXMLAttributeList
>& xAttrs
,
1609 const uno::Reference
<xml::sax::XAttributeList
>& xUnoAttrs
,
1610 const uno::Reference
<xml::dom::XElement
>& xElem
,
1611 const OUString
& rStyleId
,
1612 const basegfx::B2DEllipse
& rEllipse
)
1614 State aState
= maCurrState
;
1618 basegfx::B2DPolygon aPoly
= basegfx::tools::createPolygonFromEllipse(rEllipse
.getB2DEllipseCenter(),
1619 rEllipse
.getB2DEllipseRadius().getX(), rEllipse
.getB2DEllipseRadius().getY());
1620 writePathShape(xAttrs
, xUnoAttrs
, xElem
, rStyleId
, basegfx::B2DPolyPolygon(aPoly
));
1624 void writePathShape( rtl::Reference
<SvXMLAttributeList
>& xAttrs
,
1625 const uno::Reference
<xml::sax::XAttributeList
>& xUnoAttrs
,
1626 const uno::Reference
<xml::dom::XElement
>& xElem
,
1627 const OUString
& rStyleId
,
1628 const basegfx::B2DPolyPolygon
& rPoly
)
1630 // we might need to split up polypolygon into multiple path
1631 // shapes (e.g. when emulating line stroking)
1632 std::vector
<basegfx::B2DPolyPolygon
> aPolys(1,rPoly
);
1633 State aState
= maCurrState
;
1634 OUString
aStyleId(rStyleId
);
1638 OSL_TRACE("writePath - the CTM is: %f %f %f %f %f %f",
1639 maCurrState
.maCTM
.get(0,0),
1640 maCurrState
.maCTM
.get(0,1),
1641 maCurrState
.maCTM
.get(0,2),
1642 maCurrState
.maCTM
.get(1,0),
1643 maCurrState
.maCTM
.get(1,1),
1644 maCurrState
.maCTM
.get(1,2));
1646 // TODO(F2): separate out shear, rotate etc.
1647 // apply transformation to polygon, to keep draw
1648 // import in 100th mm
1649 std::for_each(aPolys
.begin(),aPolys
.end(),
1650 boost::bind(&basegfx::B2DPolyPolygon::transform
,
1651 _1
,boost::cref(aState
.maCTM
)));
1653 for( sal_uInt32 i
=0; i
<aPolys
.size(); ++i
)
1655 const basegfx::B2DRange
aBounds(
1656 aPolys
[i
].areControlPointsUsed() ?
1657 basegfx::tools::getRange(
1658 basegfx::tools::adaptiveSubdivideByAngle(aPolys
[i
])) :
1659 basegfx::tools::getRange(aPolys
[i
]));
1660 fillShapeProperties(xAttrs
,
1663 "svggraphicstyle"+aStyleId
);
1665 // force path coordinates to 100th millimeter, after
1666 // putting polygon data at origin (ODF viewbox
1667 // calculations largely untested codepaths, as OOo always
1668 // writes "0 0 w h" viewboxes)
1669 basegfx::B2DHomMatrix aNormalize
;
1670 aNormalize
.translate(-aBounds
.getMinX(),-aBounds
.getMinY());
1671 aNormalize
.scale(2540.0/72.0,2540.0/72.0);
1672 aPolys
[i
].transform(aNormalize
);
1674 xAttrs
->AddAttribute( "svg:d", basegfx::tools::exportToSvgD(
1676 false, // no relative coords. causes rounding errors
1677 false, // no quad bezier detection. crashes older versions.
1679 mxDocumentHandler
->startElement("draw:path", xUnoAttrs
);
1680 mxDocumentHandler
->endElement("draw:path");
1684 void fillShapeProperties( rtl::Reference
<SvXMLAttributeList
>& xAttrs
,
1685 const uno::Reference
<xml::dom::XElement
>& /* xElem */,
1686 const basegfx::B2DRange
& rShapeBounds
,
1687 const OUString
& rStyleName
)
1689 xAttrs
->AddAttribute( "draw:z-index", OUString::number( mnShapeNum
++ ));
1690 xAttrs
->AddAttribute( "draw:style-name", rStyleName
);
1691 xAttrs
->AddAttribute( "svg:width", OUString::number(pt2mm(rShapeBounds
.getWidth()))+"mm");
1692 xAttrs
->AddAttribute( "svg:height", OUString::number(pt2mm(rShapeBounds
.getHeight()))+"mm");
1694 // OOo expects the viewbox to be in 100th of mm
1695 xAttrs
->AddAttribute( "svg:viewBox",
1698 basegfx::fround(pt100thmm(rShapeBounds
.getWidth())) )
1701 basegfx::fround(pt100thmm(rShapeBounds
.getHeight())) ));
1703 // TODO(F1): decompose transformation in calling code, and use
1704 // transform attribute here
1705 // writeTranslate(maCurrState.maCTM, xAttrs);
1706 xAttrs
->AddAttribute( "svg:x", OUString::number(pt2mm(rShapeBounds
.getMinX()))+"mm");
1707 xAttrs
->AddAttribute( "svg:y", OUString::number(pt2mm(rShapeBounds
.getMinY()))+"mm");
1711 StateMap
& mrStateMap
;
1712 uno::Reference
<xml::sax::XDocumentHandler
> mxDocumentHandler
;
1713 sal_Int32 mnShapeNum
;
1716 /// Write out shapes from DOM tree
1717 static void writeShapes( StatePool
& rStatePool
,
1718 StateMap
& rStateMap
,
1719 const uno::Reference
<xml::dom::XElement
>& rElem
,
1720 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocHdl
)
1722 ShapeWritingVisitor
aVisitor(rStatePool
,rStateMap
,xDocHdl
);
1723 visitElements(aVisitor
, rElem
, SHAPE_WRITER
);
1728 struct OfficeStylesWritingVisitor
1730 OfficeStylesWritingVisitor( StateMap
& rStateMap
,
1731 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
) :
1732 mrStateMap(rStateMap
),
1733 mxDocumentHandler(xDocumentHandler
)
1735 void operator()( const uno::Reference
<xml::dom::XElement
>& /*xElem*/ )
1738 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
,
1739 const uno::Reference
<xml::dom::XNamedNodeMap
>& /*xAttributes*/ )
1741 rtl::Reference
<SvXMLAttributeList
> xAttrs( new SvXMLAttributeList() );
1742 uno::Reference
<xml::sax::XAttributeList
> xUnoAttrs( xAttrs
.get() );
1744 sal_Int32
nDummyIndex(0);
1746 xElem
->getAttribute("internal-style-ref").getToken(
1747 0,'$',nDummyIndex
));
1748 StateMap::iterator pOrigState
=mrStateMap
.find(
1749 sStyleId
.toInt32());
1751 if( pOrigState
== mrStateMap
.end() )
1752 return; // non-exportable element, e.g. linearGradient
1754 maCurrState
= pOrigState
->second
;
1756 if( maCurrState
.meStrokeType
== DASH
)
1758 sal_Int32 dots1
, dots2
;
1759 double dots1_length
, dots2_length
, dash_distance
;
1760 SvgDashArray2Odf( &dots1
, &dots1_length
, &dots2
, &dots2_length
, &dash_distance
);
1763 xAttrs
->AddAttribute( "draw:name", "dash"+sStyleId
);
1764 xAttrs
->AddAttribute( "draw:display-name", "dash"+sStyleId
);
1765 xAttrs
->AddAttribute( "draw:style", "rect" );
1767 xAttrs
->AddAttribute( "draw:dots1", OUString::number(dots1
) );
1768 xAttrs
->AddAttribute( "draw:dots1-length", OUString::number(pt2mm(convLength( OUString::number(dots1_length
), maCurrState
, 'h' )))+"mm" );
1770 xAttrs
->AddAttribute( "draw:distance", OUString::number(pt2mm(convLength( OUString::number(dash_distance
), maCurrState
, 'h' )))+"mm" );
1772 xAttrs
->AddAttribute( "draw:dots2", OUString::number(dots2
) );
1773 xAttrs
->AddAttribute( "draw:dots2-length", OUString::number(pt2mm(convLength( OUString::number(dots2_length
), maCurrState
, 'h' )))+"mm" );
1776 mxDocumentHandler
->startElement( "draw:stroke-dash", xUnoAttrs
);
1777 mxDocumentHandler
->endElement( "draw:stroke-dash" );
1781 void SvgDashArray2Odf( sal_Int32
*dots1
, double *dots1_length
, sal_Int32
*dots2
, double *dots2_length
, double *dash_distance
)
1789 if( maCurrState
.maDashArray
.size() == 0 ) {
1793 double effective_dasharray_size
= maCurrState
.maDashArray
.size();
1794 if( maCurrState
.maDashArray
.size() % 2 == 1 )
1795 effective_dasharray_size
= maCurrState
.maDashArray
.size()*2;
1797 *dash_distance
= maCurrState
.maDashArray
[1%maCurrState
.maDashArray
.size()];
1798 sal_Int32 dist_count
= 1;
1799 for( int i
=3; i
<effective_dasharray_size
; i
+=2 ) {
1800 *dash_distance
= ((dist_count
* *dash_distance
) + maCurrState
.maDashArray
[i
%maCurrState
.maDashArray
.size()])/(dist_count
+1);
1805 *dots1_length
= maCurrState
.maDashArray
[0];
1807 while( ( i
<effective_dasharray_size
) && ( maCurrState
.maDashArray
[i
%maCurrState
.maDashArray
.size()] == *dots1_length
) ) {
1811 if( i
<effective_dasharray_size
) {
1813 *dots2_length
= maCurrState
.maDashArray
[i
];
1815 while( ( i
<effective_dasharray_size
) && ( maCurrState
.maDashArray
[i
%maCurrState
.maDashArray
.size()] == *dots2_length
) ) {
1821 SAL_INFO("svg", "SvgDashArray2Odf " << *dash_distance
<< " " << *dots1
<< " " << *dots1_length
<< " " << *dots2
<< " " << *dots2_length
);
1826 static void push() {}
1827 static void pop() {}
1830 StateMap
& mrStateMap
;
1831 uno::Reference
<xml::sax::XDocumentHandler
> mxDocumentHandler
;
1834 static void writeOfficeStyles( StateMap
& rStateMap
,
1835 const uno::Reference
<xml::dom::XElement
>& rElem
,
1836 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocHdl
)
1838 OfficeStylesWritingVisitor
aVisitor( rStateMap
, xDocHdl
);
1839 visitElements( aVisitor
, rElem
, STYLE_WRITER
);
1842 #if OSL_DEBUG_LEVEL > 2
1843 struct DumpingVisitor
1845 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
)
1847 OSL_TRACE("name: %s",
1849 xElem
->getTagName(),
1850 RTL_TEXTENCODING_UTF8
).getStr());
1853 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
,
1854 const uno::Reference
<xml::dom::XNamedNodeMap
>& xAttributes
)
1856 OSL_TRACE("name: %s",
1858 xElem
->getTagName(),
1859 RTL_TEXTENCODING_UTF8
).getStr());
1860 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1861 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1865 xAttributes
->item(i
)->getNodeName(),
1866 RTL_TEXTENCODING_UTF8
).getStr(),
1868 xAttributes
->item(i
)->getNodeValue(),
1869 RTL_TEXTENCODING_UTF8
).getStr());
1877 static void dumpTree( const uno::Reference
<xml::dom::XElement
> xElem
)
1879 DumpingVisitor aVisitor
;
1880 visitElements(aVisitor
, xElem
);
1885 SVGReader::SVGReader(const uno::Reference
<uno::XComponentContext
>& xContext
,
1886 const uno::Reference
<io::XInputStream
>& xInputStream
,
1887 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
) :
1888 m_xContext( xContext
),
1889 m_xInputStream( xInputStream
),
1890 m_xDocumentHandler( xDocumentHandler
)
1894 bool SVGReader::parseAndConvert()
1896 uno::Reference
<xml::dom::XDocumentBuilder
> xDomBuilder
= xml::dom::DocumentBuilder::create(m_xContext
);
1898 uno::Reference
<xml::dom::XDocument
> xDom(
1899 xDomBuilder
->parse(m_xInputStream
),
1900 uno::UNO_QUERY_THROW
);
1902 uno::Reference
<xml::dom::XElement
> xDocElem( xDom
->getDocumentElement(),
1903 uno::UNO_QUERY_THROW
);
1905 // the root state for svg document
1906 State aInitialState
;
1912 m_xDocumentHandler
->startDocument();
1914 // get the document dimensions
1916 // if the "width" and "height" attributes are missing, inkscape fakes
1917 // A4 portrait for. Let's do the same.
1918 if (!xDocElem
->hasAttribute("width"))
1919 xDocElem
->setAttribute("width", "210mm");
1920 if (!xDocElem
->hasAttribute("height"))
1921 xDocElem
->setAttribute("height", "297mm");
1923 double fViewPortWidth( pt2mm(convLength(xDocElem
->getAttribute("width"),aInitialState
,'h')) );
1924 double fViewPortHeight( pt2mm(convLength(xDocElem
->getAttribute("height"),aInitialState
,'v')) );
1927 rtl::Reference
<SvXMLAttributeList
> xAttrs( new SvXMLAttributeList() );
1928 uno::Reference
<xml::sax::XAttributeList
> xUnoAttrs( xAttrs
.get() );
1930 xAttrs
->AddAttribute( "xmlns:office", OASIS_STR
"office:1.0" );
1931 xAttrs
->AddAttribute( "xmlns:style", OASIS_STR
"style:1.0" );
1932 xAttrs
->AddAttribute( "xmlns:text", OASIS_STR
"text:1.0" );
1933 xAttrs
->AddAttribute( "xmlns:svg", OASIS_STR
"svg-compatible:1.0" );
1934 xAttrs
->AddAttribute( "xmlns:table", OASIS_STR
"table:1.0" );
1935 xAttrs
->AddAttribute( "xmlns:draw", OASIS_STR
"drawing:1.0" );
1936 xAttrs
->AddAttribute( "xmlns:fo", OASIS_STR
"xsl-fo-compatible:1.0" );
1937 xAttrs
->AddAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink");
1938 xAttrs
->AddAttribute( "xmlns:dc", "http://purl.org/dc/elements/1.1/");
1939 xAttrs
->AddAttribute( "xmlns:number", OASIS_STR
"datastyle:1.0" );
1940 xAttrs
->AddAttribute( "xmlns:presentation", OASIS_STR
"presentation:1.0" );
1941 xAttrs
->AddAttribute( "xmlns:math", "http://www.w3.org/1998/Math/MathML");
1942 xAttrs
->AddAttribute( "xmlns:form", OASIS_STR
"form:1.0" );
1943 xAttrs
->AddAttribute( "xmlns:script", OASIS_STR
"script:1.0" );
1944 xAttrs
->AddAttribute( "xmlns:dom", "http://www.w3.org/2001/xml-events");
1945 xAttrs
->AddAttribute( "xmlns:xforms", "http://www.w3.org/2002/xforms");
1946 xAttrs
->AddAttribute( "xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
1947 xAttrs
->AddAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
1948 xAttrs
->AddAttribute( "office:version", "1.0");
1949 xAttrs
->AddAttribute( "office:mimetype", "application/vnd.oasis.opendocument.graphics");
1951 m_xDocumentHandler
->startElement( "office:document", xUnoAttrs
);
1955 m_xDocumentHandler
->startElement( "office:settings", xUnoAttrs
);
1957 xAttrs
->AddAttribute( "config:name", "ooo:view-settings");
1958 m_xDocumentHandler
->startElement( "config:config-item-set", xUnoAttrs
);
1962 xAttrs
->AddAttribute( "config:name", "VisibleAreaTop");
1963 xAttrs
->AddAttribute( "config:type", "int");
1964 m_xDocumentHandler
->startElement( "config:config-item", xUnoAttrs
);
1966 m_xDocumentHandler
->characters( "0" );
1968 m_xDocumentHandler
->endElement( "config:config-item" );
1972 xAttrs
->AddAttribute( "config:name", "VisibleAreaLeft" );
1973 xAttrs
->AddAttribute( "config:type", "int" );
1974 m_xDocumentHandler
->startElement( "config:config-item" , xUnoAttrs
);
1976 m_xDocumentHandler
->characters( "0" );
1978 m_xDocumentHandler
->endElement( "config:config-item" );
1982 xAttrs
->AddAttribute( "config:name" , "VisibleAreaWidth" );
1983 xAttrs
->AddAttribute( "config:type" , "int" );
1984 m_xDocumentHandler
->startElement( "config:config-item" , xUnoAttrs
);
1986 sal_Int64 iWidth
= sal_Int64(fViewPortWidth
);
1987 m_xDocumentHandler
->characters( OUString::number(iWidth
) );
1989 m_xDocumentHandler
->endElement( "config:config-item" );
1993 xAttrs
->AddAttribute( "config:name", "VisibleAreaHeight" );
1994 xAttrs
->AddAttribute( "config:type", "int" );
1995 m_xDocumentHandler
->startElement( "config:config-item", xUnoAttrs
);
1997 sal_Int64 iHeight
= sal_Int64(fViewPortHeight
);
1998 m_xDocumentHandler
->characters( OUString::number(iHeight
) );
2000 m_xDocumentHandler
->endElement( "config:config-item" );
2002 m_xDocumentHandler
->endElement( "config:config-item-set" );
2004 m_xDocumentHandler
->endElement( "office:settings" );
2008 m_xDocumentHandler
->startElement( "office:automatic-styles",
2011 xAttrs
->AddAttribute( "style:name", "pagelayout1");
2012 m_xDocumentHandler
->startElement( "style:page-layout", xUnoAttrs
);
2013 // TODO(Q3): this is super-ugly. In-place container come to mind.
2016 // make page viewport-width times viewport-height mm large - add
2017 // 5% border at every side
2018 xAttrs
->AddAttribute( "fo:margin-top", "0mm");
2019 xAttrs
->AddAttribute( "fo:margin-bottom", "0mm");
2020 xAttrs
->AddAttribute( "fo:margin-left", "0mm");
2021 xAttrs
->AddAttribute( "fo:margin-right", "0mm");
2022 xAttrs
->AddAttribute( "fo:page-width", OUString::number(fViewPortWidth
)+"mm");
2023 xAttrs
->AddAttribute( "fo:page-height", OUString::number(fViewPortHeight
)+"mm");
2024 xAttrs
->AddAttribute( "style:print-orientation",
2025 fViewPortWidth
> fViewPortHeight
? OUString("landscape") : OUString("portrait") );
2026 m_xDocumentHandler
->startElement( "style:page-layout-properties", xUnoAttrs
);
2027 m_xDocumentHandler
->endElement( "style:page-layout-properties" );
2028 m_xDocumentHandler
->endElement( "style:page-layout" );
2031 xAttrs
->AddAttribute( "style:name", "pagestyle1" );
2032 xAttrs
->AddAttribute( "style:family", "drawing-page" );
2033 m_xDocumentHandler
->startElement( "style:style", xUnoAttrs
);
2036 xAttrs
->AddAttribute( "draw:background-size", "border");
2037 xAttrs
->AddAttribute( "draw:fill", "none");
2038 m_xDocumentHandler
->startElement( "style:drawing-page-properties", xUnoAttrs
);
2039 m_xDocumentHandler
->endElement( "style:drawing-page-properties" );
2040 m_xDocumentHandler
->endElement( "style:style" );
2042 StatePool aStatePool
;
2044 annotateStyles(aStatePool
,aStateMap
,aInitialState
,
2045 xDocElem
,m_xDocumentHandler
);
2047 #if OSL_DEBUG_LEVEL > 2
2051 m_xDocumentHandler
->endElement( "office:automatic-styles" );
2056 m_xDocumentHandler
->startElement( "office:styles", xUnoAttrs
);
2057 writeOfficeStyles( aStateMap
,
2059 m_xDocumentHandler
);
2060 m_xDocumentHandler
->endElement( "office:styles" );
2064 m_xDocumentHandler
->startElement( "office:master-styles", xUnoAttrs
);
2066 xAttrs
->AddAttribute( "style:name", "Default");
2067 xAttrs
->AddAttribute( "style:page-layout-name", "pagelayout1");
2068 xAttrs
->AddAttribute( "draw:style-name", "pagestyle1");
2069 m_xDocumentHandler
->startElement( "style:master-page", xUnoAttrs
);
2070 m_xDocumentHandler
->endElement( "style:master-page" );
2072 m_xDocumentHandler
->endElement( "office:master-styles" );
2077 m_xDocumentHandler
->startElement( "office:body", xUnoAttrs
);
2078 m_xDocumentHandler
->startElement( "office:drawing", xUnoAttrs
);
2081 xAttrs
->AddAttribute( "draw:master-page-name", "Default");
2082 xAttrs
->AddAttribute( "draw:style-name", "pagestyle1");
2083 m_xDocumentHandler
->startElement("draw:page", xUnoAttrs
);
2085 // write out all shapes
2086 writeShapes(aStatePool
,
2089 m_xDocumentHandler
);
2091 m_xDocumentHandler
->endElement( "draw:page" );
2092 m_xDocumentHandler
->endElement( "office:drawing" );
2093 m_xDocumentHandler
->endElement( "office:body" );
2094 m_xDocumentHandler
->endElement( "office:document" );
2095 m_xDocumentHandler
->endDocument();
2102 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */