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