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