1ddde725dSArmin Le Grand /**************************************************************
2ddde725dSArmin Le Grand  *
3ddde725dSArmin Le Grand  * Licensed to the Apache Software Foundation (ASF) under one
4ddde725dSArmin Le Grand  * or more contributor license agreements.  See the NOTICE file
5ddde725dSArmin Le Grand  * distributed with this work for additional information
6ddde725dSArmin Le Grand  * regarding copyright ownership.  The ASF licenses this file
7ddde725dSArmin Le Grand  * to you under the Apache License, Version 2.0 (the
8ddde725dSArmin Le Grand  * "License"); you may not use this file except in compliance
9ddde725dSArmin Le Grand  * with the License.  You may obtain a copy of the License at
10ddde725dSArmin Le Grand  *
11ddde725dSArmin Le Grand  *   http://www.apache.org/licenses/LICENSE-2.0
12ddde725dSArmin Le Grand  *
13ddde725dSArmin Le Grand  * Unless required by applicable law or agreed to in writing,
14ddde725dSArmin Le Grand  * software distributed under the License is distributed on an
15ddde725dSArmin Le Grand  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16ddde725dSArmin Le Grand  * KIND, either express or implied.  See the License for the
17ddde725dSArmin Le Grand  * specific language governing permissions and limitations
18ddde725dSArmin Le Grand  * under the License.
19ddde725dSArmin Le Grand  *
20ddde725dSArmin Le Grand  *************************************************************/
21ddde725dSArmin Le Grand 
22ddde725dSArmin Le Grand // MARKER(update_precomp.py): autogen include statement, do not remove
23ddde725dSArmin Le Grand #include "precompiled_svgio.hxx"
24ddde725dSArmin Le Grand 
25ddde725dSArmin Le Grand #include <svgio/svgreader/svgsvgnode.hxx>
26ddde725dSArmin Le Grand #include <drawinglayer/geometry/viewinformation2d.hxx>
27ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
28ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
29ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygontools.hxx>
30ddde725dSArmin Le Grand #include <basegfx/polygon/b2dpolygon.hxx>
31ddde725dSArmin Le Grand #include <basegfx/matrix/b2dhommatrixtools.hxx>
3241923119SArmin Le Grand #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
3341923119SArmin Le Grand #include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
34ddde725dSArmin Le Grand 
35ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
36ddde725dSArmin Le Grand 
37ddde725dSArmin Le Grand namespace svgio
38ddde725dSArmin Le Grand {
39ddde725dSArmin Le Grand     namespace svgreader
40ddde725dSArmin Le Grand     {
41ddde725dSArmin Le Grand         SvgSvgNode::SvgSvgNode(
42ddde725dSArmin Le Grand             SvgDocument& rDocument,
43ddde725dSArmin Le Grand             SvgNode* pParent)
44ddde725dSArmin Le Grand         :   SvgNode(SVGTokenSvg, rDocument, pParent),
45ddde725dSArmin Le Grand             maSvgStyleAttributes(*this),
46ddde725dSArmin Le Grand             mpViewBox(0),
47ddde725dSArmin Le Grand             maSvgAspectRatio(),
48ddde725dSArmin Le Grand             maX(),
49ddde725dSArmin Le Grand             maY(),
50ddde725dSArmin Le Grand             maWidth(),
51ddde725dSArmin Le Grand             maHeight(),
52ddde725dSArmin Le Grand             maVersion()
53ddde725dSArmin Le Grand         {
54ddde725dSArmin Le Grand             if(!getParent())
55ddde725dSArmin Le Grand             {
56ddde725dSArmin Le Grand                 // initial fill is black
57ddde725dSArmin Le Grand                 maSvgStyleAttributes.setFill(SvgPaint(basegfx::BColor(0.0, 0.0, 0.0), true, true));
58ddde725dSArmin Le Grand             }
59ddde725dSArmin Le Grand         }
60ddde725dSArmin Le Grand 
61ddde725dSArmin Le Grand         SvgSvgNode::~SvgSvgNode()
62ddde725dSArmin Le Grand         {
63ddde725dSArmin Le Grand             if(mpViewBox) delete mpViewBox;
64ddde725dSArmin Le Grand         }
65ddde725dSArmin Le Grand 
66ddde725dSArmin Le Grand         const SvgStyleAttributes* SvgSvgNode::getSvgStyleAttributes() const
67ddde725dSArmin Le Grand         {
68ddde725dSArmin Le Grand             return &maSvgStyleAttributes;
69ddde725dSArmin Le Grand         }
70ddde725dSArmin Le Grand 
71ddde725dSArmin Le Grand         void SvgSvgNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
72ddde725dSArmin Le Grand         {
73ddde725dSArmin Le Grand             // call parent
74ddde725dSArmin Le Grand             SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
75ddde725dSArmin Le Grand 
76ddde725dSArmin Le Grand             // read style attributes
77ddde725dSArmin Le Grand             maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
78ddde725dSArmin Le Grand 
79ddde725dSArmin Le Grand             // parse own
80ddde725dSArmin Le Grand             switch(aSVGToken)
81ddde725dSArmin Le Grand             {
82ddde725dSArmin Le Grand                 case SVGTokenStyle:
83ddde725dSArmin Le Grand                 {
84ddde725dSArmin Le Grand                     maSvgStyleAttributes.readStyle(aContent);
85ddde725dSArmin Le Grand                     break;
86ddde725dSArmin Le Grand                 }
87ddde725dSArmin Le Grand                 case SVGTokenViewBox:
88ddde725dSArmin Le Grand                 {
89ddde725dSArmin Le Grand                     const basegfx::B2DRange aRange(readViewBox(aContent, *this));
90ddde725dSArmin Le Grand 
91ddde725dSArmin Le Grand                     if(!aRange.isEmpty())
92ddde725dSArmin Le Grand                     {
93ddde725dSArmin Le Grand                         setViewBox(&aRange);
94ddde725dSArmin Le Grand                     }
95ddde725dSArmin Le Grand                     break;
96ddde725dSArmin Le Grand                 }
97ddde725dSArmin Le Grand                 case SVGTokenPreserveAspectRatio:
98ddde725dSArmin Le Grand                 {
99ddde725dSArmin Le Grand                     setSvgAspectRatio(readSvgAspectRatio(aContent));
100ddde725dSArmin Le Grand                     break;
101ddde725dSArmin Le Grand                 }
102ddde725dSArmin Le Grand                 case SVGTokenX:
103ddde725dSArmin Le Grand                 {
104ddde725dSArmin Le Grand                     SvgNumber aNum;
105ddde725dSArmin Le Grand 
106ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
107ddde725dSArmin Le Grand                     {
108ddde725dSArmin Le Grand                         setX(aNum);
109ddde725dSArmin Le Grand                     }
110ddde725dSArmin Le Grand                     break;
111ddde725dSArmin Le Grand                 }
112ddde725dSArmin Le Grand                 case SVGTokenY:
113ddde725dSArmin Le Grand                 {
114ddde725dSArmin Le Grand                     SvgNumber aNum;
115ddde725dSArmin Le Grand 
116ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
117ddde725dSArmin Le Grand                     {
118ddde725dSArmin Le Grand                         setY(aNum);
119ddde725dSArmin Le Grand                     }
120ddde725dSArmin Le Grand                     break;
121ddde725dSArmin Le Grand                 }
122ddde725dSArmin Le Grand                 case SVGTokenWidth:
123ddde725dSArmin Le Grand                 {
124ddde725dSArmin Le Grand                     SvgNumber aNum;
125ddde725dSArmin Le Grand 
126ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
127ddde725dSArmin Le Grand                     {
128ddde725dSArmin Le Grand                         if(aNum.isPositive())
129ddde725dSArmin Le Grand                         {
130ddde725dSArmin Le Grand                             setWidth(aNum);
131ddde725dSArmin Le Grand                         }
132ddde725dSArmin Le Grand                     }
133ddde725dSArmin Le Grand                     break;
134ddde725dSArmin Le Grand                 }
135ddde725dSArmin Le Grand                 case SVGTokenHeight:
136ddde725dSArmin Le Grand                 {
137ddde725dSArmin Le Grand                     SvgNumber aNum;
138ddde725dSArmin Le Grand 
139ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
140ddde725dSArmin Le Grand                     {
141ddde725dSArmin Le Grand                         if(aNum.isPositive())
142ddde725dSArmin Le Grand                         {
143ddde725dSArmin Le Grand                             setHeight(aNum);
144ddde725dSArmin Le Grand                         }
145ddde725dSArmin Le Grand                     }
146ddde725dSArmin Le Grand                     break;
147ddde725dSArmin Le Grand                 }
148ddde725dSArmin Le Grand                 case SVGTokenVersion:
149ddde725dSArmin Le Grand                 {
150ddde725dSArmin Le Grand                     SvgNumber aNum;
151ddde725dSArmin Le Grand 
152ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
153ddde725dSArmin Le Grand                     {
154ddde725dSArmin Le Grand                         setVersion(aNum);
155ddde725dSArmin Le Grand                     }
156ddde725dSArmin Le Grand                     break;
157e2bf1e9dSArmin Le Grand                 }
158e2bf1e9dSArmin Le Grand                 default:
159e2bf1e9dSArmin Le Grand                 {
160e2bf1e9dSArmin Le Grand                     break;
161ddde725dSArmin Le Grand                 }
162ddde725dSArmin Le Grand             }
163ddde725dSArmin Le Grand         }
164ddde725dSArmin Le Grand 
165ddde725dSArmin Le Grand         void SvgSvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
166ddde725dSArmin Le Grand         {
167ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence aSequence;
168ddde725dSArmin Le Grand 
169ddde725dSArmin Le Grand             // decompose childs
170ddde725dSArmin Le Grand             SvgNode::decomposeSvgNode(aSequence, bReferenced);
171ddde725dSArmin Le Grand 
172ddde725dSArmin Le Grand             if(aSequence.hasElements())
173ddde725dSArmin Le Grand             {
174ddde725dSArmin Le Grand                 if(getParent())
175ddde725dSArmin Le Grand                 {
176*bca0eb5dSArmin Le Grand                     const bool bWidthIsRelative(!getWidth().isSet() || Unit_percent == getWidth().getUnit());
177*bca0eb5dSArmin Le Grand                     const bool bHeightIsRelative(!getWidth().isSet() || Unit_percent == getWidth().getUnit());
178*bca0eb5dSArmin Le Grand                     const SvgSvgNode* pParentSvgSvgNode = 0;
179*bca0eb5dSArmin Le Grand                     double fW(0.0);
180*bca0eb5dSArmin Le Grand                     double fH(0.0);
181*bca0eb5dSArmin Le Grand 
182*bca0eb5dSArmin Le Grand                     // #122594# if width/height is not given, it's 100% (see 5.1.2 The �svg� element in SVG1.1 spec).
183*bca0eb5dSArmin Le Grand                     // If it is relative, the question is to what. The previous implementatin assumed relative to the
184*bca0eb5dSArmin Le Grand                     // local ViewBox which is implied by (4.2 Basic data types):
185*bca0eb5dSArmin Le Grand                     //
186*bca0eb5dSArmin Le Grand                     // "Note that the non-property <length> definition also allows a percentage unit identifier.
187*bca0eb5dSArmin Le Grand                     // The meaning of a percentage length value depends on the attribute for which the percentage
188*bca0eb5dSArmin Le Grand                     // length value has been specified. Two common cases are: (a) when a percentage length value
189*bca0eb5dSArmin Le Grand                     // represents a percentage of the viewport width or height (refer to the section that discusses
190*bca0eb5dSArmin Le Grand                     // units in general), and (b) when a percentage length value represents a percentage of the
191*bca0eb5dSArmin Le Grand                     // bounding box width or height on a given object (refer to the section that describes object
192*bca0eb5dSArmin Le Grand                     // bounding box units)."
193*bca0eb5dSArmin Le Grand                     //
194*bca0eb5dSArmin Le Grand                     // This is not closer specified for the SVG element itself as non-outmost element, but comparisons
195*bca0eb5dSArmin Le Grand                     // with common browsers shows that it's mostly interpreted relative to the viewBox of the parent.
196*bca0eb5dSArmin Le Grand                     // Adding code to search the parent SVG element and calculating width/height relative to it's
197*bca0eb5dSArmin Le Grand                     // viewBox width/height (and no longer to the local viewBox).
198*bca0eb5dSArmin Le Grand                     if(bWidthIsRelative || bHeightIsRelative)
199*bca0eb5dSArmin Le Grand                     {
200*bca0eb5dSArmin Le Grand                         for(const SvgNode* pParent = getParent(); pParent && !pParentSvgSvgNode; pParent = pParent->getParent())
201*bca0eb5dSArmin Le Grand                         {
202*bca0eb5dSArmin Le Grand                             pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent);
203*bca0eb5dSArmin Le Grand                         }
204*bca0eb5dSArmin Le Grand                     }
205*bca0eb5dSArmin Le Grand 
206*bca0eb5dSArmin Le Grand                     if(bWidthIsRelative)
207*bca0eb5dSArmin Le Grand                     {
208*bca0eb5dSArmin Le Grand                         fW = getWidth().isSet() ? getWidth().getNumber() * 0.01 : 1.0;
209*bca0eb5dSArmin Le Grand 
210*bca0eb5dSArmin Le Grand                         if(pParentSvgSvgNode)
211*bca0eb5dSArmin Le Grand                         {
212*bca0eb5dSArmin Le Grand                             fW *= pParentSvgSvgNode->getViewBox()->getWidth();
213*bca0eb5dSArmin Le Grand                         }
214*bca0eb5dSArmin Le Grand                     }
215*bca0eb5dSArmin Le Grand                     else
216*bca0eb5dSArmin Le Grand                     {
217*bca0eb5dSArmin Le Grand                         fW = getWidth().solve(*this, xcoordinate);
218*bca0eb5dSArmin Le Grand                     }
219*bca0eb5dSArmin Le Grand 
220*bca0eb5dSArmin Le Grand                     if(bHeightIsRelative)
221*bca0eb5dSArmin Le Grand                     {
222*bca0eb5dSArmin Le Grand                         fH = getHeight().isSet() ? getHeight().getNumber() * 0.01 : 1.0;
223*bca0eb5dSArmin Le Grand 
224*bca0eb5dSArmin Le Grand                         if(pParentSvgSvgNode)
225*bca0eb5dSArmin Le Grand                         {
226*bca0eb5dSArmin Le Grand                             fH *= pParentSvgSvgNode->getViewBox()->getHeight();
227*bca0eb5dSArmin Le Grand                         }
228*bca0eb5dSArmin Le Grand                     }
229*bca0eb5dSArmin Le Grand                     else
230*bca0eb5dSArmin Le Grand                     {
231*bca0eb5dSArmin Le Grand                         fH = getHeight().solve(*this, ycoordinate);
232*bca0eb5dSArmin Le Grand                     }
233*bca0eb5dSArmin Le Grand 
234ddde725dSArmin Le Grand                     if(getViewBox())
235ddde725dSArmin Le Grand                     {
236ddde725dSArmin Le Grand                         // Svg defines that with no width or no height the viewBox content is empty,
237ddde725dSArmin Le Grand                         // so both need to exist
238ddde725dSArmin Le Grand                         if(!basegfx::fTools::equalZero(getViewBox()->getWidth()) && !basegfx::fTools::equalZero(getViewBox()->getHeight()))
239ddde725dSArmin Le Grand                         {
240ddde725dSArmin Le Grand                             // create target range homing x,y, width and height as given
241ddde725dSArmin Le Grand                             const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0);
242ddde725dSArmin Le Grand                             const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0);
243ddde725dSArmin Le Grand                             const basegfx::B2DRange aTarget(fX, fY, fX + fW, fY + fH);
244ddde725dSArmin Le Grand 
245ddde725dSArmin Le Grand                             if(aTarget.equal(*getViewBox()))
246ddde725dSArmin Le Grand                             {
247ddde725dSArmin Le Grand                                 // no mapping needed, append
248ddde725dSArmin Le Grand                                 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence);
249ddde725dSArmin Le Grand                             }
250ddde725dSArmin Le Grand                             else
251ddde725dSArmin Le Grand                             {
252ddde725dSArmin Le Grand                                 // create mapping
253ddde725dSArmin Le Grand                                 const SvgAspectRatio& rRatio = getSvgAspectRatio();
254ddde725dSArmin Le Grand 
255ddde725dSArmin Le Grand                                 if(rRatio.isSet())
256ddde725dSArmin Le Grand                                 {
257ddde725dSArmin Le Grand                                     // let mapping be created from SvgAspectRatio
258ddde725dSArmin Le Grand                                     const basegfx::B2DHomMatrix aEmbeddingTransform(
259ddde725dSArmin Le Grand                                         rRatio.createMapping(aTarget, *getViewBox()));
260ddde725dSArmin Le Grand 
261ddde725dSArmin Le Grand                                     // prepare embedding in transformation
262ddde725dSArmin Le Grand                                     const drawinglayer::primitive2d::Primitive2DReference xRef(
263ddde725dSArmin Le Grand                                         new drawinglayer::primitive2d::TransformPrimitive2D(
264ddde725dSArmin Le Grand                                             aEmbeddingTransform,
265ddde725dSArmin Le Grand                                             aSequence));
266ddde725dSArmin Le Grand 
267ddde725dSArmin Le Grand                                     if(rRatio.isMeetOrSlice())
268ddde725dSArmin Le Grand                                     {
269ddde725dSArmin Le Grand                                         // embed in transformation
270ddde725dSArmin Le Grand                                         drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef);
271ddde725dSArmin Le Grand                                     }
272ddde725dSArmin Le Grand                                     else
273ddde725dSArmin Le Grand                                     {
274ddde725dSArmin Le Grand                                         // need to embed in MaskPrimitive2D, too
275ddde725dSArmin Le Grand                                         const drawinglayer::primitive2d::Primitive2DReference xMask(
276ddde725dSArmin Le Grand                                             new drawinglayer::primitive2d::MaskPrimitive2D(
277ddde725dSArmin Le Grand                                                 basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)),
278ddde725dSArmin Le Grand                                                 drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1)));
279ddde725dSArmin Le Grand 
280ddde725dSArmin Le Grand                                         drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask);
281ddde725dSArmin Le Grand                                     }
282ddde725dSArmin Le Grand                                 }
283ddde725dSArmin Le Grand                                 else
284ddde725dSArmin Le Grand                                 {
285ddde725dSArmin Le Grand                                     // choose default mapping
286ddde725dSArmin Le Grand                                     const basegfx::B2DHomMatrix aEmbeddingTransform(
287ddde725dSArmin Le Grand                                         rRatio.createLinearMapping(
288ddde725dSArmin Le Grand                                             aTarget, *getViewBox()));
289ddde725dSArmin Le Grand 
290ddde725dSArmin Le Grand                                     // embed in transformation
291ddde725dSArmin Le Grand                                     const drawinglayer::primitive2d::Primitive2DReference xTransform(
292ddde725dSArmin Le Grand                                         new drawinglayer::primitive2d::TransformPrimitive2D(
293ddde725dSArmin Le Grand                                             aEmbeddingTransform,
294ddde725dSArmin Le Grand                                             aSequence));
295ddde725dSArmin Le Grand 
296ddde725dSArmin Le Grand                                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xTransform);
297ddde725dSArmin Le Grand                                 }
298ddde725dSArmin Le Grand                             }
299ddde725dSArmin Le Grand                         }
300ddde725dSArmin Le Grand                     }
301ddde725dSArmin Le Grand                     else
302ddde725dSArmin Le Grand                     {
303ddde725dSArmin Le Grand                         // Svg defines that a negative value is an error and that 0.0 disables rendering
304ddde725dSArmin Le Grand                         if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0))
305ddde725dSArmin Le Grand                         {
306ddde725dSArmin Le Grand                             // check if we have a x,y position
307ddde725dSArmin Le Grand                             const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0);
308ddde725dSArmin Le Grand                             const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0);
309ddde725dSArmin Le Grand 
310ddde725dSArmin Le Grand                             if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY))
311ddde725dSArmin Le Grand                             {
312ddde725dSArmin Le Grand                                 // embed in transform
313ddde725dSArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xRef(
314ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::TransformPrimitive2D(
315ddde725dSArmin Le Grand                                         basegfx::tools::createTranslateB2DHomMatrix(fX, fY),
316ddde725dSArmin Le Grand                                         aSequence));
317ddde725dSArmin Le Grand 
318ddde725dSArmin Le Grand                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
319ddde725dSArmin Le Grand                             }
320ddde725dSArmin Le Grand 
321ddde725dSArmin Le Grand                             // embed in MaskPrimitive2D to clip
322ddde725dSArmin Le Grand                             const drawinglayer::primitive2d::Primitive2DReference xMask(
323ddde725dSArmin Le Grand                                 new drawinglayer::primitive2d::MaskPrimitive2D(
324ddde725dSArmin Le Grand                                     basegfx::B2DPolyPolygon(
325ddde725dSArmin Le Grand                                         basegfx::tools::createPolygonFromRect(
326ddde725dSArmin Le Grand                                             basegfx::B2DRange(fX, fY, fX + fW, fY + fH))),
327ddde725dSArmin Le Grand                                     aSequence));
328ddde725dSArmin Le Grand 
329ddde725dSArmin Le Grand                             // append
330ddde725dSArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask);
331ddde725dSArmin Le Grand                         }
332ddde725dSArmin Le Grand                     }
333ddde725dSArmin Le Grand                 }
334ddde725dSArmin Le Grand                 else
335ddde725dSArmin Le Grand                 {
336ddde725dSArmin Le Grand                     // Outermost SVG element; create target range homing width and height as given.
337ddde725dSArmin Le Grand                     // SVG defines that x,y has no meanig for the outermost SVG element. Use a fallback
338ddde725dSArmin Le Grand                     // width and height of din A 4 (21 x 29,7 cm)
339ddde725dSArmin Le Grand                     double fW(getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : (210.0 * 3.543307));
340ddde725dSArmin Le Grand                     double fH(getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : (297.0 * 3.543307));
341ddde725dSArmin Le Grand 
342ddde725dSArmin Le Grand                     // Svg defines that a negative value is an error and that 0.0 disables rendering
343ddde725dSArmin Le Grand                     if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0))
344ddde725dSArmin Le Grand                     {
345ddde725dSArmin Le Grand                         const basegfx::B2DRange aSvgCanvasRange(0.0, 0.0, fW, fH);
346ddde725dSArmin Le Grand 
347ddde725dSArmin Le Grand                         if(getViewBox())
348ddde725dSArmin Le Grand                         {
349ddde725dSArmin Le Grand                             if(!basegfx::fTools::equalZero(getViewBox()->getWidth()) && !basegfx::fTools::equalZero(getViewBox()->getHeight()))
350ddde725dSArmin Le Grand                             {
351ddde725dSArmin Le Grand                                 // create mapping
352ddde725dSArmin Le Grand                                 const SvgAspectRatio& rRatio = getSvgAspectRatio();
353ddde725dSArmin Le Grand                                 basegfx::B2DHomMatrix aViewBoxMapping;
354ddde725dSArmin Le Grand 
355ddde725dSArmin Le Grand                                 if(rRatio.isSet())
356ddde725dSArmin Le Grand                                 {
357ddde725dSArmin Le Grand                                     // let mapping be created from SvgAspectRatio
358ddde725dSArmin Le Grand                                     aViewBoxMapping = rRatio.createMapping(aSvgCanvasRange, *getViewBox());
359ddde725dSArmin Le Grand 
360ddde725dSArmin Le Grand                                     // no need to check ratio here for slice, the outermost Svg will
361ddde725dSArmin Le Grand                                     // be clipped anyways (see below)
362ddde725dSArmin Le Grand                                 }
363ddde725dSArmin Le Grand                                 else
364ddde725dSArmin Le Grand                                 {
365ddde725dSArmin Le Grand                                     // choose default mapping
366ddde725dSArmin Le Grand                                     aViewBoxMapping = rRatio.createLinearMapping(aSvgCanvasRange, *getViewBox());
367ddde725dSArmin Le Grand                                 }
368ddde725dSArmin Le Grand 
369ddde725dSArmin Le Grand                                 // scale content to viewBox definitions
370ddde725dSArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xTransform(
371ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::TransformPrimitive2D(
372ddde725dSArmin Le Grand                                         aViewBoxMapping,
373ddde725dSArmin Le Grand                                         aSequence));
374ddde725dSArmin Le Grand 
375ddde725dSArmin Le Grand                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
376ddde725dSArmin Le Grand                             }
377ddde725dSArmin Le Grand                         }
378ddde725dSArmin Le Grand 
379ddde725dSArmin Le Grand                         // to be completely correct in Svg sense it is necessary to clip
380ddde725dSArmin Le Grand                         // the whole content to the given canvas. I choose here to do this
381ddde725dSArmin Le Grand                         // initially despite I found various examples of Svg files out there
382ddde725dSArmin Le Grand                         // which have no correct values for this clipping. It's correct
383ddde725dSArmin Le Grand                         // due to the Svg spec.
384ddde725dSArmin Le Grand                         bool bDoCorrectCanvasClipping(true);
385ddde725dSArmin Le Grand 
386ddde725dSArmin Le Grand                         if(bDoCorrectCanvasClipping)
387ddde725dSArmin Le Grand                         {
388ddde725dSArmin Le Grand                             // different from Svg we have the possibility with primitives to get
38941923119SArmin Le Grand                             // a correct bounding box for the geometry. Get it for evtl. taking action
390ddde725dSArmin Le Grand                             const basegfx::B2DRange aContentRange(
391ddde725dSArmin Le Grand                                 drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
392ddde725dSArmin Le Grand                                     aSequence,
393ddde725dSArmin Le Grand                                     drawinglayer::geometry::ViewInformation2D()));
394ddde725dSArmin Le Grand 
39541923119SArmin Le Grand                             if(aSvgCanvasRange.isInside(aContentRange))
396ddde725dSArmin Le Grand                             {
39741923119SArmin Le Grand                                 // no clip needed, but an invisible HiddenGeometryPrimitive2D
39841923119SArmin Le Grand                                 // to allow getting the full Svg range using the primitive mechanisms.
39941923119SArmin Le Grand                                 // This is needed since e.g. an SdrObject using this as graphic will
40041923119SArmin Le Grand                                 // create a mapping transformation to exactly map the content to it's
40141923119SArmin Le Grand                                 // real life size
40241923119SArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xLine(
40341923119SArmin Le Grand                                     new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
40441923119SArmin Le Grand                                         basegfx::tools::createPolygonFromRect(
40541923119SArmin Le Grand                                             aSvgCanvasRange),
40641923119SArmin Le Grand                                         basegfx::BColor(0.0, 0.0, 0.0)));
40741923119SArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xHidden(
40841923119SArmin Le Grand                                     new drawinglayer::primitive2d::HiddenGeometryPrimitive2D(
40941923119SArmin Le Grand                                         drawinglayer::primitive2d::Primitive2DSequence(&xLine, 1)));
41041923119SArmin Le Grand 
41141923119SArmin Le Grand                                 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aSequence, xHidden);
41241923119SArmin Le Grand                             }
41341923119SArmin Le Grand                             else if(aSvgCanvasRange.overlaps(aContentRange))
41441923119SArmin Le Grand                             {
41541923119SArmin Le Grand                                 // Clip is necessary. This will make Svg images evtl. smaller
41641923119SArmin Le Grand                                 // than wanted from Svg (the free space which may be around it is
41741923119SArmin Le Grand                                 // conform to the Svg spec), but avoids an expensive and unneccessary
41841923119SArmin Le Grand                                 // clip. Keep the full Svg range here to get the correct mappings
41941923119SArmin Le Grand                                 // to objects using this. Optimizations can be done in the processors
420ddde725dSArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xMask(
421ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::MaskPrimitive2D(
422ddde725dSArmin Le Grand                                         basegfx::B2DPolyPolygon(
423ddde725dSArmin Le Grand                                             basegfx::tools::createPolygonFromRect(
424ddde725dSArmin Le Grand                                                 aSvgCanvasRange)),
425ddde725dSArmin Le Grand                                         aSequence));
426ddde725dSArmin Le Grand 
427ddde725dSArmin Le Grand                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1);
428ddde725dSArmin Le Grand                             }
42941923119SArmin Le Grand                             else
43041923119SArmin Le Grand                             {
43141923119SArmin Le Grand                                 // not inside, no overlap. Empty Svg
43241923119SArmin Le Grand                                 aSequence.realloc(0);
43341923119SArmin Le Grand                             }
434ddde725dSArmin Le Grand                         }
435ddde725dSArmin Le Grand 
43641923119SArmin Le Grand                         if(aSequence.hasElements())
437ddde725dSArmin Le Grand                         {
438ddde725dSArmin Le Grand                             // embed in transform primitive to scale to 1/100th mm
439ddde725dSArmin Le Grand                             // where 1 mm == 3.543307 px to get from Svg coordinates to
440ddde725dSArmin Le Grand                             // drawinglayer ones
441ddde725dSArmin Le Grand                             const double fScaleTo100thmm(100.0 / 3.543307);
442ddde725dSArmin Le Grand                             const basegfx::B2DHomMatrix aTransform(
443ddde725dSArmin Le Grand                                 basegfx::tools::createScaleB2DHomMatrix(
444ddde725dSArmin Le Grand                                     fScaleTo100thmm,
445ddde725dSArmin Le Grand                                     fScaleTo100thmm));
446ddde725dSArmin Le Grand 
447ddde725dSArmin Le Grand                             const drawinglayer::primitive2d::Primitive2DReference xTransform(
448ddde725dSArmin Le Grand                                 new drawinglayer::primitive2d::TransformPrimitive2D(
449ddde725dSArmin Le Grand                                     aTransform,
450ddde725dSArmin Le Grand                                     aSequence));
451ddde725dSArmin Le Grand 
452ddde725dSArmin Le Grand                             aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
453ddde725dSArmin Le Grand 
45441923119SArmin Le Grand                             // append to result
45541923119SArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence);
45641923119SArmin Le Grand                         }
457ddde725dSArmin Le Grand                     }
458ddde725dSArmin Le Grand                 }
459ddde725dSArmin Le Grand             }
460ddde725dSArmin Le Grand         }
461ddde725dSArmin Le Grand 
462ddde725dSArmin Le Grand         const basegfx::B2DRange* SvgSvgNode::getCurrentViewPort() const
463ddde725dSArmin Le Grand         {
464ddde725dSArmin Le Grand             if(getViewBox())
465ddde725dSArmin Le Grand             {
466ddde725dSArmin Le Grand                 return getViewBox();
467ddde725dSArmin Le Grand             }
468ddde725dSArmin Le Grand             else
469ddde725dSArmin Le Grand             {
470ddde725dSArmin Le Grand                 return SvgNode::getCurrentViewPort();
471ddde725dSArmin Le Grand             }
472ddde725dSArmin Le Grand         }
473ddde725dSArmin Le Grand 
474ddde725dSArmin Le Grand     } // end of namespace svgreader
475ddde725dSArmin Le Grand } // end of namespace svgio
476ddde725dSArmin Le Grand 
477ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
478ddde725dSArmin Le Grand // eof
479