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     {
SvgSvgNode(SvgDocument & rDocument,SvgNode * pParent)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(),
52*b3ba8dd4SArmin Le Grand             maVersion(),
53*b3ba8dd4SArmin Le Grand             mbStyleAttributesInitialized(false) // #125258#
54ddde725dSArmin Le Grand         {
55*b3ba8dd4SArmin Le Grand         }
56*b3ba8dd4SArmin Le Grand 
57*b3ba8dd4SArmin Le Grand         // #125258#
initializeStyleAttributes()58*b3ba8dd4SArmin Le Grand         void SvgSvgNode::initializeStyleAttributes()
59*b3ba8dd4SArmin Le Grand         {
60*b3ba8dd4SArmin Le Grand             if(!mbStyleAttributesInitialized)
61ddde725dSArmin Le Grand             {
62*b3ba8dd4SArmin Le Grand                 // #125258# determine if initial values need to be initialized with hard values
63*b3ba8dd4SArmin Le Grand                 // for the case that this is the outmost SVG statement and it has no parent
64*b3ba8dd4SArmin Le Grand                 // stale (CssStyle for svg may be defined)
65*b3ba8dd4SArmin Le Grand                 bool bSetInitialValues(true);
66*b3ba8dd4SArmin Le Grand 
67*b3ba8dd4SArmin Le Grand                 if(getParent())
68*b3ba8dd4SArmin Le Grand                 {
69*b3ba8dd4SArmin Le Grand                     // #125258# no initial values when it's a SVG element embedded in SVG
70*b3ba8dd4SArmin Le Grand                     bSetInitialValues = false;
71*b3ba8dd4SArmin Le Grand                 }
72*b3ba8dd4SArmin Le Grand 
73*b3ba8dd4SArmin Le Grand                 if(bSetInitialValues)
74*b3ba8dd4SArmin Le Grand                 {
75*b3ba8dd4SArmin Le Grand                     const SvgStyleAttributes* pStyles = getSvgStyleAttributes();
76*b3ba8dd4SArmin Le Grand 
77*b3ba8dd4SArmin Le Grand                     if(pStyles && pStyles->getParentStyle())
78*b3ba8dd4SArmin Le Grand                     {
79*b3ba8dd4SArmin Le Grand                         // #125258# no initial values when SVG has a parent style (probably CssStyle)
80*b3ba8dd4SArmin Le Grand                         bSetInitialValues = false;
81*b3ba8dd4SArmin Le Grand                     }
82*b3ba8dd4SArmin Le Grand                 }
83*b3ba8dd4SArmin Le Grand 
84*b3ba8dd4SArmin Le Grand                 if(bSetInitialValues)
85*b3ba8dd4SArmin Le Grand                 {
86*b3ba8dd4SArmin Le Grand                     // #125258# only set if not yet initialized (SvgSvgNode::parseAttribute is already done,
87*b3ba8dd4SArmin Le Grand                     // just setting may revert an already set valid value)
88*b3ba8dd4SArmin Le Grand                     if(!maSvgStyleAttributes.isFillSet())
89*b3ba8dd4SArmin Le Grand                     {
90*b3ba8dd4SArmin Le Grand                         // #125258# initial fill is black (see SVG1.1 spec)
91*b3ba8dd4SArmin Le Grand                         maSvgStyleAttributes.setFill(SvgPaint(basegfx::BColor(0.0, 0.0, 0.0), true, true));
92*b3ba8dd4SArmin Le Grand                     }
93*b3ba8dd4SArmin Le Grand                 }
94*b3ba8dd4SArmin Le Grand 
95*b3ba8dd4SArmin Le Grand                 mbStyleAttributesInitialized = true;
96ddde725dSArmin Le Grand             }
97ddde725dSArmin Le Grand         }
98ddde725dSArmin Le Grand 
~SvgSvgNode()99ddde725dSArmin Le Grand         SvgSvgNode::~SvgSvgNode()
100ddde725dSArmin Le Grand         {
101ddde725dSArmin Le Grand             if(mpViewBox) delete mpViewBox;
102ddde725dSArmin Le Grand         }
103ddde725dSArmin Le Grand 
getSvgStyleAttributes() const104ddde725dSArmin Le Grand         const SvgStyleAttributes* SvgSvgNode::getSvgStyleAttributes() const
105ddde725dSArmin Le Grand         {
106*b3ba8dd4SArmin Le Grand             // #125258# svg node can vahe CssStyles, too, so check for it here
107*b3ba8dd4SArmin Le Grand             static rtl::OUString aClassStr(rtl::OUString::createFromAscii("svg"));
108*b3ba8dd4SArmin Le Grand 
109*b3ba8dd4SArmin Le Grand             return checkForCssStyle(aClassStr, maSvgStyleAttributes);
110ddde725dSArmin Le Grand         }
111ddde725dSArmin Le Grand 
parseAttribute(const rtl::OUString & rTokenName,SVGToken aSVGToken,const rtl::OUString & aContent)112ddde725dSArmin Le Grand         void SvgSvgNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
113ddde725dSArmin Le Grand         {
114ddde725dSArmin Le Grand             // call parent
115ddde725dSArmin Le Grand             SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
116ddde725dSArmin Le Grand 
117ddde725dSArmin Le Grand             // read style attributes
118ddde725dSArmin Le Grand             maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
119ddde725dSArmin Le Grand 
120ddde725dSArmin Le Grand             // parse own
121ddde725dSArmin Le Grand             switch(aSVGToken)
122ddde725dSArmin Le Grand             {
123ddde725dSArmin Le Grand                 case SVGTokenStyle:
124ddde725dSArmin Le Grand                 {
125ddde725dSArmin Le Grand                     maSvgStyleAttributes.readStyle(aContent);
126ddde725dSArmin Le Grand                     break;
127ddde725dSArmin Le Grand                 }
128ddde725dSArmin Le Grand                 case SVGTokenViewBox:
129ddde725dSArmin Le Grand                 {
130ddde725dSArmin Le Grand                     const basegfx::B2DRange aRange(readViewBox(aContent, *this));
131ddde725dSArmin Le Grand 
132ddde725dSArmin Le Grand                     if(!aRange.isEmpty())
133ddde725dSArmin Le Grand                     {
134ddde725dSArmin Le Grand                         setViewBox(&aRange);
135ddde725dSArmin Le Grand                     }
136ddde725dSArmin Le Grand                     break;
137ddde725dSArmin Le Grand                 }
138ddde725dSArmin Le Grand                 case SVGTokenPreserveAspectRatio:
139ddde725dSArmin Le Grand                 {
140ddde725dSArmin Le Grand                     setSvgAspectRatio(readSvgAspectRatio(aContent));
141ddde725dSArmin Le Grand                     break;
142ddde725dSArmin Le Grand                 }
143ddde725dSArmin Le Grand                 case SVGTokenX:
144ddde725dSArmin Le Grand                 {
145ddde725dSArmin Le Grand                     SvgNumber aNum;
146ddde725dSArmin Le Grand 
147ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
148ddde725dSArmin Le Grand                     {
149ddde725dSArmin Le Grand                         setX(aNum);
150ddde725dSArmin Le Grand                     }
151ddde725dSArmin Le Grand                     break;
152ddde725dSArmin Le Grand                 }
153ddde725dSArmin Le Grand                 case SVGTokenY:
154ddde725dSArmin Le Grand                 {
155ddde725dSArmin Le Grand                     SvgNumber aNum;
156ddde725dSArmin Le Grand 
157ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
158ddde725dSArmin Le Grand                     {
159ddde725dSArmin Le Grand                         setY(aNum);
160ddde725dSArmin Le Grand                     }
161ddde725dSArmin Le Grand                     break;
162ddde725dSArmin Le Grand                 }
163ddde725dSArmin Le Grand                 case SVGTokenWidth:
164ddde725dSArmin Le Grand                 {
165ddde725dSArmin Le Grand                     SvgNumber aNum;
166ddde725dSArmin Le Grand 
167ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
168ddde725dSArmin Le Grand                     {
169ddde725dSArmin Le Grand                         if(aNum.isPositive())
170ddde725dSArmin Le Grand                         {
171ddde725dSArmin Le Grand                             setWidth(aNum);
172ddde725dSArmin Le Grand                         }
173ddde725dSArmin Le Grand                     }
174ddde725dSArmin Le Grand                     break;
175ddde725dSArmin Le Grand                 }
176ddde725dSArmin Le Grand                 case SVGTokenHeight:
177ddde725dSArmin Le Grand                 {
178ddde725dSArmin Le Grand                     SvgNumber aNum;
179ddde725dSArmin Le Grand 
180ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
181ddde725dSArmin Le Grand                     {
182ddde725dSArmin Le Grand                         if(aNum.isPositive())
183ddde725dSArmin Le Grand                         {
184ddde725dSArmin Le Grand                             setHeight(aNum);
185ddde725dSArmin Le Grand                         }
186ddde725dSArmin Le Grand                     }
187ddde725dSArmin Le Grand                     break;
188ddde725dSArmin Le Grand                 }
189ddde725dSArmin Le Grand                 case SVGTokenVersion:
190ddde725dSArmin Le Grand                 {
191ddde725dSArmin Le Grand                     SvgNumber aNum;
192ddde725dSArmin Le Grand 
193ddde725dSArmin Le Grand                     if(readSingleNumber(aContent, aNum))
194ddde725dSArmin Le Grand                     {
195ddde725dSArmin Le Grand                         setVersion(aNum);
196ddde725dSArmin Le Grand                     }
197ddde725dSArmin Le Grand                     break;
198e2bf1e9dSArmin Le Grand                 }
199e2bf1e9dSArmin Le Grand                 default:
200e2bf1e9dSArmin Le Grand                 {
201e2bf1e9dSArmin Le Grand                     break;
202ddde725dSArmin Le Grand                 }
203ddde725dSArmin Le Grand             }
204ddde725dSArmin Le Grand         }
205ddde725dSArmin Le Grand 
seekReferenceWidth(double & fWidth,bool & bHasFound) const2062169cc62SArmin Le Grand         void SvgSvgNode::seekReferenceWidth(double& fWidth, bool& bHasFound) const
2072169cc62SArmin Le Grand         {
2082169cc62SArmin Le Grand             if (!getParent() || bHasFound)
2092169cc62SArmin Le Grand             {
2102169cc62SArmin Le Grand                 return;
2112169cc62SArmin Le Grand             }
2122169cc62SArmin Le Grand             const SvgSvgNode* pParentSvgSvgNode = 0;
2132169cc62SArmin Le Grand             // enclosing svg might have relative width, need to cumulate them till they are
2142169cc62SArmin Le Grand             // resolved somewhere up in the node tree
2152169cc62SArmin Le Grand             double fPercentage(1.0);
2162169cc62SArmin Le Grand             for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent())
2172169cc62SArmin Le Grand             {
2182169cc62SArmin Le Grand                 // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition
2192169cc62SArmin Le Grand                 pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent);
2202169cc62SArmin Le Grand                 if (pParentSvgSvgNode)
2212169cc62SArmin Le Grand                 {
2222169cc62SArmin Le Grand                     if (pParentSvgSvgNode->getViewBox())
2232169cc62SArmin Le Grand                     {
2242169cc62SArmin Le Grand                         // viewbox values are already in 'user unit'.
2252169cc62SArmin Le Grand                         fWidth = pParentSvgSvgNode->getViewBox()->getWidth() * fPercentage;
2262169cc62SArmin Le Grand                         bHasFound = true;
2272169cc62SArmin Le Grand                     }
2282169cc62SArmin Le Grand                     else
2292169cc62SArmin Le Grand                     {
2302169cc62SArmin Le Grand                         // take absolute value or cummulate percentage
2312169cc62SArmin Le Grand                         if (pParentSvgSvgNode->getWidth().isSet())
2322169cc62SArmin Le Grand                         {
2332169cc62SArmin Le Grand                             if (Unit_percent == pParentSvgSvgNode->getWidth().getUnit())
2342169cc62SArmin Le Grand                             {
2352169cc62SArmin Le Grand                                 fPercentage *= pParentSvgSvgNode->getWidth().getNumber() * 0.01;
2362169cc62SArmin Le Grand                             }
2372169cc62SArmin Le Grand                             else
2382169cc62SArmin Le Grand                             {
2392169cc62SArmin Le Grand                                 fWidth = pParentSvgSvgNode->getWidth().solveNonPercentage(*pParentSvgSvgNode) * fPercentage;
2402169cc62SArmin Le Grand                                 bHasFound = true;
2412169cc62SArmin Le Grand                             }
2422169cc62SArmin Le Grand                         } // not set => width=100% => factor 1, no need for else
2432169cc62SArmin Le Grand                     }
2442169cc62SArmin Le Grand                 }
2452169cc62SArmin Le Grand             }
2462169cc62SArmin Le Grand         }
2472169cc62SArmin Le Grand 
seekReferenceHeight(double & fHeight,bool & bHasFound) const2482169cc62SArmin Le Grand         void SvgSvgNode::seekReferenceHeight(double& fHeight, bool& bHasFound) const
2492169cc62SArmin Le Grand         {
2502169cc62SArmin Le Grand             if (!getParent() || bHasFound)
2512169cc62SArmin Le Grand             {
2522169cc62SArmin Le Grand                 return;
2532169cc62SArmin Le Grand             }
2542169cc62SArmin Le Grand             const SvgSvgNode* pParentSvgSvgNode = 0;
2552169cc62SArmin Le Grand             // enclosing svg might have relative width and height, need to cumulate them till they are
2562169cc62SArmin Le Grand             // resolved somewhere up in the node tree
2572169cc62SArmin Le Grand             double fPercentage(1.0);
2582169cc62SArmin Le Grand             for(const SvgNode* pParent = getParent(); pParent && !bHasFound; pParent = pParent->getParent())
2592169cc62SArmin Le Grand             {
2602169cc62SArmin Le Grand                 // dynamic_cast results Null-pointer for not SvgSvgNode and so skips them in if condition
2612169cc62SArmin Le Grand                 pParentSvgSvgNode = dynamic_cast< const SvgSvgNode* >(pParent);
2622169cc62SArmin Le Grand                 if (pParentSvgSvgNode)
2632169cc62SArmin Le Grand                 {
2642169cc62SArmin Le Grand                     if (pParentSvgSvgNode->getViewBox())
2652169cc62SArmin Le Grand                     {
2662169cc62SArmin Le Grand                         // viewbox values are already in 'user unit'.
2672169cc62SArmin Le Grand                         fHeight = pParentSvgSvgNode->getViewBox()->getHeight() * fPercentage;
2682169cc62SArmin Le Grand                         bHasFound = true;
2692169cc62SArmin Le Grand                     }
2702169cc62SArmin Le Grand                     else
2712169cc62SArmin Le Grand                     {
2722169cc62SArmin Le Grand                         // take absolute value or cummulate percentage
2732169cc62SArmin Le Grand                         if (pParentSvgSvgNode->getHeight().isSet())
2742169cc62SArmin Le Grand                         {
2752169cc62SArmin Le Grand                             if (Unit_percent == pParentSvgSvgNode->getHeight().getUnit())
2762169cc62SArmin Le Grand                             {
2772169cc62SArmin Le Grand                                 fPercentage *= pParentSvgSvgNode->getHeight().getNumber() * 0.01;
2782169cc62SArmin Le Grand                             }
2792169cc62SArmin Le Grand                             else
2802169cc62SArmin Le Grand                             {
2812169cc62SArmin Le Grand                                 fHeight = pParentSvgSvgNode->getHeight().solveNonPercentage(*pParentSvgSvgNode) * fPercentage;
2822169cc62SArmin Le Grand                                 bHasFound = true;
2832169cc62SArmin Le Grand                             }
2842169cc62SArmin Le Grand                         } // not set => height=100% => factor 1, no need for else
2852169cc62SArmin Le Grand                     }
2862169cc62SArmin Le Grand                 }
2872169cc62SArmin Le Grand             }
2882169cc62SArmin Le Grand         }
2892169cc62SArmin Le Grand 
2902169cc62SArmin Le Grand // ToDo: Consider attribute overflow in method decomposeSvgNode
decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence & rTarget,bool bReferenced) const291ddde725dSArmin Le Grand         void SvgSvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const
292ddde725dSArmin Le Grand         {
293ddde725dSArmin Le Grand             drawinglayer::primitive2d::Primitive2DSequence aSequence;
294ddde725dSArmin Le Grand 
295*b3ba8dd4SArmin Le Grand             // #125258# check now if we need to init some style settings locally. Do not do this
296*b3ba8dd4SArmin Le Grand             // in the constructor, there is not yet informatikon e.g. about existing CssStyles.
297*b3ba8dd4SArmin Le Grand             // Here all nodes are read and interpreted
298*b3ba8dd4SArmin Le Grand             const_cast< SvgSvgNode* >(this)->initializeStyleAttributes();
299*b3ba8dd4SArmin Le Grand 
300ddde725dSArmin Le Grand             // decompose childs
301ddde725dSArmin Le Grand             SvgNode::decomposeSvgNode(aSequence, bReferenced);
302ddde725dSArmin Le Grand 
303ddde725dSArmin Le Grand             if(aSequence.hasElements())
304ddde725dSArmin Le Grand             {
305ddde725dSArmin Le Grand                 if(getParent())
306ddde725dSArmin Le Grand                 {
3072169cc62SArmin Le Grand                     // #122594# if width/height is not given, it's 100% (see 5.1.2 The 'svg' element in SVG1.1 spec).
308bca0eb5dSArmin Le Grand                     // If it is relative, the question is to what. The previous implementatin assumed relative to the
309bca0eb5dSArmin Le Grand                     // local ViewBox which is implied by (4.2 Basic data types):
310bca0eb5dSArmin Le Grand                     //
311bca0eb5dSArmin Le Grand                     // "Note that the non-property <length> definition also allows a percentage unit identifier.
312bca0eb5dSArmin Le Grand                     // The meaning of a percentage length value depends on the attribute for which the percentage
313bca0eb5dSArmin Le Grand                     // length value has been specified. Two common cases are: (a) when a percentage length value
314bca0eb5dSArmin Le Grand                     // represents a percentage of the viewport width or height (refer to the section that discusses
315bca0eb5dSArmin Le Grand                     // units in general), and (b) when a percentage length value represents a percentage of the
316bca0eb5dSArmin Le Grand                     // bounding box width or height on a given object (refer to the section that describes object
317bca0eb5dSArmin Le Grand                     // bounding box units)."
3182169cc62SArmin Le Grand 
3192169cc62SArmin Le Grand                     // Comparisons with commom browsers show, that it's mostly interpreted relative to the viewport
3202169cc62SArmin Le Grand                     // of the parent, and so does the new implementation.
3212169cc62SArmin Le Grand 
3222169cc62SArmin Le Grand                     // Extract known viewport data
3232169cc62SArmin Le Grand                     // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values
3242169cc62SArmin Le Grand 
3252169cc62SArmin Le Grand                     // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2
3262169cc62SArmin Le Grand                     // value 0.0 here is only to initialize variable
3272169cc62SArmin Le Grand                     bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
3282169cc62SArmin Le Grand                     double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0);
3292169cc62SArmin Le Grand 
3302169cc62SArmin Le Grand                     bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
3312169cc62SArmin Le Grand                     double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0);
3322169cc62SArmin Le Grand 
3332169cc62SArmin Le Grand                     // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2
3342169cc62SArmin Le Grand                     bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet());
3352169cc62SArmin Le Grand                     double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0);
3362169cc62SArmin Le Grand 
3372169cc62SArmin Le Grand                     bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet());
3382169cc62SArmin Le Grand                     double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0);
3392169cc62SArmin Le Grand 
3402169cc62SArmin Le Grand                     if ( !bXIsAbsolute || !bWidthIsAbsolute)
341bca0eb5dSArmin Le Grand                     {
3422169cc62SArmin Le Grand                         // get width of enclosing svg and resolve percentage in x and width;
3432169cc62SArmin Le Grand                         double fWReference(0.0);
3442169cc62SArmin Le Grand                         bool bHasFoundWidth(false);
3452169cc62SArmin Le Grand                         seekReferenceWidth(fWReference, bHasFoundWidth);
3462169cc62SArmin Le Grand                         if (!bHasFoundWidth)
347bca0eb5dSArmin Le Grand                         {
3482169cc62SArmin Le Grand                             // Even outermost svg has not all information to resolve relative values,
3492169cc62SArmin Le Grand                             // I use content itself as fallback to set missing values for viewport
3502169cc62SArmin Le Grand                             // Any better idea for such ill structures svg documents?
3512169cc62SArmin Le Grand                             const basegfx::B2DRange aChildRange(
3522169cc62SArmin Le Grand                                         drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
3532169cc62SArmin Le Grand                                             aSequence,
3542169cc62SArmin Le Grand                                         drawinglayer::geometry::ViewInformation2D()));
3552169cc62SArmin Le Grand                             fWReference = aChildRange.getWidth();
356bca0eb5dSArmin Le Grand                         }
3572169cc62SArmin Le Grand                         // referenced values are already in 'user unit'
3582169cc62SArmin Le Grand                         if (!bXIsAbsolute)
359bca0eb5dSArmin Le Grand                         {
3602169cc62SArmin Le Grand                             fX = getX().getNumber() * 0.01 * fWReference;
3612169cc62SArmin Le Grand                         }
3622169cc62SArmin Le Grand                         if (!bWidthIsAbsolute)
3632169cc62SArmin Le Grand                         {
3642169cc62SArmin Le Grand                             fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference;
365bca0eb5dSArmin Le Grand                         }
366bca0eb5dSArmin Le Grand                     }
367bca0eb5dSArmin Le Grand 
3682169cc62SArmin Le Grand                     if ( !bYIsAbsolute || !bHeightIsAbsolute)
369bca0eb5dSArmin Le Grand                     {
3702169cc62SArmin Le Grand                         // get height of enclosing svg and resolve percentage in y and height
3712169cc62SArmin Le Grand                         double fHReference(0.0);
3722169cc62SArmin Le Grand                         bool bHasFoundHeight(false);
3732169cc62SArmin Le Grand                         seekReferenceHeight(fHReference, bHasFoundHeight);
3742169cc62SArmin Le Grand                         if (!bHasFoundHeight)
3752169cc62SArmin Le Grand                         {
3762169cc62SArmin Le Grand                             // Even outermost svg has not all information to resolve relative values,
3772169cc62SArmin Le Grand                             // I use content itself as fallback to set missing values for viewport
3782169cc62SArmin Le Grand                             // Any better idea for such ill structures svg documents?
3792169cc62SArmin Le Grand                             const basegfx::B2DRange aChildRange(
3802169cc62SArmin Le Grand                                         drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
3812169cc62SArmin Le Grand                                             aSequence,
3822169cc62SArmin Le Grand                                         drawinglayer::geometry::ViewInformation2D()));
3832169cc62SArmin Le Grand                             fHReference = aChildRange.getHeight();
3842169cc62SArmin Le Grand                         }
385bca0eb5dSArmin Le Grand 
3862169cc62SArmin Le Grand                         // referenced values are already in 'user unit'
3872169cc62SArmin Le Grand                         if (!bYIsAbsolute)
388bca0eb5dSArmin Le Grand                         {
3892169cc62SArmin Le Grand                             fY = getY().getNumber() * 0.01 * fHReference;
3902169cc62SArmin Le Grand                         }
3912169cc62SArmin Le Grand                         if (!bHeightIsAbsolute)
3922169cc62SArmin Le Grand                         {
3932169cc62SArmin Le Grand                             fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference;
394bca0eb5dSArmin Le Grand                         }
395bca0eb5dSArmin Le Grand                     }
396bca0eb5dSArmin Le Grand 
397ddde725dSArmin Le Grand                     if(getViewBox())
398ddde725dSArmin Le Grand                     {
3992169cc62SArmin Le Grand                         // SVG 1.1 defines in section 7.7 that a negative value for width or height
4002169cc62SArmin Le Grand                         // in viewBox is an error and that 0.0 disables rendering
4012169cc62SArmin Le Grand                         if(basegfx::fTools::more(getViewBox()->getWidth(),0.0) && basegfx::fTools::more(getViewBox()->getHeight(),0.0))
402ddde725dSArmin Le Grand                         {
4032169cc62SArmin Le Grand                             // create target range homing x,y, width and height as calculated above
404ddde725dSArmin Le Grand                             const basegfx::B2DRange aTarget(fX, fY, fX + fW, fY + fH);
405ddde725dSArmin Le Grand 
406ddde725dSArmin Le Grand                             if(aTarget.equal(*getViewBox()))
407ddde725dSArmin Le Grand                             {
408ddde725dSArmin Le Grand                                 // no mapping needed, append
409ddde725dSArmin Le Grand                                 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence);
410ddde725dSArmin Le Grand                             }
411ddde725dSArmin Le Grand                             else
412ddde725dSArmin Le Grand                             {
413ddde725dSArmin Le Grand                                 // create mapping
4142169cc62SArmin Le Grand                                 // #i122610 SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified,
4152169cc62SArmin Le Grand                                 // then the effect is as if a value of 'xMidYMid meet' were specified.
4162169cc62SArmin Le Grand                                 SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true);
4172169cc62SArmin Le Grand                                 const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault;
4182169cc62SArmin Le Grand 
4192169cc62SArmin Le Grand                                 // let mapping be created from SvgAspectRatio
4202169cc62SArmin Le Grand                                 const basegfx::B2DHomMatrix aEmbeddingTransform(
4212169cc62SArmin Le Grand                                     rRatio.createMapping(aTarget, *getViewBox()));
4222169cc62SArmin Le Grand 
4232169cc62SArmin Le Grand                                 // prepare embedding in transformation
4242169cc62SArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xRef(
4252169cc62SArmin Le Grand                                     new drawinglayer::primitive2d::TransformPrimitive2D(
4262169cc62SArmin Le Grand                                         aEmbeddingTransform,
4272169cc62SArmin Le Grand                                         aSequence));
428ddde725dSArmin Le Grand 
4292169cc62SArmin Le Grand                                 if(rRatio.isMeetOrSlice())
430ddde725dSArmin Le Grand                                 {
4312169cc62SArmin Le Grand                                     // embed in transformation
4322169cc62SArmin Le Grand                                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef);
433ddde725dSArmin Le Grand                                 }
434ddde725dSArmin Le Grand                                 else
435ddde725dSArmin Le Grand                                 {
4362169cc62SArmin Le Grand                                     // need to embed in MaskPrimitive2D, too
4372169cc62SArmin Le Grand                                     const drawinglayer::primitive2d::Primitive2DReference xMask(
4382169cc62SArmin Le Grand                                         new drawinglayer::primitive2d::MaskPrimitive2D(
4392169cc62SArmin Le Grand                                             basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)),
4402169cc62SArmin Le Grand                                             drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1)));
441ddde725dSArmin Le Grand 
4422169cc62SArmin Le Grand                                     drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask);
443ddde725dSArmin Le Grand                                 }
444ddde725dSArmin Le Grand                             }
445ddde725dSArmin Le Grand                         }
446ddde725dSArmin Le Grand                     }
4472169cc62SArmin Le Grand                     else // no viewBox attribute
448ddde725dSArmin Le Grand                     {
449ddde725dSArmin Le Grand                         // Svg defines that a negative value is an error and that 0.0 disables rendering
450ddde725dSArmin Le Grand                         if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0))
451ddde725dSArmin Le Grand                         {
452ddde725dSArmin Le Grand                             if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY))
453ddde725dSArmin Le Grand                             {
454ddde725dSArmin Le Grand                                 // embed in transform
455ddde725dSArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xRef(
456ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::TransformPrimitive2D(
457ddde725dSArmin Le Grand                                         basegfx::tools::createTranslateB2DHomMatrix(fX, fY),
458ddde725dSArmin Le Grand                                         aSequence));
459ddde725dSArmin Le Grand 
460ddde725dSArmin Le Grand                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
461ddde725dSArmin Le Grand                             }
462ddde725dSArmin Le Grand 
463ddde725dSArmin Le Grand                             // embed in MaskPrimitive2D to clip
464ddde725dSArmin Le Grand                             const drawinglayer::primitive2d::Primitive2DReference xMask(
465ddde725dSArmin Le Grand                                 new drawinglayer::primitive2d::MaskPrimitive2D(
466ddde725dSArmin Le Grand                                     basegfx::B2DPolyPolygon(
467ddde725dSArmin Le Grand                                         basegfx::tools::createPolygonFromRect(
468ddde725dSArmin Le Grand                                             basegfx::B2DRange(fX, fY, fX + fW, fY + fH))),
469ddde725dSArmin Le Grand                                     aSequence));
470ddde725dSArmin Le Grand 
471ddde725dSArmin Le Grand                             // append
472ddde725dSArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask);
473ddde725dSArmin Le Grand                         }
474ddde725dSArmin Le Grand                     }
475ddde725dSArmin Le Grand                 }
4762169cc62SArmin Le Grand                 else // Outermost SVG element
477ddde725dSArmin Le Grand                 {
4782169cc62SArmin Le Grand                     double fW = 0.0; // effective value depends on viewBox
4792169cc62SArmin Le Grand                     double fH = 0.0;
480ddde725dSArmin Le Grand 
481ddde725dSArmin Le Grand                     // Svg defines that a negative value is an error and that 0.0 disables rendering
4822169cc62SArmin Le Grand                     // isPositive() not usable because it allows 0.0 in contrast to mathematical definition of 'positive'
4832169cc62SArmin Le Grand                     const bool bWidthInvalid(getWidth().isSet() && basegfx::fTools::lessOrEqual(getWidth().getNumber(), 0.0));
4842169cc62SArmin Le Grand                     const bool bHeightInvalid(getHeight().isSet() && basegfx::fTools::lessOrEqual(getHeight().getNumber(), 0.0));
4852169cc62SArmin Le Grand                     if(!bWidthInvalid && !bHeightInvalid)
486ddde725dSArmin Le Grand                     {
4872169cc62SArmin Le Grand                         basegfx::B2DRange aSvgCanvasRange; // effective value depends on viewBox
488ddde725dSArmin Le Grand                         if(getViewBox())
489ddde725dSArmin Le Grand                         {
4902169cc62SArmin Le Grand                             // SVG 1.1 defines in section 7.7 that a negative value for width or height
4912169cc62SArmin Le Grand                             // in viewBox is an error and that 0.0 disables rendering
4922169cc62SArmin Le Grand                             const double fViewBoxWidth = getViewBox()->getWidth();
4932169cc62SArmin Le Grand                             const double fViewBoxHeight = getViewBox()->getHeight();
4942169cc62SArmin Le Grand                             if(basegfx::fTools::more(fViewBoxWidth,0.0) && basegfx::fTools::more(fViewBoxHeight,0.0))
495ddde725dSArmin Le Grand                             {
4962169cc62SArmin Le Grand                                 // The intrinsic aspect ratio of the svg element is given by absolute values of both width and height
4972169cc62SArmin Le Grand                                 // or if one or both of them is relative by the width and height of the viewBox
4982169cc62SArmin Le Grand                                 // see SVG 1.1 section 7.12
4992169cc62SArmin Le Grand                                 const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
5002169cc62SArmin Le Grand                                 const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
5012169cc62SArmin Le Grand                                 if(bWidthIsAbsolute && bHeightIsAbsolute)
502ddde725dSArmin Le Grand                                 {
5032169cc62SArmin Le Grand                                     fW =getWidth().solveNonPercentage(*this);
5042169cc62SArmin Le Grand                                     fH =getHeight().solveNonPercentage(*this);
5052169cc62SArmin Le Grand                                 }
5062169cc62SArmin Le Grand                                 else if (bWidthIsAbsolute)
5072169cc62SArmin Le Grand                                 {
5082169cc62SArmin Le Grand                                     fW = getWidth().solveNonPercentage(*this);
5092169cc62SArmin Le Grand                                     fH = fW * fViewBoxWidth / fViewBoxHeight ;
5102169cc62SArmin Le Grand                                 }
5112169cc62SArmin Le Grand                                 else if (bHeightIsAbsolute)
5122169cc62SArmin Le Grand                                 {
5132169cc62SArmin Le Grand                                     fH = getHeight().solveNonPercentage(*this);
5142169cc62SArmin Le Grand                                     fW = fH * fViewBoxWidth / fViewBoxHeight ;
515ddde725dSArmin Le Grand                                 }
516ddde725dSArmin Le Grand                                 else
517ddde725dSArmin Le Grand                                 {
5182169cc62SArmin Le Grand                                     fW = fViewBoxWidth;
5192169cc62SArmin Le Grand                                     fH = fViewBoxHeight;
520ddde725dSArmin Le Grand                                 }
5212169cc62SArmin Le Grand                                 // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element.
5222169cc62SArmin Le Grand                                 aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH);
5232169cc62SArmin Le Grand 
5242169cc62SArmin Le Grand                                 // create mapping
5252169cc62SArmin Le Grand                                 // SVG 1.1 defines in section 5.1.2 that if the attribute perserveAspectRatio is not specified,
5262169cc62SArmin Le Grand                                 // then the effect is as if a value of 'xMidYMid meet' were specified.
5272169cc62SArmin Le Grand                                 SvgAspectRatio aRatioDefault(Align_xMidYMid,false,true);
5282169cc62SArmin Le Grand                                 const SvgAspectRatio& rRatio = getSvgAspectRatio().isSet()? getSvgAspectRatio() : aRatioDefault;
5292169cc62SArmin Le Grand 
5302169cc62SArmin Le Grand                                 basegfx::B2DHomMatrix aViewBoxMapping;
5312169cc62SArmin Le Grand                                 aViewBoxMapping = rRatio.createMapping(aSvgCanvasRange, *getViewBox());
5322169cc62SArmin Le Grand                                 // no need to check ratio here for slice, the outermost Svg will
5332169cc62SArmin Le Grand                                 // be clipped anyways (see below)
534ddde725dSArmin Le Grand 
535ddde725dSArmin Le Grand                                 // scale content to viewBox definitions
536ddde725dSArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xTransform(
537ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::TransformPrimitive2D(
538ddde725dSArmin Le Grand                                         aViewBoxMapping,
539ddde725dSArmin Le Grand                                         aSequence));
540ddde725dSArmin Le Grand 
541ddde725dSArmin Le Grand                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
542ddde725dSArmin Le Grand                             }
543ddde725dSArmin Le Grand                         }
5442169cc62SArmin Le Grand                         else // no viewbox
5452169cc62SArmin Le Grand                         {
5462169cc62SArmin Le Grand                            // There exists no parent to resolve relative width or height.
5472169cc62SArmin Le Grand                            // Use child size as fallback.
5482169cc62SArmin Le Grand                             const bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
5492169cc62SArmin Le Grand                             const bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
5502169cc62SArmin Le Grand                             if (bWidthIsAbsolute && bHeightIsAbsolute)
5512169cc62SArmin Le Grand                             {
5522169cc62SArmin Le Grand                                 fW =getWidth().solveNonPercentage(*this);
5532169cc62SArmin Le Grand                                 fH =getHeight().solveNonPercentage(*this);
5542169cc62SArmin Le Grand 
5552169cc62SArmin Le Grand                             }
5562169cc62SArmin Le Grand                             else
5572169cc62SArmin Le Grand                             {
5582169cc62SArmin Le Grand                                 const basegfx::B2DRange aChildRange(
5592169cc62SArmin Le Grand                                     drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
5602169cc62SArmin Le Grand                                         aSequence,
5612169cc62SArmin Le Grand                                      drawinglayer::geometry::ViewInformation2D()));
5622169cc62SArmin Le Grand                                 const double fChildWidth(aChildRange.getWidth());
5632169cc62SArmin Le Grand                                 const double fChildHeight(aChildRange.getHeight());
5642169cc62SArmin Le Grand                                 fW = bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : fChildWidth;
5652169cc62SArmin Le Grand                                 fH = bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : fChildHeight;
5662169cc62SArmin Le Grand                             }
5672169cc62SArmin Le Grand                             // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element.
5682169cc62SArmin Le Grand                             aSvgCanvasRange = basegfx::B2DRange(0.0, 0.0, fW, fH);
5692169cc62SArmin Le Grand                         }
570ddde725dSArmin Le Grand 
571ddde725dSArmin Le Grand                         // to be completely correct in Svg sense it is necessary to clip
572ddde725dSArmin Le Grand                         // the whole content to the given canvas. I choose here to do this
573ddde725dSArmin Le Grand                         // initially despite I found various examples of Svg files out there
574ddde725dSArmin Le Grand                         // which have no correct values for this clipping. It's correct
575ddde725dSArmin Le Grand                         // due to the Svg spec.
576ddde725dSArmin Le Grand                         bool bDoCorrectCanvasClipping(true);
577ddde725dSArmin Le Grand 
578ddde725dSArmin Le Grand                         if(bDoCorrectCanvasClipping)
579ddde725dSArmin Le Grand                         {
580ddde725dSArmin Le Grand                             // different from Svg we have the possibility with primitives to get
58141923119SArmin Le Grand                             // a correct bounding box for the geometry. Get it for evtl. taking action
582ddde725dSArmin Le Grand                             const basegfx::B2DRange aContentRange(
583ddde725dSArmin Le Grand                                 drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(
584ddde725dSArmin Le Grand                                     aSequence,
585ddde725dSArmin Le Grand                                     drawinglayer::geometry::ViewInformation2D()));
586ddde725dSArmin Le Grand 
58741923119SArmin Le Grand                             if(aSvgCanvasRange.isInside(aContentRange))
588ddde725dSArmin Le Grand                             {
58941923119SArmin Le Grand                                 // no clip needed, but an invisible HiddenGeometryPrimitive2D
59041923119SArmin Le Grand                                 // to allow getting the full Svg range using the primitive mechanisms.
59141923119SArmin Le Grand                                 // This is needed since e.g. an SdrObject using this as graphic will
59241923119SArmin Le Grand                                 // create a mapping transformation to exactly map the content to it's
59341923119SArmin Le Grand                                 // real life size
59441923119SArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xLine(
59541923119SArmin Le Grand                                     new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
59641923119SArmin Le Grand                                         basegfx::tools::createPolygonFromRect(
59741923119SArmin Le Grand                                             aSvgCanvasRange),
59841923119SArmin Le Grand                                         basegfx::BColor(0.0, 0.0, 0.0)));
59941923119SArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xHidden(
60041923119SArmin Le Grand                                     new drawinglayer::primitive2d::HiddenGeometryPrimitive2D(
60141923119SArmin Le Grand                                         drawinglayer::primitive2d::Primitive2DSequence(&xLine, 1)));
60241923119SArmin Le Grand 
60341923119SArmin Le Grand                                 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aSequence, xHidden);
60441923119SArmin Le Grand                             }
60541923119SArmin Le Grand                             else if(aSvgCanvasRange.overlaps(aContentRange))
60641923119SArmin Le Grand                             {
60741923119SArmin Le Grand                                 // Clip is necessary. This will make Svg images evtl. smaller
60841923119SArmin Le Grand                                 // than wanted from Svg (the free space which may be around it is
60941923119SArmin Le Grand                                 // conform to the Svg spec), but avoids an expensive and unneccessary
61041923119SArmin Le Grand                                 // clip. Keep the full Svg range here to get the correct mappings
61141923119SArmin Le Grand                                 // to objects using this. Optimizations can be done in the processors
612ddde725dSArmin Le Grand                                 const drawinglayer::primitive2d::Primitive2DReference xMask(
613ddde725dSArmin Le Grand                                     new drawinglayer::primitive2d::MaskPrimitive2D(
614ddde725dSArmin Le Grand                                         basegfx::B2DPolyPolygon(
615ddde725dSArmin Le Grand                                             basegfx::tools::createPolygonFromRect(
616ddde725dSArmin Le Grand                                                 aSvgCanvasRange)),
617ddde725dSArmin Le Grand                                         aSequence));
618ddde725dSArmin Le Grand 
619ddde725dSArmin Le Grand                                 aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1);
620ddde725dSArmin Le Grand                             }
62141923119SArmin Le Grand                             else
62241923119SArmin Le Grand                             {
62341923119SArmin Le Grand                                 // not inside, no overlap. Empty Svg
62441923119SArmin Le Grand                                 aSequence.realloc(0);
62541923119SArmin Le Grand                             }
626ddde725dSArmin Le Grand                         }
627ddde725dSArmin Le Grand 
62841923119SArmin Le Grand                         if(aSequence.hasElements())
629ddde725dSArmin Le Grand                         {
630ddde725dSArmin Le Grand                             // embed in transform primitive to scale to 1/100th mm
6312169cc62SArmin Le Grand                             // where 1 inch == 25.4 mm to get from Svg coordinates (px) to
6322169cc62SArmin Le Grand                             // drawinglayer coordinates
6332169cc62SArmin Le Grand                             const double fScaleTo100thmm(25.4 * 100.0 / F_SVG_PIXEL_PER_INCH);
634ddde725dSArmin Le Grand                             const basegfx::B2DHomMatrix aTransform(
635ddde725dSArmin Le Grand                                 basegfx::tools::createScaleB2DHomMatrix(
636ddde725dSArmin Le Grand                                     fScaleTo100thmm,
637ddde725dSArmin Le Grand                                     fScaleTo100thmm));
638ddde725dSArmin Le Grand 
639ddde725dSArmin Le Grand                             const drawinglayer::primitive2d::Primitive2DReference xTransform(
640ddde725dSArmin Le Grand                                 new drawinglayer::primitive2d::TransformPrimitive2D(
641ddde725dSArmin Le Grand                                     aTransform,
642ddde725dSArmin Le Grand                                     aSequence));
643ddde725dSArmin Le Grand 
644ddde725dSArmin Le Grand                             aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1);
645ddde725dSArmin Le Grand 
64641923119SArmin Le Grand                             // append to result
64741923119SArmin Le Grand                             drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence);
64841923119SArmin Le Grand                         }
649ddde725dSArmin Le Grand                     }
650ddde725dSArmin Le Grand                 }
651ddde725dSArmin Le Grand             }
652ddde725dSArmin Le Grand         }
653ddde725dSArmin Le Grand 
getCurrentViewPort() const654e92bb418SOliver-Rainer Wittmann         const basegfx::B2DRange SvgSvgNode::getCurrentViewPort() const
655ddde725dSArmin Le Grand         {
656ddde725dSArmin Le Grand             if(getViewBox())
657ddde725dSArmin Le Grand             {
658e92bb418SOliver-Rainer Wittmann                 return *(getViewBox());
659ddde725dSArmin Le Grand             }
6602169cc62SArmin Le Grand             else // viewport should be given by x, y, width, and height
661ddde725dSArmin Le Grand             {
6622169cc62SArmin Le Grand                 // Extract known viewport data
6632169cc62SArmin Le Grand                 // bXXXIsAbsolute tracks whether relative values could be resolved to absolute values
6642169cc62SArmin Le Grand                 if (getParent())
6652169cc62SArmin Le Grand                     {
6662169cc62SArmin Le Grand                     // If width or height is not provided, the default 100% is used, see SVG 1.1 section 5.1.2
6672169cc62SArmin Le Grand                     // value 0.0 here is only to initialize variable
6682169cc62SArmin Le Grand                     bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
6692169cc62SArmin Le Grand                     double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0);
6702169cc62SArmin Le Grand                     bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
6712169cc62SArmin Le Grand                     double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0);
6722169cc62SArmin Le Grand 
6732169cc62SArmin Le Grand                     // If x or y not provided, then default 0.0 is used, see SVG 1.1 Section 5.1.2
6742169cc62SArmin Le Grand                     bool bXIsAbsolute((getX().isSet() && Unit_percent != getX().getUnit()) || !getX().isSet());
6752169cc62SArmin Le Grand                     double fX( bXIsAbsolute && getX().isSet() ? getX().solveNonPercentage(*this) : 0.0);
6762169cc62SArmin Le Grand 
6772169cc62SArmin Le Grand                     bool bYIsAbsolute((getY().isSet() && Unit_percent != getY().getUnit()) || !getY().isSet());
6782169cc62SArmin Le Grand                     double fY( bYIsAbsolute && getY().isSet() ? getY().solveNonPercentage(*this) : 0.0);
6792169cc62SArmin Le Grand 
6802169cc62SArmin Le Grand                     if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute)
6812169cc62SArmin Le Grand                     {
682e92bb418SOliver-Rainer Wittmann                         return basegfx::B2DRange(fX, fY, fX+fW, fY+fH);
6832169cc62SArmin Le Grand                     }
6842169cc62SArmin Le Grand                     else // try to resolve relative values
6852169cc62SArmin Le Grand                     {
6862169cc62SArmin Le Grand                         if (!bXIsAbsolute || !bWidthIsAbsolute)
6872169cc62SArmin Le Grand                         {
6882169cc62SArmin Le Grand                             // get width of enclosing svg and resolve percentage in x and width
6892169cc62SArmin Le Grand                             double fWReference(0.0);
6902169cc62SArmin Le Grand                             bool bHasFoundWidth(false);
6912169cc62SArmin Le Grand                             seekReferenceWidth(fWReference, bHasFoundWidth);
6922169cc62SArmin Le Grand                             // referenced values are already in 'user unit'
6932169cc62SArmin Le Grand                             if (!bXIsAbsolute && bHasFoundWidth)
6942169cc62SArmin Le Grand                             {
6952169cc62SArmin Le Grand                                 fX = getX().getNumber() * 0.01 * fWReference;
6962169cc62SArmin Le Grand                                 bXIsAbsolute = true;
6972169cc62SArmin Le Grand                             }
6982169cc62SArmin Le Grand                             if (!bWidthIsAbsolute && bHasFoundWidth)
6992169cc62SArmin Le Grand                             {
7002169cc62SArmin Le Grand                                 fW = (getWidth().isSet() ? getWidth().getNumber() *0.01 : 1.0) * fWReference;
7012169cc62SArmin Le Grand                                 bWidthIsAbsolute = true;
7022169cc62SArmin Le Grand                             }
7032169cc62SArmin Le Grand                         }
7042169cc62SArmin Le Grand                         if (!bYIsAbsolute || !bHeightIsAbsolute)
7052169cc62SArmin Le Grand                         {
7062169cc62SArmin Le Grand                             // get height of enclosing svg and resolve percentage in y and height
7072169cc62SArmin Le Grand                             double fHReference(0.0);
7082169cc62SArmin Le Grand                             bool bHasFoundHeight(false);
7092169cc62SArmin Le Grand                             seekReferenceHeight(fHReference, bHasFoundHeight);
7102169cc62SArmin Le Grand                             // referenced values are already in 'user unit'
7112169cc62SArmin Le Grand                             if (!bYIsAbsolute && bHasFoundHeight)
7122169cc62SArmin Le Grand                             {
7132169cc62SArmin Le Grand                                 fY = getY().getNumber() * 0.01 * fHReference;
7142169cc62SArmin Le Grand                                 bYIsAbsolute = true;
7152169cc62SArmin Le Grand                             }
7162169cc62SArmin Le Grand                             if (!bHeightIsAbsolute && bHasFoundHeight)
7172169cc62SArmin Le Grand                             {
7182169cc62SArmin Le Grand                                 fH = (getHeight().isSet() ? getHeight().getNumber() *0.01 : 1.0) * fHReference;
7192169cc62SArmin Le Grand                                 bHeightIsAbsolute = true;
7202169cc62SArmin Le Grand                             }
7212169cc62SArmin Le Grand                         }
7222169cc62SArmin Le Grand 
7232169cc62SArmin Le Grand                         if (bXIsAbsolute && bYIsAbsolute && bWidthIsAbsolute && bHeightIsAbsolute)
7242169cc62SArmin Le Grand                         {
725e92bb418SOliver-Rainer Wittmann                             return basegfx::B2DRange(fX, fY, fX+fW, fY+fH);
7262169cc62SArmin Le Grand                         }
7272169cc62SArmin Le Grand                         else // relative values could not be resolved, there exists no fallback
7282169cc62SArmin Le Grand                         {
7292169cc62SArmin Le Grand                             return SvgNode::getCurrentViewPort();
7302169cc62SArmin Le Grand                         }
7312169cc62SArmin Le Grand                     }
7322169cc62SArmin Le Grand                 }
7332169cc62SArmin Le Grand                 else //outermost svg
7342169cc62SArmin Le Grand                 {
7352169cc62SArmin Le Grand                     // If width or height is not provided, the default would be 100%, see SVG 1.1 section 5.1.2
7362169cc62SArmin Le Grand                     // But here it cannot be resolved and no fallback exists.
7372169cc62SArmin Le Grand                     // SVG 1.1 defines in section 5.1.2 that x,y has no meanig for the outermost SVG element.
7382169cc62SArmin Le Grand                     bool bWidthIsAbsolute(getWidth().isSet() && Unit_percent != getWidth().getUnit());
7392169cc62SArmin Le Grand                     double fW( bWidthIsAbsolute ? getWidth().solveNonPercentage(*this) : 0.0);
7402169cc62SArmin Le Grand                     bool bHeightIsAbsolute(getHeight().isSet() && Unit_percent != getHeight().getUnit());
7412169cc62SArmin Le Grand                     double fH( bHeightIsAbsolute ? getHeight().solveNonPercentage(*this) : 0.0);
7422169cc62SArmin Le Grand                     if (bWidthIsAbsolute && bHeightIsAbsolute)
7432169cc62SArmin Le Grand                     {
744e92bb418SOliver-Rainer Wittmann                         return basegfx::B2DRange(0.0, 0.0, fW, fH);
7452169cc62SArmin Le Grand                     }
7462169cc62SArmin Le Grand                     else // no fallback exists
7472169cc62SArmin Le Grand                     {
7482169cc62SArmin Le Grand                             return SvgNode::getCurrentViewPort();
7492169cc62SArmin Le Grand                     }
7502169cc62SArmin Le Grand                 }
7512169cc62SArmin Le Grand // ToDo: Is it possible to decompose and use the bounding box of the childs, if even the
7522169cc62SArmin Le Grand //       outermost svg has no information to resolve percentage? Is it worth, how expensive is it?
7532169cc62SArmin Le Grand 
754ddde725dSArmin Le Grand             }
755ddde725dSArmin Le Grand         }
756ddde725dSArmin Le Grand 
757ddde725dSArmin Le Grand     } // end of namespace svgreader
758ddde725dSArmin Le Grand } // end of namespace svgio
759ddde725dSArmin Le Grand 
760ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
761ddde725dSArmin Le Grand // eof
762