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 
165*2169cc62SArmin Le Grand         void SvgSvgNode::seekReferenceWidth(double& fWidth, bool& bHasFound) const
166*2169cc62SArmin Le Grand         {
167*2169cc62SArmin Le Grand             if (!getParent() || bHasFound)
168*2169cc62SArmin Le Grand             {
169*2169cc62SArmin Le Grand                 return;
170*2169cc62SArmin Le Grand             }
171*2169cc62SArmin Le Grand             const SvgSvgNode* pParentSvgSvgNode = 0;
172*2169cc62SArmin Le Grand             // enclosing svg might have relative width, need to cumulate them till they are
173*2169cc62SArmin Le Grand             // resolved somewhere up in the node tree
174*2169cc62SArmin Le Grand             double fPercentage(1.0);
175*2169cc62SArmin Le Grand             for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent())
176*2169cc62SArmin Le Grand             {
177*2169cc62SArmin Le Grand                 // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition
178*2169cc62SArmin Le Grand                 pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent);
179*2169cc62SArmin Le Grand                 if (pParentSvgSvgNode)
180*2169cc62SArmin Le Grand                 {
181*2169cc62SArmin Le Grand                     if (pParentSvgSvgNode->getViewBox())
182*2169cc62SArmin Le Grand                     {
183*2169cc62SArmin Le Grand                         // viewbox values are already in 'user unit'.
184*2169cc62SArmin Le Grand                         fWidth = pParentSvgSvgNode->getViewBox()->getWidth() * fPercentage;
185*2169cc62SArmin Le Grand                         bHasFound = true;
186*2169cc62SArmin Le Grand                     }
187*2169cc62SArmin Le Grand                     else
188*2169cc62SArmin Le Grand                     {
189*2169cc62SArmin Le Grand                         // take absolute value or cummulate percentage
190*2169cc62SArmin Le Grand                         if (pParentSvgSvgNode->getWidth().isSet())
191*2169cc62SArmin Le Grand                         {
192*2169cc62SArmin Le Grand                             if (Unit_percent == pParentSvgSvgNode->getWidth().getUnit())
193*2169cc62SArmin Le Grand                             {
194*2169cc62SArmin Le Grand                                 fPercentage *= pParentSvgSvgNode->getWidth().getNumber() * 0.01;
195*2169cc62SArmin Le Grand                             }
196*2169cc62SArmin Le Grand                             else
197*2169cc62SArmin Le Grand                             {
198*2169cc62SArmin Le Grand                                 fWidth = pParentSvgSvgNode->getWidth().solveNonPercentage(*pParentSvgSvgNode) * fPercentage;
199*2169cc62SArmin Le Grand                                 bHasFound = true;
200*2169cc62SArmin Le Grand                             }
201*2169cc62SArmin Le Grand                         } // not set => width=100% => factor 1, no need for else
202*2169cc62SArmin Le Grand                     }
203*2169cc62SArmin Le Grand                 }
204*2169cc62SArmin Le Grand             }
205*2169cc62SArmin Le Grand         }
206*2169cc62SArmin Le Grand 
207*2169cc62SArmin Le Grand         void SvgSvgNode::seekReferenceHeight(double& fHeight, bool& bHasFound) const
208*2169cc62SArmin Le Grand         {
209*2169cc62SArmin Le Grand             if (!getParent() || bHasFound)
210*2169cc62SArmin Le Grand             {
211*2169cc62SArmin Le Grand                 return;
212*2169cc62SArmin Le Grand             }
213*2169cc62SArmin Le Grand             const SvgSvgNode* pParentSvgSvgNode = 0;
214*2169cc62SArmin Le Grand             // enclosing svg might have relative width and height, need to cumulate them till they are
215*2169cc62SArmin Le Grand             // resolved somewhere up in the node tree
216*2169cc62SArmin Le Grand             double fPercentage(1.0);
217*2169cc62SArmin Le Grand             for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent())
218*2169cc62SArmin Le Grand             {
219*2169cc62SArmin Le Grand                 // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition
220*2169cc62SArmin Le Grand                 pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent);
221*2169cc62SArmin Le Grand                 if (pParentSvgSvgNode)
222*2169cc62SArmin Le Grand                 {
223*2169cc62SArmin Le Grand                     if (pParentSvgSvgNode->getViewBox())
224*2169cc62SArmin Le Grand                     {
225*2169cc62SArmin Le Grand                         // viewbox values are already in 'user unit'.
226*2169cc62SArmin Le Grand                         fHeight = pParentSvgSvgNode->getViewBox()->getHeight() * fPercentage;
227*2169cc62SArmin Le Grand                         bHasFound = true;
228*2169cc62SArmin Le Grand                     }
229*2169cc62SArmin Le Grand                     else
230*2169cc62SArmin Le Grand                     {
231*2169cc62SArmin Le Grand                         // take absolute value or cummulate percentage
232*2169cc62SArmin Le Grand                         if (pParentSvgSvgNode->getHeight().isSet())
233*2169cc62SArmin Le Grand                         {
234*2169cc62SArmin Le Grand                             if (Unit_percent == pParentSvgSvgNode->getHeight().getUnit())
235*2169cc62SArmin Le Grand                             {
236*2169cc62SArmin Le Grand                                 fPercentage *= pParentSvgSvgNode->getHeight().getNumber() * 0.01;
237*2169cc62SArmin Le Grand                             }
238*2169cc62SArmin Le Grand                             else
239*2169cc62SArmin Le Grand                             {
240*2169cc62SArmin Le Grand                                 fHeight = pParentSvgSvgNode->getHeight().solveNonPercentage(*pParentSvgSvgNode) * fPercentage;
241*2169cc62SArmin Le Grand                                 bHasFound = true;
242*2169cc62SArmin Le Grand                             }
243*2169cc62SArmin Le Grand                         } // not set => height=100% => factor 1, no need for else
244*2169cc62SArmin Le Grand                     }
245*2169cc62SArmin Le Grand                 }
246*2169cc62SArmin Le Grand             }
247*2169cc62SArmin Le Grand         }
248*2169cc62SArmin Le Grand 
249*2169cc62SArmin Le Grand // ToDo: Consider attribute overflow in method decomposeSvgNode
250ddde725dSArmin Le Grand         void SvgSvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
251ddde725dSArmin Le Grand         {
252ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence aSequence;
253ddde725dSArmin Le Grand 
254ddde725dSArmin Le Grand             // decompose childs
255ddde725dSArmin Le Grand             SvgNode::decomposeSvgNode(aSequence, bReferenced);
256ddde725dSArmin Le Grand 
257ddde725dSArmin Le Grand             if(aSequence.hasElements())
258ddde725dSArmin Le Grand             {
259ddde725dSArmin Le Grand                 if(getParent())
260ddde725dSArmin Le Grand                 {
261*2169cc62SArmin Le Grand                     // #122594# if width/height is not given, it's 100% (see 5.1.2 The 'svg' element in SVG1.1 spec).
262bca0eb5dSArmin Le Grand                     // If it is relative, the question is to what. The previous implementatin assumed relative to the
263bca0eb5dSArmin Le Grand                     // local ViewBox which is implied by (4.2 Basic data types):
264bca0eb5dSArmin Le Grand                     //
265bca0eb5dSArmin Le Grand                     // "Note that the non-property <length> definition also allows a percentage unit identifier.
266bca0eb5dSArmin Le Grand                     // The meaning of a percentage length value depends on the attribute for which the percentage
267bca0eb5dSArmin Le Grand                     // length value has been specified. Two common cases are: (a) when a percentage length value
268bca0eb5dSArmin Le Grand                     // represents a percentage of the viewport width or height (refer to the section that discusses
269bca0eb5dSArmin Le Grand                     // units in general), and (b) when a percentage length value represents a percentage of the
270bca0eb5dSArmin Le Grand                     // bounding box width or height on a given object (refer to the section that describes object
271bca0eb5dSArmin Le Grand                     // bounding box units)."
272*2169cc62SArmin Le Grand 
273*2169cc62SArmin Le Grand                     // Comparisons with commom browsers show, that it's mostly interpreted relative to the viewport
274*2169cc62SArmin Le Grand                     // of the parent, and so does the new implementation.
275*2169cc62SArmin Le Grand 
276*2169cc62SArmin Le Grand                     // Extract known viewport data
277*2169cc62SArmin Le Grand                     // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values
278*2169cc62SArmin Le Grand 
279*2169cc62SArmin Le Grand                     // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2
280*2169cc62SArmin Le Grand                     // value 0.0 here is only to initialize variable
281*2169cc62SArmin Le Grand                     bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
282*2169cc62SArmin Le Grand                     double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0);
283*2169cc62SArmin Le Grand 
284*2169cc62SArmin Le Grand                     bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
285*2169cc62SArmin Le Grand                     double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0);
286*2169cc62SArmin Le Grand 
287*2169cc62SArmin Le Grand                     // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2
288*2169cc62SArmin Le Grand                     bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet());
289*2169cc62SArmin Le Grand                     double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0);
290*2169cc62SArmin Le Grand 
291*2169cc62SArmin Le Grand                     bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet());
292*2169cc62SArmin Le Grand                     double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0);
293*2169cc62SArmin Le Grand 
294*2169cc62SArmin Le Grand                     if ( !bXIsAbsolute || !bWidthIsAbsolute)
295bca0eb5dSArmin Le Grand                     {
296*2169cc62SArmin Le Grand                         // get width of enclosing svg and resolve percentage in x and width;
297*2169cc62SArmin Le Grand                         double fWReference(0.0);
298*2169cc62SArmin Le Grand                         bool bHasFoundWidth(false);
299*2169cc62SArmin Le Grand                         seekReferenceWidth(fWReference, bHasFoundWidth);
300*2169cc62SArmin Le Grand                         if (!bHasFoundWidth)
301bca0eb5dSArmin Le Grand                         {
302*2169cc62SArmin Le Grand                             // Even outermost svg has not all information to resolve relative values,
303*2169cc62SArmin Le Grand                             // I use content itself as fallback to set missing values for viewport
304*2169cc62SArmin Le Grand                             // Any better idea for such ill structures svg documents?
305*2169cc62SArmin Le Grand                             const basegfx::B2DRange aChildRange(
306*2169cc62SArmin Le Grand                                         drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
307*2169cc62SArmin Le Grand                                             aSequence,
308*2169cc62SArmin Le Grand                                         drawinglayer::geometry::ViewInformation2D()));
309*2169cc62SArmin Le Grand                             fWReference = aChildRange.getWidth();
310bca0eb5dSArmin Le Grand                         }
311*2169cc62SArmin Le Grand                         // referenced values are already in 'user unit'
312*2169cc62SArmin Le Grand                         if (!bXIsAbsolute)
313bca0eb5dSArmin Le Grand                         {
314*2169cc62SArmin Le Grand                             fX = getX().getNumber() * 0.01 * fWReference;
315*2169cc62SArmin Le Grand                         }
316*2169cc62SArmin Le Grand                         if (!bWidthIsAbsolute)
317*2169cc62SArmin Le Grand                         {
318*2169cc62SArmin Le Grand                             fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference;
319bca0eb5dSArmin Le Grand                         }
320bca0eb5dSArmin Le Grand                     }
321bca0eb5dSArmin Le Grand 
322*2169cc62SArmin Le Grand                     if ( !bYIsAbsolute || !bHeightIsAbsolute)
323bca0eb5dSArmin Le Grand                     {
324*2169cc62SArmin Le Grand                         // get height of enclosing svg and resolve percentage in y and height
325*2169cc62SArmin Le Grand                         double fHReference(0.0);
326*2169cc62SArmin Le Grand                         bool bHasFoundHeight(false);
327*2169cc62SArmin Le Grand                         seekReferenceHeight(fHReference, bHasFoundHeight);
328*2169cc62SArmin Le Grand                         if (!bHasFoundHeight)
329*2169cc62SArmin Le Grand                         {
330*2169cc62SArmin Le Grand                             // Even outermost svg has not all information to resolve relative values,
331*2169cc62SArmin Le Grand                             // I use content itself as fallback to set missing values for viewport
332*2169cc62SArmin Le Grand                             // Any better idea for such ill structures svg documents?
333*2169cc62SArmin Le Grand                             const basegfx::B2DRange aChildRange(
334*2169cc62SArmin Le Grand                                         drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
335*2169cc62SArmin Le Grand                                             aSequence,
336*2169cc62SArmin Le Grand                                         drawinglayer::geometry::ViewInformation2D()));
337*2169cc62SArmin Le Grand                             fHReference = aChildRange.getHeight();
338*2169cc62SArmin Le Grand                         }
339bca0eb5dSArmin Le Grand 
340*2169cc62SArmin Le Grand                         // referenced values are already in 'user unit'
341*2169cc62SArmin Le Grand                         if (!bYIsAbsolute)
342bca0eb5dSArmin Le Grand                         {
343*2169cc62SArmin Le Grand                             fY = getY().getNumber() * 0.01 * fHReference;
344*2169cc62SArmin Le Grand                         }
345*2169cc62SArmin Le Grand                         if (!bHeightIsAbsolute)
346*2169cc62SArmin Le Grand                         {
347*2169cc62SArmin Le Grand                             fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference;
348bca0eb5dSArmin Le Grand                         }
349bca0eb5dSArmin Le Grand                     }
350bca0eb5dSArmin Le Grand 
351ddde725dSArmin Le Grand                     if(getViewBox())
352ddde725dSArmin Le Grand                     {
353*2169cc62SArmin Le Grand                         // SVG 1.1 defines in section 7.7 that a negative value for width or height
354*2169cc62SArmin Le Grand                         // in viewBox is an error and that 0.0 disables rendering
355*2169cc62SArmin Le Grand                         if(basegfx::fTools::more(getViewBox()->getWidth(),0.0) && basegfx::fTools::more(getViewBox()->getHeight(),0.0))
356ddde725dSArmin Le Grand                         {
357*2169cc62SArmin Le Grand                             // create target range homing x,y, width and height as calculated above
358ddde725dSArmin Le Grand                             const basegfx::B2DRange aTarget(fX, fY, fX + fW, fY + fH);
359ddde725dSArmin Le Grand 
360ddde725dSArmin Le Grand                             if(aTarget.equal(*getViewBox()))
361ddde725dSArmin Le Grand                             {
362ddde725dSArmin Le Grand                                 // no mapping needed, append
363ddde725dSArmin Le Grand                                 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence);
364ddde725dSArmin Le Grand                             }
365ddde725dSArmin Le Grand                             else
366ddde725dSArmin Le Grand                             {
367ddde725dSArmin Le Grand                                 // create mapping
368*2169cc62SArmin Le Grand                                 // #i122610 SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified,
369*2169cc62SArmin Le Grand                                 // then the effect is as if a value of 'xMidYMid meet' were specified.
370*2169cc62SArmin Le Grand                                 SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true);
371*2169cc62SArmin Le Grand                                 const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault;
372*2169cc62SArmin Le Grand 
373*2169cc62SArmin Le Grand                                 // let mapping be created from SvgAspectRatio
374*2169cc62SArmin Le Grand                                 const basegfx::B2DHomMatrix aEmbeddingTransform(
375*2169cc62SArmin Le Grand                                     rRatio.createMapping(aTarget, *getViewBox()));
376*2169cc62SArmin Le Grand 
377*2169cc62SArmin Le Grand                                 // prepare embedding in transformation
378*2169cc62SArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xRef(
379*2169cc62SArmin Le Grand                                     new drawinglayer::primitive2d::TransformPrimitive2D(
380*2169cc62SArmin Le Grand                                         aEmbeddingTransform,
381*2169cc62SArmin Le Grand                                         aSequence));
382ddde725dSArmin Le Grand 
383*2169cc62SArmin Le Grand                                 if(rRatio.isMeetOrSlice())
384ddde725dSArmin Le Grand                                 {
385*2169cc62SArmin Le Grand                                     // embed in transformation
386*2169cc62SArmin Le Grand                                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef);
387ddde725dSArmin Le Grand                                 }
388ddde725dSArmin Le Grand                                 else
389ddde725dSArmin Le Grand                                 {
390*2169cc62SArmin Le Grand                                     // need to embed in MaskPrimitive2D, too
391*2169cc62SArmin Le Grand                                     const drawinglayer::primitive2d::Primitive2DReference xMask(
392*2169cc62SArmin Le Grand                                         new drawinglayer::primitive2d::MaskPrimitive2D(
393*2169cc62SArmin Le Grand                                             basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)),
394*2169cc62SArmin Le Grand                                             drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1)));
395ddde725dSArmin Le Grand 
396*2169cc62SArmin Le Grand                                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask);
397ddde725dSArmin Le Grand                                 }
398ddde725dSArmin Le Grand                             }
399ddde725dSArmin Le Grand                         }
400ddde725dSArmin Le Grand                     }
401*2169cc62SArmin Le Grand                     else // no viewBox attribute
402ddde725dSArmin Le Grand                     {
403ddde725dSArmin Le Grand                         // Svg defines that a negative value is an error and that 0.0 disables rendering
404ddde725dSArmin Le Grand                         if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0))
405ddde725dSArmin Le Grand                         {
406ddde725dSArmin Le Grand                             if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY))
407ddde725dSArmin Le Grand                             {
408ddde725dSArmin Le Grand                                 // embed in transform
409ddde725dSArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xRef(
410ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::TransformPrimitive2D(
411ddde725dSArmin Le Grand                                         basegfx::tools::createTranslateB2DHomMatrix(fX, fY),
412ddde725dSArmin Le Grand                                         aSequence));
413ddde725dSArmin Le Grand 
414ddde725dSArmin Le Grand                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
415ddde725dSArmin Le Grand                             }
416ddde725dSArmin Le Grand 
417ddde725dSArmin Le Grand                             // embed in MaskPrimitive2D to clip
418ddde725dSArmin Le Grand                             const drawinglayer::primitive2d::Primitive2DReference xMask(
419ddde725dSArmin Le Grand                                 new drawinglayer::primitive2d::MaskPrimitive2D(
420ddde725dSArmin Le Grand                                     basegfx::B2DPolyPolygon(
421ddde725dSArmin Le Grand                                         basegfx::tools::createPolygonFromRect(
422ddde725dSArmin Le Grand                                             basegfx::B2DRange(fX, fY, fX + fW, fY + fH))),
423ddde725dSArmin Le Grand                                     aSequence));
424ddde725dSArmin Le Grand 
425ddde725dSArmin Le Grand                             // append
426ddde725dSArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask);
427ddde725dSArmin Le Grand                         }
428ddde725dSArmin Le Grand                     }
429ddde725dSArmin Le Grand                 }
430*2169cc62SArmin Le Grand                 else // Outermost SVG element
431ddde725dSArmin Le Grand                 {
432*2169cc62SArmin Le Grand                     double fW = 0.0; // effective value depends on viewBox
433*2169cc62SArmin Le Grand                     double fH = 0.0;
434ddde725dSArmin Le Grand 
435ddde725dSArmin Le Grand                     // Svg defines that a negative value is an error and that 0.0 disables rendering
436*2169cc62SArmin Le Grand                     // isPositive() not usable because it allows 0.0 in contrast to mathematical definition of 'positive'
437*2169cc62SArmin Le Grand                     const bool bWidthInvalid(getWidth().isSet() && basegfx::fTools::lessOrEqual(getWidth().getNumber(), 0.0));
438*2169cc62SArmin Le Grand                     const bool bHeightInvalid(getHeight().isSet() && basegfx::fTools::lessOrEqual(getHeight().getNumber(), 0.0));
439*2169cc62SArmin Le Grand                     if(!bWidthInvalid && !bHeightInvalid)
440ddde725dSArmin Le Grand                     {
441*2169cc62SArmin Le Grand                         basegfx::B2DRange aSvgCanvasRange; // effective value depends on viewBox
442ddde725dSArmin Le Grand                         if(getViewBox())
443ddde725dSArmin Le Grand                         {
444*2169cc62SArmin Le Grand                             // SVG 1.1 defines in section 7.7 that a negative value for width or height
445*2169cc62SArmin Le Grand                             // in viewBox is an error and that 0.0 disables rendering
446*2169cc62SArmin Le Grand                             const double fViewBoxWidth = getViewBox()->getWidth();
447*2169cc62SArmin Le Grand                             const double fViewBoxHeight = getViewBox()->getHeight();
448*2169cc62SArmin Le Grand                             if(basegfx::fTools::more(fViewBoxWidth,0.0) && basegfx::fTools::more(fViewBoxHeight,0.0))
449ddde725dSArmin Le Grand                             {
450*2169cc62SArmin Le Grand                                 // The intrinsic aspect ratio of the svg element is given by absolute values of both width and height
451*2169cc62SArmin Le Grand                                 // or if one or both of them is relative by the width and height of the viewBox
452*2169cc62SArmin Le Grand                                 // see SVG 1.1 section 7.12
453*2169cc62SArmin Le Grand                                 const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
454*2169cc62SArmin Le Grand                                 const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
455*2169cc62SArmin Le Grand                                 if(bWidthIsAbsolute && bHeightIsAbsolute)
456ddde725dSArmin Le Grand                                 {
457*2169cc62SArmin Le Grand                                     fW =getWidth().solveNonPercentage(*this);
458*2169cc62SArmin Le Grand                                     fH =getHeight().solveNonPercentage(*this);
459*2169cc62SArmin Le Grand                                 }
460*2169cc62SArmin Le Grand                                 else if (bWidthIsAbsolute)
461*2169cc62SArmin Le Grand                                 {
462*2169cc62SArmin Le Grand                                     fW = getWidth().solveNonPercentage(*this);
463*2169cc62SArmin Le Grand                                     fH = fW * fViewBoxWidth / fViewBoxHeight ;
464*2169cc62SArmin Le Grand                                 }
465*2169cc62SArmin Le Grand                                 else if (bHeightIsAbsolute)
466*2169cc62SArmin Le Grand                                 {
467*2169cc62SArmin Le Grand                                     fH = getHeight().solveNonPercentage(*this);
468*2169cc62SArmin Le Grand                                     fW = fH * fViewBoxWidth / fViewBoxHeight ;
469ddde725dSArmin Le Grand                                 }
470ddde725dSArmin Le Grand                                 else
471ddde725dSArmin Le Grand                                 {
472*2169cc62SArmin Le Grand                                     fW = fViewBoxWidth;
473*2169cc62SArmin Le Grand                                     fH = fViewBoxHeight;
474ddde725dSArmin Le Grand                                 }
475*2169cc62SArmin Le Grand                                 // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element.
476*2169cc62SArmin Le Grand                                 aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH);
477*2169cc62SArmin Le Grand 
478*2169cc62SArmin Le Grand                                 // create mapping
479*2169cc62SArmin Le Grand                                 // SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified,
480*2169cc62SArmin Le Grand                                 // then the effect is as if a value of 'xMidYMid meet' were specified.
481*2169cc62SArmin Le Grand                                 SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true);
482*2169cc62SArmin Le Grand                                 const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault;
483*2169cc62SArmin Le Grand 
484*2169cc62SArmin Le Grand                                 basegfx::B2DHomMatrix aViewBoxMapping;
485*2169cc62SArmin Le Grand                                 aViewBoxMapping = rRatio.createMapping(aSvgCanvasRange, *getViewBox());
486*2169cc62SArmin Le Grand                                 // no need to check ratio here for slice, the outermost Svg will
487*2169cc62SArmin Le Grand                                 // be clipped anyways (see below)
488ddde725dSArmin Le Grand 
489ddde725dSArmin Le Grand                                 // scale content to viewBox definitions
490ddde725dSArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xTransform(
491ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::TransformPrimitive2D(
492ddde725dSArmin Le Grand                                         aViewBoxMapping,
493ddde725dSArmin Le Grand                                         aSequence));
494ddde725dSArmin Le Grand 
495ddde725dSArmin Le Grand                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
496ddde725dSArmin Le Grand                             }
497ddde725dSArmin Le Grand                         }
498*2169cc62SArmin Le Grand                         else // no viewbox
499*2169cc62SArmin Le Grand                         {
500*2169cc62SArmin Le Grand                            // There exists no parent to resolve relative width or height.
501*2169cc62SArmin Le Grand                            // Use child size as fallback.
502*2169cc62SArmin Le Grand                             const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
503*2169cc62SArmin Le Grand                             const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
504*2169cc62SArmin Le Grand                             if (bWidthIsAbsolute && bHeightIsAbsolute)
505*2169cc62SArmin Le Grand                             {
506*2169cc62SArmin Le Grand                                 fW =getWidth().solveNonPercentage(*this);
507*2169cc62SArmin Le Grand                                 fH =getHeight().solveNonPercentage(*this);
508*2169cc62SArmin Le Grand 
509*2169cc62SArmin Le Grand                             }
510*2169cc62SArmin Le Grand                             else
511*2169cc62SArmin Le Grand                             {
512*2169cc62SArmin Le Grand                                 const basegfx::B2DRange aChildRange(
513*2169cc62SArmin Le Grand                                     drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
514*2169cc62SArmin Le Grand                                         aSequence,
515*2169cc62SArmin Le Grand                                      drawinglayer::geometry::ViewInformation2D()));
516*2169cc62SArmin Le Grand                                 const double fChildWidth(aChildRange.getWidth());
517*2169cc62SArmin Le Grand                                 const double fChildHeight(aChildRange.getHeight());
518*2169cc62SArmin Le Grand                                 fW = bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : fChildWidth;
519*2169cc62SArmin Le Grand                                 fH = bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : fChildHeight;
520*2169cc62SArmin Le Grand                             }
521*2169cc62SArmin Le Grand                             // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element.
522*2169cc62SArmin Le Grand                             aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH);
523*2169cc62SArmin Le Grand                         }
524ddde725dSArmin Le Grand 
525ddde725dSArmin Le Grand                         // to be completely correct in Svg sense it is necessary to clip
526ddde725dSArmin Le Grand                         // the whole content to the given canvas. I choose here to do this
527ddde725dSArmin Le Grand                         // initially despite I found various examples of Svg files out there
528ddde725dSArmin Le Grand                         // which have no correct values for this clipping. It's correct
529ddde725dSArmin Le Grand                         // due to the Svg spec.
530ddde725dSArmin Le Grand                         bool bDoCorrectCanvasClipping(true);
531ddde725dSArmin Le Grand 
532ddde725dSArmin Le Grand                         if(bDoCorrectCanvasClipping)
533ddde725dSArmin Le Grand                         {
534ddde725dSArmin Le Grand                             // different from Svg we have the possibility with primitives to get
53541923119SArmin Le Grand                             // a correct bounding box for the geometry. Get it for evtl. taking action
536ddde725dSArmin Le Grand                             const basegfx::B2DRange aContentRange(
537ddde725dSArmin Le Grand                                 drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
538ddde725dSArmin Le Grand                                     aSequence,
539ddde725dSArmin Le Grand                                     drawinglayer::geometry::ViewInformation2D()));
540ddde725dSArmin Le Grand 
54141923119SArmin Le Grand                             if(aSvgCanvasRange.isInside(aContentRange))
542ddde725dSArmin Le Grand                             {
54341923119SArmin Le Grand                                 // no clip needed, but an invisible HiddenGeometryPrimitive2D
54441923119SArmin Le Grand                                 // to allow getting the full Svg range using the primitive mechanisms.
54541923119SArmin Le Grand                                 // This is needed since e.g. an SdrObject using this as graphic will
54641923119SArmin Le Grand                                 // create a mapping transformation to exactly map the content to it's
54741923119SArmin Le Grand                                 // real life size
54841923119SArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xLine(
54941923119SArmin Le Grand                                     new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
55041923119SArmin Le Grand                                         basegfx::tools::createPolygonFromRect(
55141923119SArmin Le Grand                                             aSvgCanvasRange),
55241923119SArmin Le Grand                                         basegfx::BColor(0.0, 0.0, 0.0)));
55341923119SArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xHidden(
55441923119SArmin Le Grand                                     new drawinglayer::primitive2d::HiddenGeometryPrimitive2D(
55541923119SArmin Le Grand                                         drawinglayer::primitive2d::Primitive2DSequence(&xLine, 1)));
55641923119SArmin Le Grand 
55741923119SArmin Le Grand                                 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aSequence, xHidden);
55841923119SArmin Le Grand                             }
55941923119SArmin Le Grand                             else if(aSvgCanvasRange.overlaps(aContentRange))
56041923119SArmin Le Grand                             {
56141923119SArmin Le Grand                                 // Clip is necessary. This will make Svg images evtl. smaller
56241923119SArmin Le Grand                                 // than wanted from Svg (the free space which may be around it is
56341923119SArmin Le Grand                                 // conform to the Svg spec), but avoids an expensive and unneccessary
56441923119SArmin Le Grand                                 // clip. Keep the full Svg range here to get the correct mappings
56541923119SArmin Le Grand                                 // to objects using this. Optimizations can be done in the processors
566ddde725dSArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xMask(
567ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::MaskPrimitive2D(
568ddde725dSArmin Le Grand                                         basegfx::B2DPolyPolygon(
569ddde725dSArmin Le Grand                                             basegfx::tools::createPolygonFromRect(
570ddde725dSArmin Le Grand                                                 aSvgCanvasRange)),
571ddde725dSArmin Le Grand                                         aSequence));
572ddde725dSArmin Le Grand 
573ddde725dSArmin Le Grand                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1);
574ddde725dSArmin Le Grand                             }
57541923119SArmin Le Grand                             else
57641923119SArmin Le Grand                             {
57741923119SArmin Le Grand                                 // not inside, no overlap. Empty Svg
57841923119SArmin Le Grand                                 aSequence.realloc(0);
57941923119SArmin Le Grand                             }
580ddde725dSArmin Le Grand                         }
581ddde725dSArmin Le Grand 
58241923119SArmin Le Grand                         if(aSequence.hasElements())
583ddde725dSArmin Le Grand                         {
584ddde725dSArmin Le Grand                             // embed in transform primitive to scale to 1/100th mm
585*2169cc62SArmin Le Grand                             // where 1 inch == 25.4 mm to get from Svg coordinates (px) to
586*2169cc62SArmin Le Grand                             // drawinglayer coordinates
587*2169cc62SArmin Le Grand                             const double fScaleTo100thmm(25.4 * 100.0 / F_SVG_PIXEL_PER_INCH);
588ddde725dSArmin Le Grand                             const basegfx::B2DHomMatrix aTransform(
589ddde725dSArmin Le Grand                                 basegfx::tools::createScaleB2DHomMatrix(
590ddde725dSArmin Le Grand                                     fScaleTo100thmm,
591ddde725dSArmin Le Grand                                     fScaleTo100thmm));
592ddde725dSArmin Le Grand 
593ddde725dSArmin Le Grand                             const drawinglayer::primitive2d::Primitive2DReference xTransform(
594ddde725dSArmin Le Grand                                 new drawinglayer::primitive2d::TransformPrimitive2D(
595ddde725dSArmin Le Grand                                     aTransform,
596ddde725dSArmin Le Grand                                     aSequence));
597ddde725dSArmin Le Grand 
598ddde725dSArmin Le Grand                             aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
599ddde725dSArmin Le Grand 
60041923119SArmin Le Grand                             // append to result
60141923119SArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence);
60241923119SArmin Le Grand                         }
603ddde725dSArmin Le Grand                     }
604ddde725dSArmin Le Grand                 }
605ddde725dSArmin Le Grand             }
606ddde725dSArmin Le Grand         }
607ddde725dSArmin Le Grand 
608ddde725dSArmin Le Grand         const basegfx::B2DRange* SvgSvgNode::getCurrentViewPort() const
609ddde725dSArmin Le Grand         {
610ddde725dSArmin Le Grand             if(getViewBox())
611ddde725dSArmin Le Grand             {
612ddde725dSArmin Le Grand                 return getViewBox();
613ddde725dSArmin Le Grand             }
614*2169cc62SArmin Le Grand             else // viewport should be given by x, y, width, and height
615ddde725dSArmin Le Grand             {
616*2169cc62SArmin Le Grand                 // Extract known viewport data
617*2169cc62SArmin Le Grand                 // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values
618*2169cc62SArmin Le Grand                 if (getParent())
619*2169cc62SArmin Le Grand                     {
620*2169cc62SArmin Le Grand                     // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2
621*2169cc62SArmin Le Grand                     // value 0.0 here is only to initialize variable
622*2169cc62SArmin Le Grand                     bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
623*2169cc62SArmin Le Grand                     double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0);
624*2169cc62SArmin Le Grand                     bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
625*2169cc62SArmin Le Grand                     double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0);
626*2169cc62SArmin Le Grand 
627*2169cc62SArmin Le Grand                     // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2
628*2169cc62SArmin Le Grand                     bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet());
629*2169cc62SArmin Le Grand                     double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0);
630*2169cc62SArmin Le Grand 
631*2169cc62SArmin Le Grand                     bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet());
632*2169cc62SArmin Le Grand                     double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0);
633*2169cc62SArmin Le Grand 
634*2169cc62SArmin Le Grand                     if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute)
635*2169cc62SArmin Le Grand                     {
636*2169cc62SArmin Le Grand                         return &basegfx::B2DRange(fX, fY, fX+fW, fY+fH);
637*2169cc62SArmin Le Grand                     }
638*2169cc62SArmin Le Grand                     else // try to resolve relative values
639*2169cc62SArmin Le Grand                     {
640*2169cc62SArmin Le Grand                         if (!bXIsAbsolute || !bWidthIsAbsolute)
641*2169cc62SArmin Le Grand                         {
642*2169cc62SArmin Le Grand                             // get width of enclosing svg and resolve percentage in x and width
643*2169cc62SArmin Le Grand                             double fWReference(0.0);
644*2169cc62SArmin Le Grand                             bool bHasFoundWidth(false);
645*2169cc62SArmin Le Grand                             seekReferenceWidth(fWReference, bHasFoundWidth);
646*2169cc62SArmin Le Grand                             // referenced values are already in 'user unit'
647*2169cc62SArmin Le Grand                             if (!bXIsAbsolute && bHasFoundWidth)
648*2169cc62SArmin Le Grand                             {
649*2169cc62SArmin Le Grand                                 fX = getX().getNumber() * 0.01 * fWReference;
650*2169cc62SArmin Le Grand                                 bXIsAbsolute = true;
651*2169cc62SArmin Le Grand                             }
652*2169cc62SArmin Le Grand                             if (!bWidthIsAbsolute && bHasFoundWidth)
653*2169cc62SArmin Le Grand                             {
654*2169cc62SArmin Le Grand                                 fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference;
655*2169cc62SArmin Le Grand                                 bWidthIsAbsolute = true;
656*2169cc62SArmin Le Grand                             }
657*2169cc62SArmin Le Grand                         }
658*2169cc62SArmin Le Grand                         if (!bYIsAbsolute || !bHeightIsAbsolute)
659*2169cc62SArmin Le Grand                         {
660*2169cc62SArmin Le Grand                             // get height of enclosing svg and resolve percentage in y and height
661*2169cc62SArmin Le Grand                             double fHReference(0.0);
662*2169cc62SArmin Le Grand                             bool bHasFoundHeight(false);
663*2169cc62SArmin Le Grand                             seekReferenceHeight(fHReference, bHasFoundHeight);
664*2169cc62SArmin Le Grand                             // referenced values are already in 'user unit'
665*2169cc62SArmin Le Grand                             if (!bYIsAbsolute && bHasFoundHeight)
666*2169cc62SArmin Le Grand                             {
667*2169cc62SArmin Le Grand                                 fY = getY().getNumber() * 0.01 * fHReference;
668*2169cc62SArmin Le Grand                                 bYIsAbsolute = true;
669*2169cc62SArmin Le Grand                             }
670*2169cc62SArmin Le Grand                             if (!bHeightIsAbsolute && bHasFoundHeight)
671*2169cc62SArmin Le Grand                             {
672*2169cc62SArmin Le Grand                                 fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference;
673*2169cc62SArmin Le Grand                                 bHeightIsAbsolute = true;
674*2169cc62SArmin Le Grand                             }
675*2169cc62SArmin Le Grand                         }
676*2169cc62SArmin Le Grand 
677*2169cc62SArmin Le Grand                         if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute)
678*2169cc62SArmin Le Grand                         {
679*2169cc62SArmin Le Grand                             return &basegfx::B2DRange(fX, fY, fX+fW, fY+fH);
680*2169cc62SArmin Le Grand                         }
681*2169cc62SArmin Le Grand                         else // relative values could not be resolved, there exists no fallback
682*2169cc62SArmin Le Grand                         {
683*2169cc62SArmin Le Grand                             return SvgNode::getCurrentViewPort();
684*2169cc62SArmin Le Grand                         }
685*2169cc62SArmin Le Grand                     }
686*2169cc62SArmin Le Grand                 }
687*2169cc62SArmin Le Grand                 else //outermost svg
688*2169cc62SArmin Le Grand                 {
689*2169cc62SArmin Le Grand                     // If width or height is not provided, the default would be 100%, see SVG 1.1 section 5.1.2
690*2169cc62SArmin Le Grand                     // But here it cannot be resolved and no fallback exists.
691*2169cc62SArmin Le Grand                     // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element.
692*2169cc62SArmin Le Grand                     bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
693*2169cc62SArmin Le Grand                     double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0);
694*2169cc62SArmin Le Grand                     bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
695*2169cc62SArmin Le Grand                     double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0);
696*2169cc62SArmin Le Grand                     if (bWidthIsAbsolute && bHeightIsAbsolute)
697*2169cc62SArmin Le Grand                     {
698*2169cc62SArmin Le Grand                         return &basegfx::B2DRange(0.0, 0.0, fW, fH);
699*2169cc62SArmin Le Grand                     }
700*2169cc62SArmin Le Grand                     else // no fallback exists
701*2169cc62SArmin Le Grand                     {
702*2169cc62SArmin Le Grand                             return SvgNode::getCurrentViewPort();
703*2169cc62SArmin Le Grand                     }
704*2169cc62SArmin Le Grand                 }
705*2169cc62SArmin Le Grand // ToDo: Is it possible to decompose and use the bounding box of the childs, if even the
706*2169cc62SArmin Le Grand //       outermost svg has no information to resolve percentage? Is it worth, how expensive is it?
707*2169cc62SArmin Le Grand 
708ddde725dSArmin Le Grand             }
709ddde725dSArmin Le Grand         }
710ddde725dSArmin Le Grand 
711ddde725dSArmin Le Grand     } // end of namespace svgreader
712ddde725dSArmin Le Grand } // end of namespace svgio
713ddde725dSArmin Le Grand 
714ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
715ddde725dSArmin Le Grand // eof
716