1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
6 * Fridrich Strba <fridrich.strba@bluewin.ch>
7 * Thorsten Behrens <tbehrens@novell.com>
9 * Copyright (C) 2008, Novell Inc.
10 * Parts copyright 2005 by Sun Microsystems, Inc.
12 * The Contents of this file are made available subject to
13 * the terms of GNU Lesser General Public License Version 2.1.
15 ************************************************************************/
17 // MARKER(update_precomp.py): autogen include statement, do not remove
18 #include "precompiled_filter.hxx"
20 #include "svgreader.hxx"
21 #include <xmloff/attrlist.hxx>
22 #include "gfxtypes.hxx"
24 #include "parserfragments.hxx"
25 #include "tokenmap.hxx"
26 #include "b2dellipse.hxx"
28 #include <rtl/math.hxx>
29 #include <rtl/ref.hxx>
30 #include <rtl/ustring.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <basegfx/vector/b2enums.hxx>
33 #include <basegfx/range/b2drange.hxx>
34 #include <basegfx/matrix/b2dhommatrix.hxx>
35 #include <basegfx/polygon/b2dpolypolygon.hxx>
36 #include <basegfx/polygon/b2dlinegeometry.hxx>
37 #include <basegfx/polygon/b2dpolygontools.hxx>
38 #include <basegfx/polygon/b2dpolypolygontools.hxx>
39 #include <basegfx/polygon/b2dlinegeometry.hxx>
40 #include <com/sun/star/io/XSeekable.hpp>
41 #include <com/sun/star/xml/sax/XParser.hpp>
42 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
43 #include <com/sun/star/xml/dom/NodeType.hpp>
45 #include <comphelper/processfactory.hxx>
46 #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
47 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
48 #include <unotools/streamwrap.hxx>
49 #include <xmloff/xmluconv.hxx>
50 #include <vcl/graph.hxx>
51 #include <vcl/virdev.hxx>
52 #include <vcl/gradient.hxx>
53 #include <svx/impgrf.hxx>
54 #include <tools/zcodec.hxx>
56 #include <boost/bind.hpp>
61 #define USTR(x) rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( x ) )
62 #define OASIS_STR "urn:oasis:names:tc:opendocument:xmlns:"
64 using namespace ::com::sun::star
;
71 /** visits all children of the specified type with the given functor
73 template<typename Func
> void visitChildren(const Func
& rFunc
,
74 const uno::Reference
<xml::dom::XElement
> xElem
,
75 xml::dom::NodeType eChildType
)
77 uno::Reference
<xml::dom::XNodeList
> xChildren( xElem
->getChildNodes() );
78 const sal_Int32
nNumNodes( xChildren
->getLength() );
79 for( sal_Int32 i
=0; i
<nNumNodes
; ++i
)
81 if( xChildren
->item(i
)->getNodeType() == eChildType
)
82 rFunc( *xChildren
->item(i
).get() );
86 /** Visit all elements of the given tree (in-order traversal)
88 Given functor is called for every element, and passed the
89 element's attributes, if any
91 template<typename Func
> void visitElements(Func
& rFunc
,
92 const uno::Reference
<xml::dom::XElement
> xElem
)
94 if( xElem
->hasAttributes() )
95 rFunc(xElem
,xElem
->getAttributes());
99 // notify children processing
102 // recurse over children
103 uno::Reference
<xml::dom::XNodeList
> xChildren( xElem
->getChildNodes() );
104 const sal_Int32
nNumNodes( xChildren
->getLength() );
105 for( sal_Int32 i
=0; i
<nNumNodes
; ++i
)
107 if( xChildren
->item(i
)->getNodeType() == xml::dom::NodeType_ELEMENT_NODE
)
108 visitElements( rFunc
,
109 uno::Reference
<xml::dom::XElement
>(
111 uno::UNO_QUERY_THROW
) );
114 // children processing done
118 template<typename value_type
> value_type
square(value_type v
)
123 double colorDiffSquared(const ARGBColor
& rCol1
, const ARGBColor
& rCol2
)
126 square(rCol1
.a
-rCol2
.a
)
127 + square(rCol1
.r
-rCol2
.r
)
128 + square(rCol1
.g
-rCol2
.g
)
129 + square(rCol1
.b
-rCol2
.b
);
132 typedef std::map
<rtl::OUString
,sal_Size
> ElementRefMapType
;
134 struct AnnotatingVisitor
136 AnnotatingVisitor(StatePool
& rStatePool
,
138 const State
& rInitialState
,
139 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
) :
143 mrStates(rStatePool
),
144 mrStateMap(rStateMap
),
145 mxDocumentHandler(xDocumentHandler
),
147 maGradientStopVector()
149 maParentStates
.push_back(rInitialState
);
152 void operator()( const uno::Reference
<xml::dom::XElement
>& )
155 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
,
156 const uno::Reference
<xml::dom::XNamedNodeMap
>& xAttributes
)
158 const sal_Int32
nTagId(getTokenId(xElem
->getTagName()));
161 case XML_LINEARGRADIENT
:
163 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
164 rtl::OUString sAttributeValue
;
165 maGradientVector
.push_back(Gradient(Gradient::LINEAR
));
167 // do we have a reference to a parent gradient? parse
168 // that first, as it sets our defaults here (manually
169 // tracking default state on each Gradient variable is
170 // much more overhead)
171 uno::Reference
<xml::dom::XNode
> xNode(xAttributes
->getNamedItem(USTR("href")));
174 const rtl::OUString
sValue(xNode
->getNodeValue());
175 ElementRefMapType::iterator aFound
=maGradientIdMap
.end();
176 if (sValue
.copy(0,1).equalsAscii("#"))
177 aFound
= maGradientIdMap
.find(sValue
.copy(1));
179 aFound
= maGradientIdMap
.find(sValue
);;
181 if( aFound
!= maGradientIdMap
.end() )
182 maGradientVector
.back() = maGradientVector
[aFound
->second
];
185 // do that after dereferencing, to prevent hyperlinked
186 // gradient to clobber our Id again
187 maGradientVector
.back().mnId
= maGradientVector
.size()-1;
188 maGradientVector
.back().meType
= Gradient::LINEAR
; // has been clobbered as well
190 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
192 parseLinearGradientData( maGradientVector
.back(),
193 maGradientVector
.size()-1,
194 getTokenId(xAttributes
->item(i
)->getNodeName()),
195 xAttributes
->item(i
)->getNodeValue() );
199 case XML_RADIALGRADIENT
:
201 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
202 rtl::OUString sAttributeValue
;
203 maGradientVector
.push_back(Gradient(Gradient::RADIAL
));
205 // do we have a reference to a parent gradient? parse
206 // that first, as it sets our defaults here (manually
207 // tracking default state on each Gradient variable is
208 // much more overhead)
209 uno::Reference
<xml::dom::XNode
> xNode(xAttributes
->getNamedItem(USTR("href")));
212 const rtl::OUString
sValue(xNode
->getNodeValue());
213 ElementRefMapType::iterator aFound
=maGradientIdMap
.end();
214 if (sValue
.copy(0,1).equalsAscii("#"))
215 aFound
= maGradientIdMap
.find(sValue
.copy(1));
217 aFound
= maGradientIdMap
.find(sValue
);;
219 if( aFound
!= maGradientIdMap
.end() )
220 maGradientVector
.back() = maGradientVector
[aFound
->second
];
223 // do that after dereferencing, to prevent hyperlinked
224 // gradient to clobber our Id again
225 maGradientVector
.back().mnId
= maGradientVector
.size()-1;
226 maGradientVector
.back().meType
= Gradient::RADIAL
; // has been clobbered as well
228 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
230 parseRadialGradientData( maGradientVector
.back(),
231 maGradientVector
.size()-1,
232 getTokenId(xAttributes
->item(i
)->getNodeName()),
233 xAttributes
->item(i
)->getNodeValue() );
239 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
240 rtl::OUString sAttributeValue
;
241 maGradientStopVector
.push_back(GradientStop());
242 maGradientVector
.back().maStops
.push_back(maGradientStopVector
.size()-1);
243 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
245 parseGradientStop( maGradientStopVector
.back(),
246 maGradientStopVector
.size()-1,
247 getTokenId(xAttributes
->item(i
)->getNodeName()),
248 xAttributes
->item(i
)->getNodeValue() );
254 // init state. inherit defaults from parent.
255 maCurrState
= maParentStates
.back();
256 maCurrState
.maTransform
.identity();
257 maCurrState
.maViewBox
.reset();
259 // scan for style info
260 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
261 rtl::OUString sAttributeValue
;
262 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
264 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
265 const sal_Int32
nTokenId(
266 getTokenId(xAttributes
->item(i
)->getNodeName()));
267 if( XML_STYLE
== nTokenId
)
268 parseStyle(sAttributeValue
);
270 parseAttribute(nTokenId
,
274 // all attributes parsed, can calc total CTM now
275 basegfx::B2DHomMatrix aLocalTransform
;
276 if( !maCurrState
.maViewBox
.isEmpty() &&
277 maCurrState
.maViewBox
.getWidth() != 0.0 &&
278 maCurrState
.maViewBox
.getHeight() != 0.0 )
280 // transform aViewBox into viewport, such that they
282 aLocalTransform
.translate(-maCurrState
.maViewBox
.getMinX(),
283 -maCurrState
.maViewBox
.getMinY());
284 aLocalTransform
.scale(maCurrState
.maViewport
.getWidth()/maCurrState
.maViewBox
.getWidth(),
285 maCurrState
.maViewport
.getHeight()/maCurrState
.maViewBox
.getHeight());
287 maCurrState
.maCTM
= maCurrState
.maCTM
*maCurrState
.maTransform
*aLocalTransform
;
289 OSL_TRACE("annotateStyle - CTM is: %f %f %f %f %f %f",
290 maCurrState
.maCTM
.get(0,0),
291 maCurrState
.maCTM
.get(0,1),
292 maCurrState
.maCTM
.get(0,2),
293 maCurrState
.maCTM
.get(1,0),
294 maCurrState
.maCTM
.get(1,1),
295 maCurrState
.maCTM
.get(1,2));
297 // if necessary, serialize to automatic-style section
298 writeStyle(xElem
,nTagId
);
303 rtl::OUString
getStyleName( const char* sPrefix
, sal_Int32 nId
)
305 return rtl::OUString::createFromAscii(sPrefix
)+rtl::OUString::valueOf(nId
);
308 bool hasGradientOpacity( const Gradient
& rGradient
)
311 maGradientStopVector
[
312 rGradient
.maStops
[0]].maStopColor
.a
!= 1.0 ||
313 maGradientStopVector
[
314 rGradient
.maStops
[1]].maStopColor
.a
!= 1.0;
319 explicit StopSorter( const std::vector
< GradientStop
>& rStopVec
) :
323 bool operator()( sal_Size rLHS
, sal_Size rRHS
)
325 return mrStopVec
[rLHS
].mnStopPosition
< mrStopVec
[rRHS
].mnStopPosition
;
328 const std::vector
< GradientStop
>& mrStopVec
;
331 void optimizeGradientStops( Gradient
& rGradient
)
333 // sort for increasing stop position
334 std::sort(rGradient
.maStops
.begin(),rGradient
.maStops
.end(),
335 StopSorter(maGradientStopVector
));
337 if( rGradient
.maStops
.size() < 3 )
340 // join similar colors
341 std::vector
<sal_Size
> aNewStops(1,rGradient
.maStops
.front());
342 for( sal_Size i
=1; i
<rGradient
.maStops
.size(); ++i
)
344 if( maGradientStopVector
[rGradient
.maStops
[i
]].maStopColor
!=
345 maGradientStopVector
[aNewStops
.back()].maStopColor
)
346 aNewStops
.push_back(rGradient
.maStops
[i
]);
349 rGradient
.maStops
= aNewStops
;
351 // axial gradient, maybe?
352 if( rGradient
.meType
== Gradient::LINEAR
&&
353 rGradient
.maStops
.size() == 3 &&
354 maGradientStopVector
[rGradient
.maStops
.front()].maStopColor
==
355 maGradientStopVector
[rGradient
.maStops
.back()].maStopColor
)
357 // yep - keep it at that
361 // find out most significant color difference, and limit to
362 // those two stops around this border (metric is
363 // super-simplistic: take euclidean distance of colors, weigh
364 // with stop distance)
365 sal_Size nMaxIndex
=0;
366 double fMaxDistance
=0.0;
367 for( sal_Size i
=1; i
<rGradient
.maStops
.size(); ++i
)
369 const double fCurrDistance(
371 maGradientStopVector
[rGradient
.maStops
[i
-1]].maStopColor
,
372 maGradientStopVector
[rGradient
.maStops
[i
]].maStopColor
) *
373 (square(maGradientStopVector
[rGradient
.maStops
[i
-1]].mnStopPosition
) +
374 square(maGradientStopVector
[rGradient
.maStops
[i
]].mnStopPosition
)) );
376 if( fCurrDistance
> fMaxDistance
)
379 fMaxDistance
= fCurrDistance
;
382 rGradient
.maStops
[0] = rGradient
.maStops
[nMaxIndex
];
383 rGradient
.maStops
[1] = rGradient
.maStops
[nMaxIndex
+1];
384 rGradient
.maStops
.erase(rGradient
.maStops
.begin()+2,rGradient
.maStops
.end());
387 sal_Int8
toByteColor( double val
)
389 // TODO(Q3): duplicated from vcl::unotools
390 return sal::static_int_cast
<sal_Int8
>(
391 basegfx::fround(val
*255.0));
394 rtl::OUString
getOdfColor( const ARGBColor
& rColor
)
396 // TODO(Q3): duplicated from pdfimport
397 rtl::OUStringBuffer
aBuf( 7 );
398 const sal_uInt8
nRed ( toByteColor(rColor
.r
) );
399 const sal_uInt8
nGreen( toByteColor(rColor
.g
) );
400 const sal_uInt8
nBlue ( toByteColor(rColor
.b
) );
401 aBuf
.append( sal_Unicode('#') );
403 aBuf
.append( sal_Unicode('0') );
404 aBuf
.append( sal_Int32(nRed
), 16 );
406 aBuf
.append( sal_Unicode('0') );
407 aBuf
.append( sal_Int32(nGreen
), 16 );
409 aBuf
.append( sal_Unicode('0') );
410 aBuf
.append( sal_Int32(nBlue
), 16 );
412 // TODO(F3): respect alpha transparency (polygons etc.)
413 OSL_ASSERT(rColor
.a
== 1.0);
415 return aBuf
.makeStringAndClear();
418 rtl::OUString
getOdfAlign( TextAlign eAlign
)
420 static ::rtl::OUString
aStart(USTR("start"));
421 static ::rtl::OUString
aEnd(USTR("end"));
422 // static ::rtl::OUString aJustify(USTR("justify"));
423 static ::rtl::OUString
aCenter(USTR("center"));
436 bool writeStyle(State
& rState
, const sal_Int32 nTagId
)
438 rtl::Reference
<SvXMLAttributeList
> xAttrs( new SvXMLAttributeList() );
439 uno::Reference
<xml::sax::XAttributeList
> xUnoAttrs( xAttrs
.get() );
441 std::pair
<StatePool::iterator
,
442 bool> aRes
= mrStates
.insert(rState
);
444 return false; // not written
448 // mnStyleId does not take part in hashing/comparison
449 const_cast<State
&>(*aRes
.first
).mnStyleId
= mnCurrStateId
;
450 mrStateMap
.insert(std::make_pair(
454 // find two representative stop colors (as odf only support
456 optimizeGradientStops(rState
.maFillGradient
);
458 if( !mxDocumentHandler
.is() )
459 return true; // cannot write style, svm import case
461 // do we have a gradient fill? then write out gradient as well
462 if( rState
.meFillType
== GRADIENT
&& rState
.maFillGradient
.maStops
.size() > 1 )
464 // TODO(F3): ODF12 supposedly also groks svg:linear/radialGradient. But CL says: nope.
465 xAttrs
->AddAttribute( USTR( "draw:name" ), getStyleName("svggradient", rState
.maFillGradient
.mnId
) );
466 if( rState
.maFillGradient
.meType
== Gradient::LINEAR
)
468 // should the optimizeGradientStops method decide that
469 // this is a three-color gradient, it prolly wanted us
470 // to take axial instead
471 xAttrs
->AddAttribute( USTR( "draw:style" ),
472 rState
.maFillGradient
.maStops
.size() == 3 ?
478 xAttrs
->AddAttribute( USTR( "draw:style" ), USTR("ellipsoid") );
479 xAttrs
->AddAttribute( USTR( "draw:cx" ), USTR("50%") );
480 xAttrs
->AddAttribute( USTR( "draw:cy" ), USTR("50%") );
483 basegfx::B2DTuple rScale
, rTranslate
;
484 double rRotate
, rShearX
;
485 if( rState
.maFillGradient
.maTransform
.decompose(rScale
, rTranslate
, rRotate
, rShearX
) )
486 xAttrs
->AddAttribute( USTR( "draw:angle" ),
487 rtl::OUString::valueOf(rRotate
*1800.0/M_PI
) );
488 xAttrs
->AddAttribute( USTR( "draw:start-color" ),
490 maGradientStopVector
[
491 rState
.maFillGradient
.maStops
[0]].maStopColor
) );
492 xAttrs
->AddAttribute( USTR( "draw:end-color" ),
494 maGradientStopVector
[
495 rState
.maFillGradient
.maStops
[1]].maStopColor
) );
496 xAttrs
->AddAttribute( USTR( "draw:border" ), USTR("0%") );
497 mxDocumentHandler
->startElement( USTR("draw:gradient"),
499 mxDocumentHandler
->endElement( USTR("draw:gradient") );
501 if( hasGradientOpacity(rState
.maFillGradient
) )
503 // need to write out opacity style as well
505 xAttrs
->AddAttribute( USTR( "draw:name" ), getStyleName("svgopacity", rState
.maFillGradient
.mnId
) );
506 if( rState
.maFillGradient
.meType
== Gradient::LINEAR
)
508 xAttrs
->AddAttribute( USTR( "draw:style" ), USTR("linear") );
512 xAttrs
->AddAttribute( USTR( "draw:style" ), USTR("ellipsoid") );
513 xAttrs
->AddAttribute( USTR( "draw:cx" ), USTR("50%") );
514 xAttrs
->AddAttribute( USTR( "draw:cy" ), USTR("50%") );
517 // modulate gradient opacity with overall fill opacity
518 xAttrs
->AddAttribute( USTR( "draw:end" ),
519 rtl::OUString::valueOf(
520 maGradientStopVector
[
521 rState
.maFillGradient
.maStops
[0]].maStopColor
.a
*
522 maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
*100.0)+USTR("%" ) );
523 xAttrs
->AddAttribute( USTR( "draw:start" ),
524 rtl::OUString::valueOf(
525 maGradientStopVector
[
526 rState
.maFillGradient
.maStops
[1]].maStopColor
.a
*
527 maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
*100.0)+USTR("%" ) );
528 xAttrs
->AddAttribute( USTR( "draw:border" ), USTR("0%") );
529 mxDocumentHandler
->startElement( USTR("draw:opacity"),
531 mxDocumentHandler
->endElement( USTR("draw:opacity") );
535 // serialize to automatic-style section
536 if( nTagId
== XML_TEXT
)
538 // write paragraph style attributes
541 xAttrs
->AddAttribute( USTR( "style:name" ), getStyleName("svgparagraphstyle", mnCurrStateId
) );
542 xAttrs
->AddAttribute( USTR( "style:family" ), USTR("paragraph") );
543 mxDocumentHandler
->startElement( USTR("style:style"),
547 xAttrs
->AddAttribute( USTR( "fo:text-align"), getOdfAlign(rState
.meTextAnchor
));
549 mxDocumentHandler
->startElement( USTR("style:paragraph-properties"),
551 mxDocumentHandler
->endElement( USTR("style:paragraph-properties") );
552 mxDocumentHandler
->endElement( USTR("style:style") );
554 // write text style attributes
557 xAttrs
->AddAttribute( USTR( "style:name" ), getStyleName("svgtextstyle", mnCurrStateId
) );
558 xAttrs
->AddAttribute( USTR( "style:family" ), USTR("text") );
559 mxDocumentHandler
->startElement( USTR("style:style"),
562 xAttrs
->AddAttribute( USTR( "fo:font-family"), rState
.maFontFamily
);
563 xAttrs
->AddAttribute( USTR( "fo:font-size"),
564 rtl::OUString::valueOf(pt2mm(rState
.mnFontSize
))+USTR("mm"));
565 xAttrs
->AddAttribute( USTR( "fo:font-style"), rState
.maFontStyle
);
566 xAttrs
->AddAttribute( USTR( "fo:font-variant"), rState
.maFontVariant
);
567 xAttrs
->AddAttribute( USTR( "fo:font-weight"),
568 rtl::OUString::valueOf(rState
.mnFontWeight
));
569 xAttrs
->AddAttribute( USTR( "fo:color"), getOdfColor(rState
.maFillColor
));
571 mxDocumentHandler
->startElement( USTR("style:text-properties"),
573 mxDocumentHandler
->endElement( USTR("style:text-properties") );
574 mxDocumentHandler
->endElement( USTR("style:style") );
578 xAttrs
->AddAttribute( USTR( "style:name" ), getStyleName("svggraphicstyle", mnCurrStateId
) );
579 xAttrs
->AddAttribute( USTR( "style:family" ), USTR("graphic") );
580 mxDocumentHandler
->startElement( USTR("style:style"),
584 // text or shape? if the former, no use in processing any
585 // graphic attributes except stroke color, ODF can do ~nothing
587 if( nTagId
== XML_TEXT
)
589 //xAttrs->AddAttribute( USTR( "draw:auto-grow-height"), USTR("true"));
590 xAttrs
->AddAttribute( USTR( "draw:auto-grow-width"), USTR("true"));
591 xAttrs
->AddAttribute( USTR( "draw:textarea-horizontal-align"), USTR("left"));
592 //xAttrs->AddAttribute( USTR( "draw:textarea-vertical-align"), USTR("top"));
593 xAttrs
->AddAttribute( USTR( "fo:min-height"), USTR("0cm"));
595 xAttrs
->AddAttribute( USTR( "fo:padding-top"), USTR("0cm"));
596 xAttrs
->AddAttribute( USTR( "fo:padding-left"), USTR("0cm"));
597 xAttrs
->AddAttribute( USTR( "fo:padding-right"), USTR("0cm"));
598 xAttrs
->AddAttribute( USTR( "fo:padding-bottom"), USTR("0cm"));
600 // disable any background shape
601 xAttrs
->AddAttribute( USTR( "draw:stroke" ), USTR("none"));
602 xAttrs
->AddAttribute( USTR( "draw:fill" ), USTR("none"));
606 if( rState
.meFillType
!= NONE
)
608 if( rState
.meFillType
== GRADIENT
)
610 xAttrs
->AddAttribute( USTR( "draw:fill" ), USTR("gradient"));
611 xAttrs
->AddAttribute( USTR( "draw:fill-gradient-name" ),
612 getStyleName("svggradient", rState
.maFillGradient
.mnId
) );
613 if( hasGradientOpacity(rState
.maFillGradient
) )
615 // needs transparency gradient as well
616 xAttrs
->AddAttribute( USTR( "draw:opacity-name" ),
617 getStyleName("svgopacity", rState
.maFillGradient
.mnId
) );
619 else if( maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
!= 1.0 )
620 xAttrs
->AddAttribute( USTR( "draw:opacity" ),
621 rtl::OUString::valueOf(100.0*maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
)+USTR("%") );
625 xAttrs
->AddAttribute( USTR( "draw:fill" ), USTR("solid"));
626 xAttrs
->AddAttribute( USTR( "draw:fill-color" ), getOdfColor(rState
.maFillColor
));
627 if( maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
!= 1.0 )
628 xAttrs
->AddAttribute( USTR( "draw:opacity" ),
629 rtl::OUString::valueOf(100.0*maCurrState
.mnFillOpacity
*maCurrState
.mnOpacity
)+USTR("%") );
633 xAttrs
->AddAttribute( USTR( "draw:fill" ), USTR("none"));
635 if( rState
.meStrokeType
!= NONE
)
637 xAttrs
->AddAttribute( USTR( "draw:stroke" ), USTR("solid"));
638 xAttrs
->AddAttribute( USTR( "svg:stroke-color" ), getOdfColor(rState
.maStrokeColor
));
641 xAttrs
->AddAttribute( USTR( "draw:stroke" ), USTR("none"));
643 if( maCurrState
.mnStrokeWidth
!= 0.0 )
645 ::basegfx::B2DVector
aVec(maCurrState
.mnStrokeWidth
,0);
646 aVec
*= maCurrState
.maCTM
;
647 xAttrs
->AddAttribute( USTR("svg:stroke-width"), rtl::OUString::valueOf( pt2mm(aVec
.getLength()) )+USTR("mm"));
649 if( maCurrState
.meLineJoin
== basegfx::B2DLINEJOIN_MITER
)
650 xAttrs
->AddAttribute( USTR( "draw:stroke-linejoin"), USTR("miter"));
651 else if( maCurrState
.meLineJoin
== basegfx::B2DLINEJOIN_ROUND
)
652 xAttrs
->AddAttribute( USTR( "draw:stroke-linejoin"), USTR("round"));
653 else if( maCurrState
.meLineJoin
== basegfx::B2DLINEJOIN_BEVEL
)
654 xAttrs
->AddAttribute( USTR( "draw:stroke-linejoin"), USTR("bevel"));
655 if( maCurrState
.mnStrokeOpacity
*maCurrState
.mnOpacity
!= 1.0 )
656 xAttrs
->AddAttribute( USTR("svg:stroke-opacity"),
657 rtl::OUString::valueOf(100.0*maCurrState
.mnStrokeOpacity
*maCurrState
.mnOpacity
)+USTR("%"));
660 mxDocumentHandler
->startElement( USTR("style:graphic-properties"),
662 mxDocumentHandler
->endElement( USTR("style:graphic-properties") );
663 mxDocumentHandler
->endElement( USTR("style:style") );
665 return true; // newly written
668 void writeStyle(const uno::Reference
<xml::dom::XElement
>& xElem
, const sal_Int32 nTagId
)
670 sal_Int32 nEmulatedStyleId
=0;
671 if( maCurrState
.maDashArray
.size() &&
672 maCurrState
.meStrokeType
!= NONE
)
674 // ODF dashing is severly borked - generate filled shape
675 // instead (further down the road - here, we simply
676 // emulate a filled style with the next id)
678 // move all stroke attribs to fill, Clear stroking
679 State
aEmulatedStrokeState( maCurrState
);
680 aEmulatedStrokeState
.meFillType
= maCurrState
.meStrokeType
;
681 aEmulatedStrokeState
.mnFillOpacity
= maCurrState
.mnStrokeOpacity
;
682 aEmulatedStrokeState
.maFillColor
= maCurrState
.maStrokeColor
;
683 aEmulatedStrokeState
.maFillGradient
= maCurrState
.maStrokeGradient
;
684 aEmulatedStrokeState
.meFillRule
= EVEN_ODD
;
685 aEmulatedStrokeState
.meStrokeType
= NONE
;
687 if( writeStyle(aEmulatedStrokeState
, nTagId
) )
688 nEmulatedStyleId
= mnCurrStateId
;
690 nEmulatedStyleId
= mrStates
.find(aEmulatedStrokeState
)->mnStyleId
;
693 sal_Int32 nStyleId
=0;
694 if( writeStyle(maCurrState
, nTagId
) )
695 nStyleId
= mnCurrStateId
;
697 nStyleId
= mrStates
.find(maCurrState
)->mnStyleId
;
699 xElem
->setAttribute(USTR("internal-style-ref"),
700 rtl::OUString::valueOf(
703 +rtl::OUString::valueOf(
709 maParentStates
.push_back(maCurrState
);
714 maParentStates
.pop_back();
717 void parseLinearGradientData( Gradient
& io_rCurrGradient
,
718 const sal_Int32 nGradientNumber
,
719 const sal_Int32 nTokenId
,
720 const rtl::OUString
& sValue
)
724 case XML_GRADIENTTRANSFORM
:
726 rtl::OString
aValueUtf8( sValue
.getStr(),
728 RTL_TEXTENCODING_UTF8
);
729 parseTransform(aValueUtf8
.getStr(),io_rCurrGradient
.maTransform
);
733 io_rCurrGradient
.maCoords
.linear
.mfX1
= convLength(sValue
,maCurrState
,'h');
736 io_rCurrGradient
.maCoords
.linear
.mfX2
= convLength(sValue
,maCurrState
,'h');
739 io_rCurrGradient
.maCoords
.linear
.mfY1
= convLength(sValue
,maCurrState
,'v');
742 io_rCurrGradient
.maCoords
.linear
.mfY2
= convLength(sValue
,maCurrState
,'v');
745 maGradientIdMap
.insert(std::make_pair(sValue
,nGradientNumber
));
747 case XML_GRADIENTUNITS
:
748 if (getTokenId(sValue
) == XML_OBJECTBOUNDINGBOX
)
749 io_rCurrGradient
.mbBoundingBoxUnits
= true;
751 io_rCurrGradient
.mbBoundingBoxUnits
= false;
758 void parseRadialGradientData( Gradient
& io_rCurrGradient
,
759 const sal_Int32 nGradientNumber
,
760 const sal_Int32 nTokenId
,
761 const rtl::OUString
& sValue
)
765 case XML_GRADIENTTRANSFORM
:
767 rtl::OString
aValueUtf8( sValue
.getStr(),
769 RTL_TEXTENCODING_UTF8
);
770 parseTransform(aValueUtf8
.getStr(),io_rCurrGradient
.maTransform
);
774 io_rCurrGradient
.maCoords
.radial
.mfCX
= convLength(sValue
,maCurrState
,'h');
777 io_rCurrGradient
.maCoords
.radial
.mfCY
= convLength(sValue
,maCurrState
,'v');
780 io_rCurrGradient
.maCoords
.radial
.mfFX
= convLength(sValue
,maCurrState
,'h');
783 io_rCurrGradient
.maCoords
.radial
.mfFY
= convLength(sValue
,maCurrState
,'v');
786 io_rCurrGradient
.maCoords
.radial
.mfR
= convLength(sValue
,maCurrState
,'r');
789 maGradientIdMap
.insert(std::make_pair(sValue
,nGradientNumber
));
791 case XML_GRADIENTUNITS
:
792 if (getTokenId(sValue
) == XML_OBJECTBOUNDINGBOX
)
793 io_rCurrGradient
.mbBoundingBoxUnits
= true;
795 io_rCurrGradient
.mbBoundingBoxUnits
= false;
802 void parseGradientStop( GradientStop
& io_rGradientStop
,
803 const sal_Int32 nStopNumber
,
804 const sal_Int32 nTokenId
,
805 const rtl::OUString
& sValue
)
811 ElementRefMapType::iterator aFound
=maStopIdMap
.end();
812 if (sValue
.copy(0,1).equalsAscii("#"))
813 aFound
= maStopIdMap
.find(sValue
.copy(1));
815 aFound
= maStopIdMap
.find(sValue
);;
817 if( aFound
!= maStopIdMap
.end() )
818 io_rGradientStop
= maGradientStopVector
[aFound
->second
];
822 maStopIdMap
.insert(std::make_pair(sValue
,nStopNumber
));
825 io_rGradientStop
.mnStopPosition
= sValue
.toDouble();
828 parseStyle( sValue
);
835 void parseAttribute( const sal_Int32 nTokenId
,
836 const rtl::OUString
& sValue
)
838 rtl::OString
aValueUtf8( sValue
.getStr(),
840 RTL_TEXTENCODING_UTF8
);
845 const double fViewPortWidth(
846 convLength(sValue
,maCurrState
,'h'));
848 maCurrState
.maViewport
.expand(
849 basegfx::B2DTuple(fViewPortWidth
,0.0));
854 const double fViewPortHeight(
855 convLength(sValue
,maCurrState
,'v'));
857 maCurrState
.maViewport
.expand(
858 basegfx::B2DTuple(0.0,fViewPortHeight
));
863 // TODO(F1): preserveAspectRatio
866 maCurrState
.maViewBox
);
871 if( aValueUtf8
== "evenodd" )
872 maCurrState
.meFillRule
= EVEN_ODD
;
873 else if( aValueUtf8
== "nonzero" )
874 maCurrState
.meFillRule
= NON_ZERO
;
875 else if( aValueUtf8
== "inherit" )
876 maCurrState
.meFillRule
= maParentStates
.back().meFillRule
;
880 if( aValueUtf8
== "inherit" )
881 maCurrState
.mnOpacity
= maParentStates
.back().mnOpacity
;
883 maCurrState
.mnOpacity
= aValueUtf8
.toDouble();
885 case XML_FILL_OPACITY
:
886 if( aValueUtf8
== "inherit" )
887 maCurrState
.mnFillOpacity
= maParentStates
.back().mnFillOpacity
;
889 maCurrState
.mnFillOpacity
= aValueUtf8
.toDouble();
891 case XML_STROKE_WIDTH
:
893 if( aValueUtf8
== "inherit" )
894 maCurrState
.mnStrokeWidth
= maParentStates
.back().mnStrokeWidth
;
896 maCurrState
.mnStrokeWidth
= convLength(sValue
,maCurrState
,'r');
899 case XML_STROKE_LINECAP
:
901 if( aValueUtf8
== "butt" )
902 maCurrState
.meLineCap
= BUTT
;
903 else if( aValueUtf8
== "round" )
904 maCurrState
.meLineCap
= ROUND
;
905 else if( aValueUtf8
== "square" )
906 maCurrState
.meLineCap
= RECT
;
907 else if( aValueUtf8
== "inherit" )
908 maCurrState
.meLineCap
= maParentStates
.back().meLineCap
;
911 case XML_STROKE_LINEJOIN
:
913 if( aValueUtf8
== "miter" )
914 maCurrState
.meLineJoin
= basegfx::B2DLINEJOIN_MITER
;
915 else if( aValueUtf8
== "round" )
916 maCurrState
.meLineJoin
= basegfx::B2DLINEJOIN_ROUND
;
917 else if( aValueUtf8
== "bevel" )
918 maCurrState
.meLineJoin
= basegfx::B2DLINEJOIN_BEVEL
;
919 else if( aValueUtf8
== "inherit" )
920 maCurrState
.meLineJoin
= maParentStates
.back().meLineJoin
;
923 case XML_STROKE_MITERLIMIT
:
925 if( aValueUtf8
== "inherit" )
926 maCurrState
.mnMiterLimit
= maParentStates
.back().mnMiterLimit
;
928 maCurrState
.mnMiterLimit
= aValueUtf8
.toDouble();
931 case XML_STROKE_DASHOFFSET
:
933 if( aValueUtf8
== "inherit" )
934 maCurrState
.mnDashOffset
= maParentStates
.back().mnDashOffset
;
936 maCurrState
.mnDashOffset
= convLength(sValue
,maCurrState
,'r');
939 case XML_STROKE_DASHARRAY
:
941 if( aValueUtf8
== "none" )
942 maCurrState
.maDashArray
.clear();
943 else if( aValueUtf8
== "inherit" )
944 maCurrState
.maDashArray
= maParentStates
.back().maDashArray
;
946 parseDashArray(aValueUtf8
.getStr(),
947 maCurrState
.maDashArray
);
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 basegfx::B2DHomMatrix aTransform
;
985 parseTransform(aValueUtf8
.getStr(),aTransform
);
986 maCurrState
.maTransform
= maCurrState
.maTransform
*aTransform
;
989 case XML_FONT_FAMILY
:
990 maCurrState
.maFontFamily
=sValue
;
993 maCurrState
.mnFontSize
=convLength(sValue
,maCurrState
,'v');
996 parseFontStyle(maCurrState
,sValue
,aValueUtf8
.getStr());
998 case XML_FONT_WEIGHT
:
999 maCurrState
.mnFontWeight
=sValue
.toDouble();
1001 case XML_FONT_VARIANT
:
1002 parseFontVariant(maCurrState
,sValue
,aValueUtf8
.getStr());
1004 case XML_TEXT_ANCHOR
:
1005 parseTextAlign(maCurrState
,aValueUtf8
.getStr());
1007 case XML_STOP_COLOR
:
1008 if( maGradientVector
.empty() ||
1009 maGradientVector
.back().maStops
.empty() )
1011 parseColor( aValueUtf8
,
1012 maGradientStopVector
[
1013 maGradientVector
.back().maStops
.back()].maStopColor
);
1015 case XML_STOP_OPACITY
:
1016 if( maGradientVector
.empty() ||
1017 maGradientVector
.back().maStops
.empty() )
1019 parseOpacity( aValueUtf8
,
1020 maGradientStopVector
[
1021 maGradientVector
.back().maStops
.back()].maStopColor
);
1024 OSL_TRACE("unhandled token %s", getTokenName(nTokenId
));
1029 void parseStyle( const rtl::OUString
& sValue
)
1031 // split individual style attributes
1032 sal_Int32 nIndex
=0, nDummyIndex
=0;
1033 rtl::OUString aCurrToken
;
1036 aCurrToken
=sValue
.getToken(0,';',nIndex
);
1038 if( aCurrToken
.getLength() )
1040 // split attrib & value
1042 rtl::OUString
aCurrAttrib(
1043 aCurrToken
.getToken(0,':',nDummyIndex
).trim());
1044 OSL_ASSERT(nDummyIndex
!=-1);
1046 rtl::OUString
aCurrValue(
1047 aCurrToken
.getToken(1,':',nDummyIndex
).trim());
1048 OSL_ASSERT(nDummyIndex
==-1);
1050 // recurse into normal attribute parsing
1051 parseAttribute( getTokenId(aCurrAttrib
),
1055 while( nIndex
!= -1 );
1058 void parseFontStyle( State
& io_rInitialState
,
1059 const rtl::OUString
& rValue
,
1060 const char* sValue
)
1062 if( strcmp(sValue
,"inherit") != 0 )
1063 io_rInitialState
.maFontStyle
= rValue
;
1066 void parseFontVariant( State
& io_rInitialState
,
1067 const rtl::OUString
& rValue
,
1068 const char* sValue
)
1070 if( strcmp(sValue
,"inherit") != 0 )
1071 io_rInitialState
.maFontVariant
= rValue
;
1074 void parseTextAlign( State
& io_rInitialState
,
1075 const char* sValue
)
1077 if( strcmp(sValue
,"start") == 0 )
1078 io_rInitialState
.meTextAnchor
= BEFORE
;
1079 else if( strcmp(sValue
,"middle") == 0 )
1080 io_rInitialState
.meTextAnchor
= CENTER
;
1081 else if( strcmp(sValue
,"end") == 0 )
1082 io_rInitialState
.meTextAnchor
= AFTER
;
1083 // keep current val for sValue == "inherit"
1086 void parsePaint( const rtl::OUString
& rValue
,
1090 Gradient
& rGradient
,
1091 const PaintType
& rInheritType
,
1092 const ARGBColor
& rInheritColor
,
1093 const Gradient
& rInheritGradient
)
1095 std::pair
<const char*,const char*> aPaintUri(NULL
,NULL
);
1096 std::pair
<ARGBColor
,bool> aColor(maCurrState
.maCurrentColor
,
1098 if( strcmp(sValue
,"none") == 0 )
1100 else if( strcmp(sValue
,"currentColor") == 0 )
1103 rColor
= maCurrState
.maCurrentColor
;
1105 else if( strcmp(sValue
,"inherit") == 0)
1107 rType
= rInheritType
;
1108 rColor
= rInheritColor
;
1109 rGradient
= rInheritGradient
;
1111 else if( parsePaintUri(aPaintUri
,aColor
,sValue
) )
1113 if( aPaintUri
.first
!= aPaintUri
.second
)
1115 // assuming gradient. assumption does not hold generally
1116 const char* pClosingBracket
;
1117 if( (pClosingBracket
=strstr(sValue
,")")) && rValue
.getLength() > 5 )
1119 ElementRefMapType::iterator aRes
;
1120 if( (aRes
=maGradientIdMap
.find(
1121 rValue
.copy(aPaintUri
.first
-sValue
,
1122 aPaintUri
.second
-aPaintUri
.first
))) != maGradientIdMap
.end() )
1124 rGradient
= maGradientVector
[aRes
->second
];
1129 else if( aColor
.second
)
1132 rColor
= aColor
.first
;
1142 parseColor(sValue
,rColor
);
1146 sal_Int32 mnCurrStateId
;
1148 std::vector
<State
> maParentStates
;
1149 StatePool
& mrStates
;
1150 StateMap
& mrStateMap
;
1151 uno::Reference
<xml::sax::XDocumentHandler
> mxDocumentHandler
;
1152 std::vector
< Gradient
> maGradientVector
;
1153 std::vector
< GradientStop
> maGradientStopVector
;
1154 ElementRefMapType maGradientIdMap
;
1155 ElementRefMapType maStopIdMap
;
1158 /// Annotate svg styles with unique references to state pool
1159 static void annotateStyles( StatePool
& rStatePool
,
1160 StateMap
& rStateMap
,
1161 const State
& rInitialState
,
1162 const uno::Reference
<xml::dom::XElement
> xElem
,
1163 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocHdl
)
1165 AnnotatingVisitor
aVisitor(rStatePool
,rStateMap
,rInitialState
,xDocHdl
);
1166 visitElements(aVisitor
, xElem
);
1169 struct ShapeWritingVisitor
1171 ShapeWritingVisitor(StatePool
& /*rStatePool*/,
1172 StateMap
& rStateMap
,
1173 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
) :
1174 mrStateMap(rStateMap
),
1175 mxDocumentHandler(xDocumentHandler
),
1179 void operator()( const uno::Reference
<xml::dom::XElement
>& )
1183 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
,
1184 const uno::Reference
<xml::dom::XNamedNodeMap
>& xAttributes
)
1186 rtl::Reference
<SvXMLAttributeList
> xAttrs( new SvXMLAttributeList() );
1187 uno::Reference
<xml::sax::XAttributeList
> xUnoAttrs( xAttrs
.get() );
1189 sal_Int32
nDummyIndex(0);
1190 rtl::OUString
sStyleId(
1191 xElem
->getAttribute(
1192 USTR("internal-style-ref")).getToken(
1193 0,'$',nDummyIndex
));
1194 StateMap::iterator pOrigState
=mrStateMap
.find(
1195 sStyleId
.toInt32());
1197 if( pOrigState
== mrStateMap
.end() )
1198 return; // non-exportable element, e.g. linearGradient
1200 maCurrState
= pOrigState
->second
;
1202 const sal_Int32
nTokenId(getTokenId(xElem
->getNodeName()));
1207 // collect attributes
1208 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1209 rtl::OUString sAttributeValue
;
1210 double x1
=0.0,y1
=0.0,x2
=0.0,y2
=0.0;
1211 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1213 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1214 const sal_Int32
nAttribId(
1215 getTokenId(xAttributes
->item(i
)->getNodeName()));
1219 x1
= convLength(sAttributeValue
,maCurrState
,'h');
1222 x2
= convLength(sAttributeValue
,maCurrState
,'h');
1225 y1
= convLength(sAttributeValue
,maCurrState
,'v');
1228 y2
= convLength(sAttributeValue
,maCurrState
,'v');
1236 rtl::OUString sLinePath
= USTR("M")+rtl::OUString::valueOf(x1
)+USTR(",")
1237 +rtl::OUString::valueOf(y1
)+USTR("L")+rtl::OUString::valueOf(x2
)+USTR(",")
1238 +rtl::OUString::valueOf(y2
);
1239 basegfx::B2DPolyPolygon aPoly
;
1240 basegfx::tools::importFromSvgD(aPoly
, sLinePath
);
1242 writePathShape(xAttrs
,
1246 basegfx::B2DPolyPolygon(aPoly
));
1252 rtl::OUString sPoints
= xElem
->hasAttribute(USTR("points")) ? xElem
->getAttribute(USTR("points")) : USTR("");
1253 basegfx::B2DPolygon aPoly
;
1254 basegfx::tools::importFromSvgPoints(aPoly
, sPoints
);
1255 if( nTokenId
== XML_POLYGON
|| maCurrState
.meFillType
!= NONE
)
1256 aPoly
.setClosed(true);
1258 writePathShape(xAttrs
,
1262 basegfx::B2DPolyPolygon(aPoly
));
1267 // collect attributes
1268 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1269 rtl::OUString sAttributeValue
;
1270 bool bRxSeen
=false, bRySeen
=false;
1271 double x
=0.0,y
=0.0,width
=0.0,height
=0.0,rx
=0.0,ry
=0.0;
1272 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1274 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1275 const sal_Int32
nAttribId(
1276 getTokenId(xAttributes
->item(i
)->getNodeName()));
1280 x
= convLength(sAttributeValue
,maCurrState
,'h');
1283 y
= convLength(sAttributeValue
,maCurrState
,'v');
1286 width
= convLength(sAttributeValue
,maCurrState
,'h');
1289 height
= convLength(sAttributeValue
,maCurrState
,'v');
1292 rx
= convLength(sAttributeValue
,maCurrState
,'h');
1296 ry
= convLength(sAttributeValue
,maCurrState
,'v');
1305 if( bRxSeen
&& !bRySeen
)
1307 else if( bRySeen
&& !bRxSeen
)
1310 basegfx::B2DPolygon aPoly
;
1311 aPoly
= basegfx::tools::createPolygonFromRect(
1312 basegfx::B2DRange(x
,y
,x
+width
,y
+height
),
1313 rx
/width
, ry
/height
);
1315 writePathShape(xAttrs
,
1319 basegfx::B2DPolyPolygon(aPoly
));
1324 rtl::OUString sPath
= xElem
->hasAttribute(USTR("d")) ? xElem
->getAttribute(USTR("d")) : USTR("");
1325 basegfx::B2DPolyPolygon aPoly
;
1326 basegfx::tools::importFromSvgD(aPoly
, sPath
);
1328 writePathShape(xAttrs
,
1337 // collect attributes
1338 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1339 rtl::OUString sAttributeValue
;
1340 double cx
=0.0,cy
=0.0,r
=0.0;
1341 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1343 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1344 const sal_Int32
nAttribId(
1345 getTokenId(xAttributes
->item(i
)->getNodeName()));
1349 cx
= convLength(sAttributeValue
,maCurrState
,'h');
1352 cy
= convLength(sAttributeValue
,maCurrState
,'v');
1355 r
= convLength(sAttributeValue
,maCurrState
,'r');
1362 writeEllipseShape(xAttrs
,
1366 basegfx::B2DEllipse(basegfx::B2DPoint(cx
, cy
), basegfx::B2DTuple(r
,r
)));
1371 // collect attributes
1372 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1373 rtl::OUString sAttributeValue
;
1374 double cx
=0.0,cy
=0.0,rx
=0.0, ry
=0.0;
1375 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1377 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1378 const sal_Int32
nAttribId(
1379 getTokenId(xAttributes
->item(i
)->getNodeName()));
1383 cx
= convLength(sAttributeValue
,maCurrState
,'h');
1386 cy
= convLength(sAttributeValue
,maCurrState
,'v');
1389 rx
= convLength(sAttributeValue
,maCurrState
,'h');
1392 ry
= convLength(sAttributeValue
,maCurrState
,'v');
1399 writeEllipseShape(xAttrs
,
1403 basegfx::B2DEllipse(basegfx::B2DPoint(cx
, cy
), basegfx::B2DTuple(rx
,ry
)));
1408 // collect attributes
1409 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1410 rtl::OUString sAttributeValue
;
1411 double x
=0.0,y
=0.0,width
=0.0,height
=0.0;
1412 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1414 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1415 const sal_Int32
nAttribId(
1416 getTokenId(xAttributes
->item(i
)->getNodeName()));
1420 x
= convLength(sAttributeValue
,maCurrState
,'h');
1423 y
= convLength(sAttributeValue
,maCurrState
,'v');
1426 width
= convLength(sAttributeValue
,maCurrState
,'h');
1429 height
= convLength(sAttributeValue
,maCurrState
,'v');
1437 rtl::OUString sValue
= xElem
->hasAttribute(USTR("href")) ? xElem
->getAttribute(USTR("href")) : USTR("");
1438 rtl::OString
aValueUtf8( sValue
.getStr(), sValue
.getLength(), RTL_TEXTENCODING_UTF8
);
1439 std::string sLinkValue
;
1440 parseXlinkHref(aValueUtf8
.getStr(), sLinkValue
);
1442 if (!sLinkValue
.empty())
1443 writeBinaryData(xAttrs
, xUnoAttrs
, xElem
, basegfx::B2DRange(x
,y
,x
+width
,y
+height
), sLinkValue
);
1448 // collect text from all TEXT_NODE children into sText
1449 rtl::OUStringBuffer sText
;
1450 visitChildren(boost::bind(
1451 (rtl::OUStringBuffer
& (rtl::OUStringBuffer::*)(const sal_Unicode
* str
))&rtl::OUStringBuffer::append
,
1453 boost::bind(&xml::dom::XNode::getNodeValue
,
1456 xml::dom::NodeType_TEXT_NODE
);
1458 // collect attributes
1459 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1460 rtl::OUString sAttributeValue
;
1461 double x
=0.0,y
=0.0,width
=0.0,height
=0.0;
1462 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1464 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
1465 const sal_Int32
nAttribId(
1466 getTokenId(xAttributes
->item(i
)->getNodeName()));
1470 x
= convLength(sAttributeValue
,maCurrState
,'h');
1473 y
= convLength(sAttributeValue
,maCurrState
,'v');
1476 width
= convLength(sAttributeValue
,maCurrState
,'h');
1479 height
= convLength(sAttributeValue
,maCurrState
,'v');
1487 // actually export text
1490 // some heuristic attempts to have text output
1491 // baseline-relative
1492 y
-= 2.0*maCurrState
.mnFontSize
/3.0;
1494 // extract basic transformations out of CTM
1495 basegfx::B2DTuple aScale
, aTranslate
;
1496 double fRotate
, fShearX
;
1497 ::rtl::OUString sTransformValue
;
1498 if (maCurrState
.maCTM
.decompose(aScale
, aTranslate
, fRotate
, fShearX
))
1500 rtl::OUString sTransform
;
1501 x
+= aTranslate
.getX();
1502 y
+= aTranslate
.getY();
1506 rtl::OUString::valueOf(aScale
.getX()) +
1508 rtl::OUString::valueOf(aScale
.getX()) +
1512 sTransform
+= USTR(" rotate(") + rtl::OUString::valueOf(fRotate
*180.0/M_PI
) + USTR(")");
1515 sTransform
+= USTR(" skewX(") + rtl::OUString::valueOf(fShearX
*180.0/M_PI
) + USTR(")");
1518 xAttrs
->AddAttribute( USTR( "svg:x" ), rtl::OUString::valueOf(pt2mm(x
))+USTR("mm"));
1519 xAttrs
->AddAttribute( USTR( "svg:y" ), rtl::OUString::valueOf(pt2mm(y
))+USTR("mm"));
1520 xAttrs
->AddAttribute( USTR( "draw:style-name" ), USTR("svggraphicstyle")+sStyleId
);
1522 mxDocumentHandler
->startElement(USTR("draw:frame"),xUnoAttrs
);
1525 mxDocumentHandler
->startElement(USTR("draw:text-box"),xUnoAttrs
);
1526 xAttrs
->AddAttribute( USTR( "text:style-name" ), USTR("svgparagraphstyle")+sStyleId
);
1527 mxDocumentHandler
->startElement(USTR("text:p"),xUnoAttrs
);
1530 xAttrs
->AddAttribute( USTR( "text:style-name" ), USTR("svgtextstyle")+sStyleId
);
1531 mxDocumentHandler
->startElement(USTR("text:span"),xUnoAttrs
);
1534 mxDocumentHandler
->characters(sText
.makeStringAndClear());
1535 mxDocumentHandler
->endElement(USTR("text:span"));
1536 mxDocumentHandler
->endElement(USTR("text:p"));
1537 mxDocumentHandler
->endElement(USTR("draw:text-box"));
1538 mxDocumentHandler
->endElement(USTR("draw:frame"));
1550 void writeBinaryData( rtl::Reference
<SvXMLAttributeList
>& xAttrs
,
1551 const uno::Reference
<xml::sax::XAttributeList
>& xUnoAttrs
,
1552 const uno::Reference
<xml::dom::XElement
>& /* xElem */,
1553 const basegfx::B2DRange
& rShapeBounds
,
1554 const std::string
& data
)
1557 xAttrs
->AddAttribute( USTR( "svg:x" ), rtl::OUString::valueOf(pt2mm(rShapeBounds
.getMinX()))+USTR("mm"));
1558 xAttrs
->AddAttribute( USTR( "svg:y" ), rtl::OUString::valueOf(pt2mm(rShapeBounds
.getMinY()))+USTR("mm"));
1559 xAttrs
->AddAttribute( USTR( "svg:width" ), rtl::OUString::valueOf(pt2mm(rShapeBounds
.getWidth()))+USTR("mm"));
1560 xAttrs
->AddAttribute( USTR( "svg:height" ), rtl::OUString::valueOf(pt2mm(rShapeBounds
.getHeight()))+USTR("mm"));
1562 mxDocumentHandler
->startElement(USTR("draw:frame"),xUnoAttrs
);
1565 mxDocumentHandler
->startElement(USTR("draw:image"),xUnoAttrs
);
1567 mxDocumentHandler
->startElement(USTR("office:binary-data"),xUnoAttrs
);
1569 mxDocumentHandler
->characters(rtl::OUString::createFromAscii(data
.c_str()));
1571 mxDocumentHandler
->endElement(USTR("office:binary-data"));
1573 mxDocumentHandler
->endElement(USTR("draw:image"));
1575 mxDocumentHandler
->endElement(USTR("draw:frame"));
1579 void writeTransformAttribute(const basegfx::B2DHomMatrix rMatrix
, rtl::Reference
<SvXMLAttributeList
>& xAttrs
)
1581 basegfx::B2DTuple rScale
, rTranslate
;
1582 double rRotate
, rShearX
;
1583 ::rtl::OUString sTransformValue
;
1584 if (!rMatrix
.decompose(rScale
, rTranslate
, rRotate
, rShearX
))
1586 if (rScale
.getX() != 1.0 || rScale
.getY() != 1.0)
1587 sTransformValue
+= USTR("scale(")+::rtl::OUString::valueOf(rScale
.getX())+USTR(" ")
1588 +::rtl::OUString::valueOf(rScale
.getY())+USTR(") ");
1589 if (rTranslate
.getX() != 0.0f
|| rTranslate
.getY() != 0.0f
)
1590 sTransformValue
+= USTR("translate(")+::rtl::OUString::valueOf(rTranslate
.getX()/100.0f
)+USTR("mm ")
1591 +::rtl::OUString::valueOf(rTranslate
.getY()/100.0f
)+USTR("mm) ");
1592 if (rRotate
!= 0.0f
)
1593 sTransformValue
+= USTR("rotate(")+::rtl::OUString::valueOf(rRotate
)+USTR(") ");
1595 if (rShearX
!= 0.0f
)
1596 sTransformValue
+= USTR("skewX(")+::rtl::OUString::valueOf(rShearX
)+USTR(") ");
1597 if (!sTransformValue
.getLength())
1599 xAttrs
->AddAttribute( USTR("draw:transform"), sTransformValue
);
1602 void writeEllipseShape( rtl::Reference
<SvXMLAttributeList
>& xAttrs
,
1603 const uno::Reference
<xml::sax::XAttributeList
>& xUnoAttrs
,
1604 const uno::Reference
<xml::dom::XElement
>& xElem
,
1605 const rtl::OUString
& rStyleId
,
1606 const basegfx::B2DEllipse
& rEllipse
)
1608 State aState
= maCurrState
;
1609 rtl::OUString
aStyleId(rStyleId
);
1613 basegfx::B2DPolygon aPoly
= basegfx::tools::createPolygonFromEllipse(rEllipse
.getB2DEllipseCenter(),
1614 rEllipse
.getB2DEllipseRadius().getX(), rEllipse
.getB2DEllipseRadius().getY());
1615 writePathShape(xAttrs
, xUnoAttrs
, xElem
, rStyleId
, basegfx::B2DPolyPolygon(aPoly
));
1619 void writePathShape( rtl::Reference
<SvXMLAttributeList
>& xAttrs
,
1620 const uno::Reference
<xml::sax::XAttributeList
>& xUnoAttrs
,
1621 const uno::Reference
<xml::dom::XElement
>& xElem
,
1622 const rtl::OUString
& rStyleId
,
1623 const basegfx::B2DPolyPolygon
& rPoly
)
1625 // we might need to split up polypolygon into multiple path
1626 // shapes (e.g. when emulating line stroking)
1627 std::vector
<basegfx::B2DPolyPolygon
> aPolys(1,rPoly
);
1628 State aState
= maCurrState
;
1629 rtl::OUString
aStyleId(rStyleId
);
1633 OSL_TRACE("writePath - the CTM is: %f %f %f %f %f %f",
1634 maCurrState
.maCTM
.get(0,0),
1635 maCurrState
.maCTM
.get(0,1),
1636 maCurrState
.maCTM
.get(0,2),
1637 maCurrState
.maCTM
.get(1,0),
1638 maCurrState
.maCTM
.get(1,1),
1639 maCurrState
.maCTM
.get(1,2));
1641 if( aState
.maDashArray
.size() )
1643 // ODF dashing is severly borked - generate filled polygon instead
1645 for( sal_uInt32 i
=0; i
<rPoly
.count(); ++i
)
1648 basegfx::tools::stripNeutralPolygons(
1649 basegfx::tools::prepareForPolygonOperation(
1650 basegfx::tools::createAreaGeometry(
1651 rPoly
.getB2DPolygon(i
),
1652 aState
.mnStrokeWidth
/2.0,
1653 aState
.meLineJoin
))));
1654 // TODO(F2): line ends
1657 sal_Int32
nDummyIndex(0);
1658 aStyleId
= xElem
->getAttribute(
1659 USTR("internal-style-ref")).getToken(1,'$',nDummyIndex
);
1660 StateMap::iterator pAlternateState
=mrStateMap
.find(aStyleId
.toInt32());
1661 OSL_ASSERT(pAlternateState
!= mrStateMap
.end());
1662 aState
= pAlternateState
->second
;
1663 OSL_ENSURE( pAlternateState
== mrStateMap
.end(),
1664 "Doh - where's my alternate style entry?!" );
1667 // TODO(F2): separate out shear, rotate etc.
1668 // apply transformation to polygon, to keep draw
1669 // import in 100th mm
1670 std::for_each(aPolys
.begin(),aPolys
.end(),
1671 boost::bind(&basegfx::B2DPolyPolygon::transform
,
1672 _1
,boost::cref(aState
.maCTM
)));
1674 for( sal_uInt32 i
=0; i
<aPolys
.size(); ++i
)
1676 const basegfx::B2DRange
aBounds(
1677 aPolys
[i
].areControlPointsUsed() ?
1678 basegfx::tools::getRange(
1679 basegfx::tools::adaptiveSubdivideByAngle(aPolys
[i
])) :
1680 basegfx::tools::getRange(aPolys
[i
]));
1681 fillShapeProperties(xAttrs
,
1684 USTR("svggraphicstyle")+aStyleId
);
1686 // force path coordinates to 100th millimeter, after
1687 // putting polygon data at origin (odf viewbox
1688 // calculations largely untested codepaths, as OOo always
1689 // writes "0 0 w h" viewboxes)
1690 basegfx::B2DHomMatrix aNormalize
;
1691 aNormalize
.translate(-aBounds
.getMinX(),-aBounds
.getMinY());
1692 aNormalize
.scale(2540.0/72.0,2540.0/72.0);
1693 aPolys
[i
].transform(aNormalize
);
1695 xAttrs
->AddAttribute( USTR( "svg:d" ), basegfx::tools::exportToSvgD(
1697 false, // no relative coords. causes rounding errors
1698 false )); // no quad bezier detection. crashes older versions.
1699 mxDocumentHandler
->startElement(USTR("draw:path"),
1701 mxDocumentHandler
->endElement(USTR("draw:path"));
1705 void fillShapeProperties( rtl::Reference
<SvXMLAttributeList
>& xAttrs
,
1706 const uno::Reference
<xml::dom::XElement
>& /* xElem */,
1707 const basegfx::B2DRange
& rShapeBounds
,
1708 const rtl::OUString
& rStyleName
)
1710 xAttrs
->AddAttribute( USTR( "draw:z-index" ), rtl::OUString::valueOf( mnShapeNum
++ ));
1711 xAttrs
->AddAttribute( USTR( "draw:style-name" ), rStyleName
);
1712 xAttrs
->AddAttribute( USTR( "svg:width" ), rtl::OUString::valueOf(pt2mm(rShapeBounds
.getWidth()))+USTR("mm"));
1713 xAttrs
->AddAttribute( USTR( "svg:height" ), rtl::OUString::valueOf(pt2mm(rShapeBounds
.getHeight()))+USTR("mm"));
1715 // OOo expects the viewbox to be in 100th of mm
1716 xAttrs
->AddAttribute( USTR( "svg:viewBox" ),
1718 + rtl::OUString::valueOf(
1719 basegfx::fround(pt100thmm(rShapeBounds
.getWidth())) )
1721 + rtl::OUString::valueOf(
1722 basegfx::fround(pt100thmm(rShapeBounds
.getHeight())) ));
1724 // TODO(F1): decompose transformation in calling code, and use
1725 // transform attribute here
1726 // writeTranslate(maCurrState.maCTM, xAttrs);
1727 xAttrs
->AddAttribute( USTR( "svg:x" ), rtl::OUString::valueOf(pt2mm(rShapeBounds
.getMinX()))+USTR("mm"));
1728 xAttrs
->AddAttribute( USTR( "svg:y" ), rtl::OUString::valueOf(pt2mm(rShapeBounds
.getMinY()))+USTR("mm"));
1732 StateMap
& mrStateMap
;
1733 uno::Reference
<xml::sax::XDocumentHandler
> mxDocumentHandler
;
1734 sal_Int32 mnShapeNum
;
1737 /// Write out shapes from DOM tree
1738 static void writeShapes( StatePool
& rStatePool
,
1739 StateMap
& rStateMap
,
1740 const uno::Reference
<xml::dom::XElement
> xElem
,
1741 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocHdl
)
1743 ShapeWritingVisitor
aVisitor(rStatePool
,rStateMap
,xDocHdl
);
1744 visitElements(aVisitor
, xElem
);
1748 struct DumpingVisitor
1750 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
)
1752 OSL_TRACE("name: %s",
1753 rtl::OUStringToOString(
1754 xElem
->getTagName(),
1755 RTL_TEXTENCODING_UTF8
).getStr());
1758 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
,
1759 const uno::Reference
<xml::dom::XNamedNodeMap
>& xAttributes
)
1761 OSL_TRACE("name: %s",
1762 rtl::OUStringToOString(
1763 xElem
->getTagName(),
1764 RTL_TEXTENCODING_UTF8
).getStr());
1765 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
1766 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
1769 rtl::OUStringToOString(
1770 xAttributes
->item(i
)->getNodeName(),
1771 RTL_TEXTENCODING_UTF8
).getStr(),
1772 rtl::OUStringToOString(
1773 xAttributes
->item(i
)->getNodeValue(),
1774 RTL_TEXTENCODING_UTF8
).getStr());
1782 static void dumpTree( const uno::Reference
<xml::dom::XElement
> xElem
)
1784 DumpingVisitor aVisitor
;
1785 visitElements(aVisitor
, xElem
);
1792 SVGReader::SVGReader(const uno::Reference
<lang::XMultiServiceFactory
>& xServiceFactory
,
1793 const uno::Reference
<io::XInputStream
>& xInputStream
,
1794 const uno::Reference
<xml::sax::XDocumentHandler
>& xDocumentHandler
) :
1795 m_xServiceFactory( xServiceFactory
),
1796 m_xInputStream( xInputStream
),
1797 m_xDocumentHandler( xDocumentHandler
)
1801 sal_Bool
SVGReader::parseAndConvert()
1803 uno::Reference
<xml::dom::XDocumentBuilder
> xDomBuilder(
1804 m_xServiceFactory
->createInstance(
1805 rtl::OUString::createFromAscii("com.sun.star.xml.dom.DocumentBuilder")), uno::UNO_QUERY
);
1807 uno::Reference
<xml::dom::XDocument
> xDom(
1808 xDomBuilder
->parse(m_xInputStream
),
1809 uno::UNO_QUERY_THROW
);
1811 uno::Reference
<xml::dom::XElement
> xDocElem( xDom
->getDocumentElement(),
1812 uno::UNO_QUERY_THROW
);
1814 // the root state for svg document
1815 State aInitialState
;
1817 /////////////////////////////////////////////////////////////////
1819 /////////////////////////////////////////////////////////////////
1821 m_xDocumentHandler
->startDocument();
1823 // get the document dimensions
1825 // if the "width" and "height" attributes are missing, inkscape fakes
1826 // A4 portrait for. Let's do the same.
1827 if (!xDocElem
->hasAttribute(USTR("width")))
1828 xDocElem
->setAttribute(USTR("width"), USTR("210mm"));
1829 if (!xDocElem
->hasAttribute(USTR("height")))
1830 xDocElem
->setAttribute(USTR("height"), USTR("297mm"));
1832 double fViewPortWidth( pt2mm(convLength(xDocElem
->getAttribute(USTR("width")),aInitialState
,'h')) );
1833 double fViewPortHeight( pt2mm(convLength(xDocElem
->getAttribute(USTR("height")),aInitialState
,'v')) );
1836 rtl::Reference
<SvXMLAttributeList
> xAttrs( new SvXMLAttributeList() );
1837 uno::Reference
<xml::sax::XAttributeList
> xUnoAttrs( xAttrs
.get() );
1839 xAttrs
->AddAttribute( USTR( "xmlns:office" ), USTR( OASIS_STR
"office:1.0" ));
1840 xAttrs
->AddAttribute( USTR( "xmlns:style" ), USTR( OASIS_STR
"style:1.0" ));
1841 xAttrs
->AddAttribute( USTR( "xmlns:text" ), USTR( OASIS_STR
"text:1.0" ));
1842 xAttrs
->AddAttribute( USTR( "xmlns:svg" ), USTR( OASIS_STR
"svg-compatible:1.0" ));
1843 xAttrs
->AddAttribute( USTR( "xmlns:table" ), USTR( OASIS_STR
"table:1.0" ));
1844 xAttrs
->AddAttribute( USTR( "xmlns:draw" ), USTR( OASIS_STR
"drawing:1.0" ));
1845 xAttrs
->AddAttribute( USTR( "xmlns:fo" ), USTR( OASIS_STR
"xsl-fo-compatible:1.0" ));
1846 xAttrs
->AddAttribute( USTR( "xmlns:xlink" ), USTR( "http://www.w3.org/1999/xlink" ));
1847 xAttrs
->AddAttribute( USTR( "xmlns:dc" ), USTR( "http://purl.org/dc/elements/1.1/" ));
1848 xAttrs
->AddAttribute( USTR( "xmlns:number" ), USTR( OASIS_STR
"datastyle:1.0" ));
1849 xAttrs
->AddAttribute( USTR( "xmlns:presentation" ), USTR( OASIS_STR
"presentation:1.0" ));
1850 xAttrs
->AddAttribute( USTR( "xmlns:math" ), USTR( "http://www.w3.org/1998/Math/MathML" ));
1851 xAttrs
->AddAttribute( USTR( "xmlns:form" ), USTR( OASIS_STR
"form:1.0" ));
1852 xAttrs
->AddAttribute( USTR( "xmlns:script" ), USTR( OASIS_STR
"script:1.0" ));
1853 xAttrs
->AddAttribute( USTR( "xmlns:dom" ), USTR( "http://www.w3.org/2001/xml-events" ));
1854 xAttrs
->AddAttribute( USTR( "xmlns:xforms" ), USTR( "http://www.w3.org/2002/xforms" ));
1855 xAttrs
->AddAttribute( USTR( "xmlns:xsd" ), USTR( "http://www.w3.org/2001/XMLSchema" ));
1856 xAttrs
->AddAttribute( USTR( "xmlns:xsi" ), USTR( "http://www.w3.org/2001/XMLSchema-instance" ));
1857 xAttrs
->AddAttribute( USTR( "office:version" ), USTR( "1.0" ));
1858 xAttrs
->AddAttribute( USTR( "office:mimetype" ), USTR( "application/vnd.oasis.opendocument.graphics" ));
1860 m_xDocumentHandler
->startElement( USTR("office:document"), xUnoAttrs
);
1864 m_xDocumentHandler
->startElement( USTR("office:settings"), xUnoAttrs
);
1866 xAttrs
->AddAttribute( USTR( "config:name" ), USTR( "ooo:view-settings" ));
1867 m_xDocumentHandler
->startElement( USTR("config:config-item-set"), xUnoAttrs
);
1871 xAttrs
->AddAttribute( USTR( "config:name" ), USTR( "VisibleAreaTop" ));
1872 xAttrs
->AddAttribute( USTR( "config:type" ), USTR( "int" ));
1873 m_xDocumentHandler
->startElement( USTR( "config:config-item" ), xUnoAttrs
);
1875 m_xDocumentHandler
->characters( USTR( "0" ));
1877 m_xDocumentHandler
->endElement( USTR( "config:config-item" ));
1881 xAttrs
->AddAttribute( USTR( "config:name" ), USTR( "VisibleAreaLeft" ));
1882 xAttrs
->AddAttribute( USTR( "config:type" ), USTR( "int" ));
1883 m_xDocumentHandler
->startElement( USTR( "config:config-item" ), xUnoAttrs
);
1885 m_xDocumentHandler
->characters( USTR( "0" ));
1887 m_xDocumentHandler
->endElement( USTR( "config:config-item" ));
1891 xAttrs
->AddAttribute( USTR( "config:name" ), USTR( "VisibleAreaWidth" ));
1892 xAttrs
->AddAttribute( USTR( "config:type" ), USTR( "int" ));
1893 m_xDocumentHandler
->startElement( USTR( "config:config-item" ), xUnoAttrs
);
1895 sal_Int64 iWidth
= sal_Int64(fViewPortWidth
);
1896 m_xDocumentHandler
->characters( ::rtl::OUString::valueOf(iWidth
) );
1898 m_xDocumentHandler
->endElement( USTR( "config:config-item" ));
1902 xAttrs
->AddAttribute( USTR( "config:name" ), USTR( "VisibleAreaHeight" ));
1903 xAttrs
->AddAttribute( USTR( "config:type" ), USTR( "int" ));
1904 m_xDocumentHandler
->startElement( USTR( "config:config-item" ), xUnoAttrs
);
1906 sal_Int64 iHeight
= sal_Int64(fViewPortHeight
);
1907 m_xDocumentHandler
->characters( ::rtl::OUString::valueOf(iHeight
) );
1909 m_xDocumentHandler
->endElement( USTR( "config:config-item" ));
1911 m_xDocumentHandler
->endElement( USTR( "config:config-item-set" ));
1913 m_xDocumentHandler
->endElement( USTR( "office:settings" ));
1917 m_xDocumentHandler
->startElement( USTR("office:automatic-styles"),
1920 xAttrs
->AddAttribute( USTR( "style:name" ), USTR("pagelayout1"));
1921 m_xDocumentHandler
->startElement( USTR("style:page-layout"),
1923 // TODO(Q3): this is super-ugly. In-place container come to mind.
1926 // make page viewport-width times viewport-height mm large - add
1927 // 5% border at every side
1928 xAttrs
->AddAttribute( USTR( "fo:margin-top" ), USTR("0mm"));
1929 xAttrs
->AddAttribute( USTR( "fo:margin-bottom" ), USTR("0mm"));
1930 xAttrs
->AddAttribute( USTR( "fo:margin-left" ), USTR("0mm"));
1931 xAttrs
->AddAttribute( USTR( "fo:margin-right" ), USTR("0mm"));
1932 xAttrs
->AddAttribute( USTR( "fo:page-width" ), rtl::OUString::valueOf(fViewPortWidth
)+USTR("mm"));
1933 xAttrs
->AddAttribute( USTR( "fo:page-height" ), rtl::OUString::valueOf(fViewPortHeight
)+USTR("mm"));
1934 xAttrs
->AddAttribute( USTR( "style:print-orientation" ),
1935 fViewPortWidth
> fViewPortHeight
?
1938 m_xDocumentHandler
->startElement( USTR("style:page-layout-properties"),
1940 m_xDocumentHandler
->endElement( USTR("style:page-layout-properties") );
1941 m_xDocumentHandler
->endElement( USTR("style:page-layout") );
1944 xAttrs
->AddAttribute( USTR( "style:name" ), USTR("pagestyle1"));
1945 xAttrs
->AddAttribute( USTR( "style:family" ), USTR("drawing-page"));
1946 m_xDocumentHandler
->startElement( USTR("style:style"),
1950 xAttrs
->AddAttribute( USTR( "draw:background-size" ), USTR("border"));
1951 xAttrs
->AddAttribute( USTR( "draw:fill" ), USTR("none"));
1952 m_xDocumentHandler
->startElement( USTR("style:drawing-page-properties"),
1954 m_xDocumentHandler
->endElement( USTR("style:drawing-page-properties") );
1955 m_xDocumentHandler
->endElement( USTR("style:style") );
1957 StatePool aStatePool
;
1959 annotateStyles(aStatePool
,aStateMap
,aInitialState
,
1960 xDocElem
,m_xDocumentHandler
);
1966 m_xDocumentHandler
->endElement( USTR("office:automatic-styles") );
1968 ////////////////////////////////////////////////////////////////////
1971 m_xDocumentHandler
->startElement( USTR("office:styles"),
1973 m_xDocumentHandler
->endElement( USTR("office:styles") );
1975 ////////////////////////////////////////////////////////////////////
1977 m_xDocumentHandler
->startElement( USTR("office:master-styles"),
1980 xAttrs
->AddAttribute( USTR( "style:name" ), USTR("Default"));
1981 xAttrs
->AddAttribute( USTR( "style:page-layout-name" ), USTR("pagelayout1"));
1982 xAttrs
->AddAttribute( USTR( "draw:style-name" ), USTR("pagestyle1"));
1983 m_xDocumentHandler
->startElement( USTR("style:master-page"),
1985 m_xDocumentHandler
->endElement( USTR("style:master-page") );
1987 m_xDocumentHandler
->endElement( USTR("office:master-styles") );
1989 ////////////////////////////////////////////////////////////////////
1992 m_xDocumentHandler
->startElement( USTR("office:body"),
1994 m_xDocumentHandler
->startElement( USTR("office:drawing"),
1998 xAttrs
->AddAttribute( USTR( "draw:master-page-name" ), USTR("Default"));
1999 xAttrs
->AddAttribute( USTR( "draw:style-name" ), USTR("pagestyle1"));
2000 m_xDocumentHandler
->startElement(USTR("draw:page"),
2003 // write out all shapes
2004 writeShapes(aStatePool
,
2007 m_xDocumentHandler
);
2009 m_xDocumentHandler
->endElement( USTR("draw:page") );
2010 m_xDocumentHandler
->endElement( USTR("office:drawing") );
2011 m_xDocumentHandler
->endElement( USTR("office:body") );
2012 m_xDocumentHandler
->endElement( USTR("office:document") );
2013 m_xDocumentHandler
->endDocument();
2018 ///////////////////////////////////////////////////////////////
2020 struct ShapeRenderingVisitor
2022 ShapeRenderingVisitor(StatePool
& /*rStatePool*/,
2023 StateMap
& rStateMap
,
2024 OutputDevice
& rOutDev
,
2025 const std::vector
< Gradient
>& rGradientVector
,
2026 const std::vector
< GradientStop
>& rGradientStopVector
) :
2027 mrStateMap(rStateMap
),
2029 mrGradientVector(rGradientVector
),
2030 mrGradientStopVector(rGradientStopVector
)
2033 void operator()( const uno::Reference
<xml::dom::XElement
>& )
2037 void operator()( const uno::Reference
<xml::dom::XElement
>& xElem
,
2038 const uno::Reference
<xml::dom::XNamedNodeMap
>& xAttributes
)
2040 sal_Int32
nDummyIndex(0);
2041 rtl::OUString
sStyleId(
2042 xElem
->getAttribute(
2043 USTR("internal-style-ref")).getToken(
2044 0,'$',nDummyIndex
));
2045 StateMap::iterator pOrigState
=mrStateMap
.find(
2046 sStyleId
.toInt32());
2048 if( pOrigState
== mrStateMap
.end() )
2049 return; // non-exportable element, e.g. linearGradient
2051 maCurrState
= pOrigState
->second
;
2053 const sal_Int32
nTokenId(getTokenId(xElem
->getNodeName()));
2058 // collect attributes
2059 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
2060 rtl::OUString sAttributeValue
;
2061 double x1
=0.0,y1
=0.0,x2
=0.0,y2
=0.0;
2062 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
2064 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
2065 const sal_Int32
nAttribId(
2066 getTokenId(xAttributes
->item(i
)->getNodeName()));
2070 x1
= convLength(sAttributeValue
,maCurrState
,'h');
2073 x2
= convLength(sAttributeValue
,maCurrState
,'h');
2076 y1
= convLength(sAttributeValue
,maCurrState
,'v');
2079 y2
= convLength(sAttributeValue
,maCurrState
,'v');
2087 basegfx::B2DPolygon aPoly
;
2088 aPoly
.append(basegfx::B2DPoint(x1
,y1
));
2089 aPoly
.append(basegfx::B2DPoint(x2
,y2
));
2091 renderPathShape(basegfx::B2DPolyPolygon(aPoly
));
2097 rtl::OUString sPoints
= xElem
->hasAttribute(USTR("points")) ? xElem
->getAttribute(USTR("points")) : USTR("");
2098 basegfx::B2DPolygon aPoly
;
2099 basegfx::tools::importFromSvgPoints(aPoly
, sPoints
);
2100 if( nTokenId
== XML_POLYGON
|| maCurrState
.meFillType
!= NONE
)
2101 aPoly
.setClosed(true);
2103 renderPathShape(basegfx::B2DPolyPolygon(aPoly
));
2108 // collect attributes
2109 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
2110 rtl::OUString sAttributeValue
;
2111 bool bRxSeen
=false, bRySeen
=false;
2112 double x
=0.0,y
=0.0,width
=0.0,height
=0.0,rx
=0.0,ry
=0.0;
2113 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
2115 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
2116 const sal_Int32
nAttribId(
2117 getTokenId(xAttributes
->item(i
)->getNodeName()));
2121 x
= convLength(sAttributeValue
,maCurrState
,'h');
2124 y
= convLength(sAttributeValue
,maCurrState
,'v');
2127 width
= convLength(sAttributeValue
,maCurrState
,'h');
2130 height
= convLength(sAttributeValue
,maCurrState
,'v');
2133 rx
= convLength(sAttributeValue
,maCurrState
,'h');
2137 ry
= convLength(sAttributeValue
,maCurrState
,'v');
2146 if( bRxSeen
&& !bRySeen
)
2148 else if( bRySeen
&& !bRxSeen
)
2151 basegfx::B2DPolygon aPoly
;
2152 aPoly
= basegfx::tools::createPolygonFromRect(
2153 basegfx::B2DRange(x
,y
,x
+width
,y
+height
),
2156 renderPathShape(basegfx::B2DPolyPolygon(aPoly
));
2161 rtl::OUString sPath
= xElem
->hasAttribute(USTR("d")) ? xElem
->getAttribute(USTR("d")) : USTR("");
2162 basegfx::B2DPolyPolygon aPoly
;
2163 basegfx::tools::importFromSvgD(aPoly
, sPath
);
2165 renderPathShape(aPoly
);
2170 // collect attributes
2171 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
2172 rtl::OUString sAttributeValue
;
2173 double cx
=0.0,cy
=0.0,r
=0.0;
2174 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
2176 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
2177 const sal_Int32
nAttribId(
2178 getTokenId(xAttributes
->item(i
)->getNodeName()));
2182 cx
= convLength(sAttributeValue
,maCurrState
,'h');
2185 cy
= convLength(sAttributeValue
,maCurrState
,'v');
2188 r
= convLength(sAttributeValue
,maCurrState
,'o');
2195 basegfx::B2DEllipse
aEllipse(basegfx::B2DPoint(cx
, cy
), basegfx::B2DTuple(r
,r
));
2196 basegfx::B2DPolygon aPoly
= basegfx::tools::createPolygonFromEllipse(
2197 aEllipse
.getB2DEllipseCenter(),
2198 aEllipse
.getB2DEllipseRadius().getX(),
2199 aEllipse
.getB2DEllipseRadius().getY());
2201 renderPathShape(basegfx::B2DPolyPolygon(aPoly
));
2206 // collect attributes
2207 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
2208 rtl::OUString sAttributeValue
;
2209 double cx
=0.0,cy
=0.0,rx
=0.0, ry
=0.0;
2210 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
2212 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
2213 const sal_Int32
nAttribId(
2214 getTokenId(xAttributes
->item(i
)->getNodeName()));
2218 cx
= convLength(sAttributeValue
,maCurrState
,'h');
2221 cy
= convLength(sAttributeValue
,maCurrState
,'v');
2224 rx
= convLength(sAttributeValue
,maCurrState
,'h');
2227 ry
= convLength(sAttributeValue
,maCurrState
,'v');
2234 basegfx::B2DEllipse
aEllipse(basegfx::B2DPoint(cx
, cy
), basegfx::B2DTuple(rx
,ry
));
2235 basegfx::B2DPolygon aPoly
= basegfx::tools::createPolygonFromEllipse(
2236 aEllipse
.getB2DEllipseCenter(),
2237 aEllipse
.getB2DEllipseRadius().getX(),
2238 aEllipse
.getB2DEllipseRadius().getY());
2240 renderPathShape(basegfx::B2DPolyPolygon(aPoly
));
2245 // collect attributes
2246 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
2247 rtl::OUString sAttributeValue
;
2248 double x
=0.0,y
=0.0,width
=0.0,height
=0.0;
2249 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
2251 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
2252 const sal_Int32
nAttribId(
2253 getTokenId(xAttributes
->item(i
)->getNodeName()));
2257 x
= convLength(sAttributeValue
,maCurrState
,'h');
2260 y
= convLength(sAttributeValue
,maCurrState
,'v');
2263 width
= convLength(sAttributeValue
,maCurrState
,'h');
2266 height
= convLength(sAttributeValue
,maCurrState
,'v');
2274 rtl::OUString sValue
= xElem
->hasAttribute(USTR("href")) ? xElem
->getAttribute(USTR("href")) : USTR("");
2275 rtl::OString
aValueUtf8( sValue
.getStr(), sValue
.getLength(), RTL_TEXTENCODING_UTF8
);
2276 std::string sLinkValue
;
2277 parseXlinkHref(aValueUtf8
.getStr(), sLinkValue
);
2279 if (!sLinkValue
.empty())
2281 // <- blatant copy from svx/source/xml/xmlgrhlp.cxx
2284 uno::Sequence
<sal_Int8
> aData
;
2285 SvXMLUnitConverter::decodeBase64(aData
,
2286 rtl::OUString::createFromAscii(sLinkValue
.c_str()));
2287 SvMemoryStream
aSrc(aData
.getArray(),
2290 USHORT nFormat
= GRFILTER_FORMAT_DONTKNOW
;
2291 USHORT pDeterminedFormat
= GRFILTER_FORMAT_DONTKNOW
;
2292 GetGrfFilter()->ImportGraphic( aGraphic
, String(), aSrc
,nFormat
,&pDeterminedFormat
);
2294 if (pDeterminedFormat
== GRFILTER_FORMAT_DONTKNOW
)
2296 //Read the first two byte to check whether it is a gzipped stream, is so it may be in wmz or emz format
2297 //unzip them and try again
2299 BYTE sFirstBytes
[ 2 ];
2301 aSrc
.Seek( STREAM_SEEK_TO_END
);
2302 ULONG nStreamLen
= aSrc
.Tell();
2307 SvLockBytes
* pLockBytes
= aSrc
.GetLockBytes();
2309 pLockBytes
->SetSynchronMode( TRUE
);
2311 aSrc
.Seek( STREAM_SEEK_TO_END
);
2312 nStreamLen
= aSrc
.Tell();
2315 if( nStreamLen
>= 2 )
2318 aSrc
.Read( sFirstBytes
, 2 );
2320 if( sFirstBytes
[0] == 0x1f && sFirstBytes
[1] == 0x8b )
2322 SvMemoryStream
* pDest
= new SvMemoryStream
;
2323 ZCodec
aZCodec( 0x8000, 0x8000 );
2324 aZCodec
.BeginCompression(ZCODEC_GZ_LIB
);
2326 aZCodec
.Decompress( aSrc
, *pDest
);
2328 if (aZCodec
.EndCompression() && pDest
)
2330 pDest
->Seek( STREAM_SEEK_TO_END
);
2331 ULONG nStreamLen_
= pDest
->Tell();
2335 GetGrfFilter()->ImportGraphic( aGraphic
, String(), *pDest
,nFormat
,&pDeterminedFormat
);
2342 // -> blatant copy from svx/source/xml/xmlgrhlp.cxx
2344 const Rectangle
aBounds(
2345 Point(basegfx::fround(pt100thmm(x
)),
2346 basegfx::fround(pt100thmm(y
))),
2347 Size(basegfx::fround(pt100thmm(width
)),
2348 basegfx::fround(pt100thmm(height
))));
2349 aGraphic
.Draw(&mrOutDev
,
2352 maBounds
.Union(aBounds
);
2358 // collect text from all TEXT_NODE children into sText
2359 rtl::OUStringBuffer sText
;
2360 visitChildren(boost::bind(
2361 (rtl::OUStringBuffer
& (rtl::OUStringBuffer::*)(const sal_Unicode
* str
))&rtl::OUStringBuffer::append
,
2363 boost::bind(&xml::dom::XNode::getNodeValue
,
2366 xml::dom::NodeType_TEXT_NODE
);
2368 // collect attributes
2369 const sal_Int32
nNumAttrs( xAttributes
->getLength() );
2370 rtl::OUString sAttributeValue
;
2371 double x
=0.0,y
=0.0,width
=0.0,height
=0.0;
2372 for( sal_Int32 i
=0; i
<nNumAttrs
; ++i
)
2374 sAttributeValue
= xAttributes
->item(i
)->getNodeValue();
2375 const sal_Int32
nAttribId(
2376 getTokenId(xAttributes
->item(i
)->getNodeName()));
2380 x
= convLength(sAttributeValue
,maCurrState
,'h');
2383 y
= convLength(sAttributeValue
,maCurrState
,'v');
2386 width
= convLength(sAttributeValue
,maCurrState
,'h');
2389 height
= convLength(sAttributeValue
,maCurrState
,'v');
2397 // actually export text
2398 Font
aFont(maCurrState
.maFontFamily
,
2400 basegfx::fround(pt100thmm(maCurrState
.mnFontSize
))));
2401 aFont
.SetAlign(ALIGN_BASELINE
);
2402 aFont
.SetColor(getVclColor(maCurrState
.maFillColor
));
2403 aFont
.SetFillColor(getVclColor(maCurrState
.maFillColor
));
2405 if( !maCurrState
.maFontStyle
.equalsAscii("normal") )
2406 aFont
.SetItalic(ITALIC_NORMAL
); // TODO: discriminate
2407 if( !maCurrState
.mnFontWeight
!= 400.0 )
2408 aFont
.SetWeight(WEIGHT_BOLD
); // TODO: discriminate
2410 // extract basic transformations out of CTM
2411 basegfx::B2DTuple aScale
, aTranslate
;
2412 double fRotate
, fShearX
;
2413 ::rtl::OUString sTransformValue
;
2414 if (maCurrState
.maCTM
.decompose(aScale
, aTranslate
, fRotate
, fShearX
))
2416 rtl::OUString sTransform
;
2417 x
+= aTranslate
.getX();
2418 y
+= aTranslate
.getY();
2421 Size(basegfx::fround(aFont
.GetWidth()*aScale
.getX()),
2422 basegfx::fround(aFont
.GetHeight()*aScale
.getY())));
2425 aFont
.SetOrientation(basegfx::fround(fRotate
*1800.0/M_PI
));
2428 // TODO(F2): update bounds
2429 mrOutDev
.SetFont(aFont
);
2430 const ::rtl::OUString
aText( sText
.makeStringAndClear() );
2431 switch( maCurrState
.meTextAnchor
)
2439 const long nWidth
=mrOutDev
.GetTextWidth(aText
);
2445 x
-= mrOutDev
.GetTextWidth(aText
);
2448 mrOutDev
.DrawText(Point(basegfx::fround(pt100thmm(x
)),
2449 basegfx::fround(pt100thmm(y
))),
2464 bool hasGradientOpacity( const Gradient
& rGradient
)
2467 mrGradientStopVector
[
2468 rGradient
.maStops
[0]].maStopColor
.a
!= 1.0 ||
2469 mrGradientStopVector
[
2470 rGradient
.maStops
[1]].maStopColor
.a
!= 1.0;
2473 sal_Int8
toByteColor( double val
)
2475 // TODO(Q3): duplicated from vcl::unotools
2476 return sal::static_int_cast
<sal_Int8
>(
2477 basegfx::fround(val
*255.0));
2480 ::Color
getVclColor( const ARGBColor
& rColor
)
2482 const sal_uInt8
nRed ( toByteColor(rColor
.r
) );
2483 const sal_uInt8
nGreen( toByteColor(rColor
.g
) );
2484 const sal_uInt8
nBlue ( toByteColor(rColor
.b
) );
2486 return ::Color(nRed
,nGreen
,nBlue
);
2489 void renderPathShape(const basegfx::B2DPolyPolygon
& rPoly
)
2491 // we might need to split up polypolygon into multiple path
2492 // shapes (e.g. when emulating line stroking)
2493 State aState
= maCurrState
;
2495 // bring polygon from pt coordinate system to 100th millimeter
2496 aState
.maCTM
.scale(2540.0/72.0,2540.0/72.0);
2498 basegfx::B2DPolyPolygon
aPoly(rPoly
);
2499 aPoly
.transform(aState
.maCTM
);
2501 const basegfx::B2DRange aBounds
=basegfx::tools::getRange(aPoly
);
2504 basegfx::fround(aBounds
.getMinX()),
2505 basegfx::fround(aBounds
.getMinY()),
2506 basegfx::fround(aBounds
.getMaxX()),
2507 basegfx::fround(aBounds
.getMaxY())));
2510 mrOutDev
.SetLineColor();
2512 // do we have a gradient fill?
2513 if( aState
.meFillType
== GRADIENT
&& aState
.maFillGradient
.maStops
.size() > 1 )
2515 ::Gradient aGradient
;
2517 if( aState
.maFillGradient
.meType
== Gradient::LINEAR
)
2519 // should the optimizeGradientStops method decide that
2520 // this is a three-color gradient, it prolly wanted us
2521 // to take axial instead
2522 aGradient
= ::Gradient( aState
.maFillGradient
.maStops
.size() == 3 ?
2528 aGradient
= ::Gradient( GRADIENT_ELLIPTICAL
);
2531 basegfx::B2DTuple rScale
, rTranslate
;
2532 double rRotate
, rShearX
;
2533 if( aState
.maFillGradient
.maTransform
.decompose(rScale
, rTranslate
, rRotate
, rShearX
) )
2534 aGradient
.SetAngle( basegfx::fround(rRotate
*1800.0/M_PI
) );
2535 aGradient
.SetStartColor( getVclColor(
2536 mrGradientStopVector
[
2537 aState
.maFillGradient
.maStops
[0]].maStopColor
) );
2538 aGradient
.SetEndColor( getVclColor(
2539 mrGradientStopVector
[
2540 aState
.maFillGradient
.maStops
[1]].maStopColor
) );
2542 if( hasGradientOpacity(aState
.maFillGradient
) )
2544 ::Gradient aTransparencyGradient
=aGradient
;
2546 const BYTE
cTransStart( 255-
2547 basegfx::fround(mrGradientStopVector
[
2548 aState
.maFillGradient
.maStops
[1]].maStopColor
.a
*
2549 aState
.mnFillOpacity
*maCurrState
.mnOpacity
*255.0));
2550 const Color
aTransStart( cTransStart
, cTransStart
, cTransStart
);
2552 const BYTE
cTransEnd( 255-
2553 basegfx::fround(mrGradientStopVector
[
2554 aState
.maFillGradient
.maStops
[0]].maStopColor
.a
*
2555 aState
.mnFillOpacity
*maCurrState
.mnOpacity
*255.0));
2556 const Color
aTransEnd( cTransEnd
, cTransEnd
, cTransEnd
);
2558 // modulate gradient opacity with overall fill opacity
2559 aTransparencyGradient
.SetStartColor(aTransStart
);
2560 aTransparencyGradient
.SetEndColor(aTransEnd
);
2562 VirtualDevice aVDev
;
2565 aVDev
.EnableOutput( FALSE
);
2566 aVDev
.SetMapMode( mrOutDev
.GetMapMode() );
2567 aMtf
.Record( &aVDev
);
2569 aVDev
.SetLineColor();
2570 aVDev
.SetFillColor();
2571 aVDev
.DrawGradient(::PolyPolygon(aPoly
),aGradient
);
2573 const Rectangle
aMtfBounds(
2574 basegfx::fround(aBounds
.getMinX()),
2575 basegfx::fround(aBounds
.getMinY()),
2576 basegfx::fround(aBounds
.getMaxX()),
2577 basegfx::fround(aBounds
.getMaxY()));
2579 MapMode
aMap(mrOutDev
.GetMapMode());
2582 aMap
.SetOrigin( aMtfBounds
.TopLeft() );
2583 aMtf
.SetPrefMapMode( aMap
);
2584 aMtf
.SetPrefSize( aMtfBounds
.GetSize() );
2586 mrOutDev
.DrawTransparent(aMtf
,
2587 aMtfBounds
.TopLeft(),
2588 aMtfBounds
.GetSize(),
2589 aTransparencyGradient
);
2593 mrOutDev
.DrawGradient(::PolyPolygon(aPoly
),aGradient
);
2598 if( aState
.meFillType
== NONE
)
2599 mrOutDev
.SetFillColor();
2601 mrOutDev
.SetFillColor(getVclColor(aState
.maFillColor
));
2603 if( aState
.mnFillOpacity
*maCurrState
.mnOpacity
!= 1.0 )
2604 mrOutDev
.DrawTransparent(::PolyPolygon(aPoly
),
2606 (1.0-(aState
.mnFillOpacity
*maCurrState
.mnOpacity
))*100.0));
2608 mrOutDev
.DrawPolyPolygon(::PolyPolygon(aPoly
));
2612 mrOutDev
.SetFillColor();
2614 if( aState
.meStrokeType
!= NONE
&&
2615 (aState
.maDashArray
.size() ||
2616 aState
.mnStrokeWidth
!= 1.0) )
2618 // vcl thick lines are severly borked - generate filled
2620 std::vector
<basegfx::B2DPolyPolygon
> aPolys
;
2622 if( !aState
.maDashArray
.empty() )
2625 basegfx::B2DPolyPolygon aSegment
;
2626 for( sal_uInt32 i
=0; i
<rPoly
.count(); ++i
)
2628 basegfx::tools::applyLineDashing(rPoly
,
2631 aPoly
.append(aSegment
);
2635 // applied line dashing to original rPoly above, to get
2636 // correctly transformed lengths - need to transform
2638 aPoly
.transform(aState
.maCTM
);
2640 for( sal_uInt32 i
=0; i
<aPoly
.count(); ++i
)
2642 // ugly. convert to integer-based tools polygon
2643 // first, and only _then_ remove intersections (we
2644 // might get new ones from the rounding)
2646 basegfx::tools::stripNeutralPolygons(
2647 basegfx::tools::prepareForPolygonOperation(
2649 basegfx::tools::createAreaGeometry(
2650 aPoly
.getB2DPolygon(i
),
2651 pt100thmm(aState
.mnStrokeWidth
/2.0),
2652 aState
.meLineJoin
)).getB2DPolyPolygon())));
2653 // TODO(F2): line ends
2656 mrOutDev
.SetLineColor();
2657 mrOutDev
.SetFillColor(getVclColor(aState
.maStrokeColor
));
2659 for( sal_uInt32 i
=0; i
<aPolys
.size(); ++i
)
2661 if( aState
.mnStrokeOpacity
*maCurrState
.mnOpacity
!= 1.0 )
2662 mrOutDev
.DrawTransparent(::PolyPolygon(aPolys
[i
]),
2664 (1.0-(aState
.mnStrokeOpacity
*maCurrState
.mnOpacity
))*100.0));
2666 mrOutDev
.DrawPolyPolygon(::PolyPolygon(aPolys
[i
]));
2668 const basegfx::B2DRange aStrokeBounds
=basegfx::tools::getRange(aPolys
[i
]);
2671 basegfx::fround(aStrokeBounds
.getMinX()),
2672 basegfx::fround(aStrokeBounds
.getMinY()),
2673 basegfx::fround(aStrokeBounds
.getMaxX()),
2674 basegfx::fround(aStrokeBounds
.getMaxY())));
2679 if( aState
.meStrokeType
== NONE
)
2680 mrOutDev
.SetLineColor();
2682 mrOutDev
.SetLineColor(getVclColor(aState
.maStrokeColor
));
2684 if( aState
.mnStrokeOpacity
*maCurrState
.mnOpacity
!= 1.0 )
2685 mrOutDev
.DrawTransparent(::PolyPolygon(aPoly
),
2687 (1.0-(aState
.mnStrokeOpacity
*maCurrState
.mnOpacity
))*100.0));
2689 mrOutDev
.DrawPolyPolygon(::PolyPolygon(aPoly
));
2694 StateMap
& mrStateMap
;
2695 OutputDevice
& mrOutDev
;
2696 const std::vector
< Gradient
>& mrGradientVector
;
2697 const std::vector
< GradientStop
>& mrGradientStopVector
;
2703 bool importSvg(SvStream
& rStream
, Graphic
& rGraphic
)
2705 const uno::Reference
<lang::XMultiServiceFactory
> xServiceFactory(
2706 ::comphelper::getProcessServiceFactory());
2708 uno::Reference
<xml::dom::XDocumentBuilder
> xDomBuilder(
2709 xServiceFactory
->createInstance(
2710 rtl::OUString::createFromAscii("com.sun.star.xml.dom.DocumentBuilder")),
2713 uno::Reference
<io::XInputStream
> xStream(
2714 new utl::OInputStreamWrapper(rStream
) );
2716 uno::Reference
<xml::dom::XDocument
> xDom(
2717 xDomBuilder
->parse(xStream
),
2718 uno::UNO_QUERY_THROW
);
2720 uno::Reference
<xml::dom::XElement
> xDocElem( xDom
->getDocumentElement(),
2721 uno::UNO_QUERY_THROW
);
2723 VirtualDevice aVDev
;
2726 aVDev
.EnableOutput( FALSE
);
2727 aMtf
.Record( &aVDev
);
2728 aVDev
.SetTextAlign(ALIGN_BASELINE
);
2730 // parse styles and fill state stack
2731 svgi::State aInitialState
;
2732 svgi::StatePool aStatePool
;
2733 svgi::StateMap aStateMap
;
2734 svgi::AnnotatingVisitor
aVisitor(aStatePool
,
2737 uno::Reference
<xml::sax::XDocumentHandler
>());
2738 svgi::visitElements(aVisitor
, xDocElem
);
2744 // render all shapes to mtf
2745 svgi::ShapeRenderingVisitor
aRenderer(aStatePool
,aStateMap
,aVDev
,
2746 aVisitor
.maGradientVector
,
2747 aVisitor
.maGradientStopVector
);
2748 svgi::visitElements(aRenderer
, xDocElem
);
2753 aMtf
.SetPrefMapMode( MAP_100TH_MM
);
2755 // get the document dimensions
2757 // if the "width" and "height" attributes are missing, inkscape fakes
2758 // A4 portrait for. Let's do the same.
2759 if (!xDocElem
->hasAttribute(USTR("width")))
2760 xDocElem
->setAttribute(USTR("width"), USTR("210mm"));
2761 if (!xDocElem
->hasAttribute(USTR("height")))
2762 xDocElem
->setAttribute(USTR("height"), USTR("297mm"));
2767 sal_Int32(aRenderer
.maBounds
.Right()),
2768 basegfx::fround( svgi::pt100thmm(svgi::convLength(xDocElem
->getAttribute(USTR("width")),aInitialState
,'h')) )),
2770 sal_Int32(aRenderer
.maBounds
.Bottom()),
2771 basegfx::fround( svgi::pt100thmm(svgi::convLength(xDocElem
->getAttribute(USTR("height")),aInitialState
,'v')) ))));